middlewares, add admin templates
This commit is contained in:
parent
bcf4c99167
commit
2a74f69f70
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,2 +1,2 @@
|
||||
*.db-shm
|
||||
*.db-wal
|
||||
*.db-*
|
||||
*.fasthttp.br
|
BIN
data/dk.db
BIN
data/dk.db
Binary file not shown.
22
fs/templates/admin/home.html
Normal file
22
fs/templates/admin/home.html
Normal file
@ -0,0 +1,22 @@
|
||||
<p>
|
||||
Welcome to the Dragon Knight Administration section. Use the links on the left
|
||||
bar to control and edit various elements of the game.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Please note that the control panel has been created mostly as a shortcut for certain
|
||||
individual settings. It is meant for use primarily with editing one thing at a time.
|
||||
If you need to completely replace an entire table (say, to replace all stock monsters
|
||||
with your own new ones), it is suggested that you use a more in-depth database tool such
|
||||
as <a href="http://www.phpmyadmin.net" target="_new">phpMyAdmin</a>. Also, you may want to
|
||||
have a copy of the Dragon Knight development kit, available from the
|
||||
<a href="http://dragon.se7enet.com/dev.php">Dragon Knight homepage</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Also, you should be aware that certain portions of the DK code are dependent on the
|
||||
formatting of certain database results (for example, the special attributes on item drops).
|
||||
While I have attempted to point these out throughout the admin script, you should
|
||||
definitely pay attention and be careful when editing some fields, because mistakes in the
|
||||
database content may result in script errors or your game breaking completely.
|
||||
</p>
|
47
fs/templates/admin/layout.html
Normal file
47
fs/templates/admin/layout.html
Normal file
@ -0,0 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{ title }} - DK Admin</title>
|
||||
<link rel="stylesheet" href="/css/admin.css">
|
||||
<script src="/js/htmx.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="admin-container">
|
||||
<header>
|
||||
<h1>Dragon Knight</h1>
|
||||
<h3>Admin</h3>
|
||||
</header>
|
||||
<main>
|
||||
<nav>
|
||||
<a href="/admin" hx-get="/admin" hx-target="#main">Admin Home</a><br>
|
||||
<a href="/">Game Home</a><br><br>
|
||||
|
||||
<br>
|
||||
<a href="/admin/main" hx-get="/admin/main" hx-target="#main">Main Settings</a><br>
|
||||
<a href="/admin/news" hx-get="/admin/news" hx-target="#main">Add News Post</a><br>
|
||||
<a href="/admin/users" hx-get="/admin/users" hx-target="#main">Edit Users</a><br><br>
|
||||
|
||||
<br>
|
||||
<a href="/admin/items" hx-get="/admin/items" hx-target="#main">Edit Items</a><br>
|
||||
<a href="/admin/drops" hx-get="/admin/drops" hx-target="#main">Edit Drops</a><br>
|
||||
<a href="/admin/towns" hx-get="/admin/towns" hx-target="#main">Edit Towns</a><br>
|
||||
<a href="/admin/monsters" hx-get="/admin/monsters" hx-target="#main">Edit Monsters</a><br>
|
||||
<a href="/admin/levels" hx-get="/admin/levels" hx-target="#main">Edit Levels</a><br>
|
||||
<a href="/admin/spells" hx-get="/admin/spells" hx-target="#main">Edit Spells</a><br>
|
||||
</nav>
|
||||
|
||||
<section id="main">
|
||||
{{{ content }}}
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<div>Powered by <a href="/" target="_new">Dragon Knight</a></div>
|
||||
<div>© 2024 Sharkk</div>
|
||||
<div>Version {{ version }} {{ build }}</div>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
129
public/css/admin.css
Normal file
129
public/css/admin.css
Normal file
@ -0,0 +1,129 @@
|
||||
:root {
|
||||
--font-size: 16px;
|
||||
--font-family: Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: var(--font-size);
|
||||
font-family: var(--font-family);
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 2rem;
|
||||
color: rgb(108, 108, 108);
|
||||
background-color: #121212;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5 {
|
||||
color: rgb(30, 30, 30);
|
||||
}
|
||||
|
||||
div#admin-container {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
header {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
main {
|
||||
display: flex;
|
||||
gap: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
main > nav {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
main > section {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
outline-width: none;
|
||||
font-family: var(--font-family);
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
|
||||
& > caption {
|
||||
margin: 1rem;
|
||||
}
|
||||
|
||||
& :is(td,th) {
|
||||
border: 1px solid rgba(0, 0, 0, 0.4);
|
||||
padding: 0.5rem 1rem;
|
||||
}
|
||||
|
||||
& thead tr {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
& tbody tr:nth-of-type(even) {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
&:hover { background: rgba(0, 0, 0, 0.2); }
|
||||
}
|
||||
|
||||
td:hover {
|
||||
color: white;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
tr:hover {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.table-wrapper {
|
||||
width: 100%; /* Ensure the wrapper takes 100% of the parent's width */
|
||||
max-height: 300px; /* Set the desired height limit */
|
||||
overflow-x: auto; /* Enable horizontal scrolling if the table overflows */
|
||||
overflow-y: auto; /* Enable vertical scrolling if needed */
|
||||
display: block; /* Ensure block-level behavior */
|
||||
-webkit-overflow-scrolling: touch; /* Smooth scrolling on touch devices */
|
||||
}
|
||||
|
||||
a {
|
||||
color: #015df7;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: hsl(218, 99%, 29%);
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.small {
|
||||
font: 10px verdana;
|
||||
}
|
||||
.highlight {
|
||||
color: red;
|
||||
}
|
||||
.light {
|
||||
color: #999999;
|
||||
}
|
||||
.title {
|
||||
border: solid 1px black;
|
||||
background-color: #eeeeee;
|
||||
font-weight: bold;
|
||||
padding: 5px;
|
||||
margin: 3px;
|
||||
}
|
||||
|
||||
footer {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
font-size: 0.8rem;
|
||||
padding: 0.5rem;
|
||||
margin: 2rem 0;
|
||||
}
|
6
routes/(guest)/login/get.lua
Normal file
6
routes/(guest)/login/get.lua
Normal file
@ -0,0 +1,6 @@
|
||||
local base_template = fs_read("templates/base.html")
|
||||
local login_form = fs_read("templates/auth/login.html")
|
||||
return send_html(render(base_template, {
|
||||
title = "Login",
|
||||
content = login_form
|
||||
}))
|
30
routes/(guest)/login/post.lua
Normal file
30
routes/(guest)/login/post.lua
Normal file
@ -0,0 +1,30 @@
|
||||
local db = sqlite("dk")
|
||||
|
||||
local username = string.trim(ctx.form.username)
|
||||
if username == "" or not db:exists("users", "username = :u COLLATE NOCASE", {u = username}) then
|
||||
return "username required and must exist"
|
||||
end
|
||||
|
||||
if ctx.form.password == "" then
|
||||
return "password required"
|
||||
end
|
||||
|
||||
local user_row = db:get_one("SELECT id, username, password FROM users WHERE username = :u COLLATE NOCASE", {u = username})
|
||||
if not password_verify(ctx.form.password, user_row.password) then
|
||||
return "wrong username or password"
|
||||
end
|
||||
|
||||
local token = generate_token()
|
||||
local expires = os.time() + (30 * 24 * 60 * 60) -- 30 days
|
||||
db:insert("user_sessions", {
|
||||
user_id = user_row.id,
|
||||
token = token,
|
||||
expires = expires
|
||||
})
|
||||
|
||||
cookie_set("dkauth", token, { expires = expires })
|
||||
|
||||
session_set("logged_in", true)
|
||||
session_set("user_id", user_row.id)
|
||||
|
||||
return "Logged in!"
|
3
routes/(guest)/middleware.lua
Normal file
3
routes/(guest)/middleware.lua
Normal file
@ -0,0 +1,3 @@
|
||||
if session_get("logged_in") then
|
||||
http_redirect("/")
|
||||
end
|
11
routes/(guest)/register/get.lua
Normal file
11
routes/(guest)/register/get.lua
Normal file
@ -0,0 +1,11 @@
|
||||
session_set("test", {
|
||||
foo = "bar",
|
||||
hen = "tai"
|
||||
})
|
||||
|
||||
local base_template = fs_read("templates/base.html")
|
||||
local register_form = fs_read("templates/auth/register.html")
|
||||
return send_html(render(base_template, {
|
||||
title = "Register",
|
||||
content = register_form
|
||||
}))
|
@ -1,12 +1,12 @@
|
||||
local db = sqlite("dk")
|
||||
|
||||
local username = string.trim(ctx.form.username)
|
||||
if username == "" or db:exists("users", "username = :u", {u = username}) then
|
||||
if username == "" or db:exists("users", "username = :u COLLATE NOCASE", {u = username}) then
|
||||
return "username required and must be unique"
|
||||
end
|
||||
|
||||
local email = string.trim(ctx.form.email)
|
||||
if util.sanitize_email(email) == "" or db:exists("users", "email = :e", {e = email}) then
|
||||
if sanitize_email(email) == "" or db:exists("users", "email = :e COLLATE NOCASE", {e = email}) then
|
||||
return "email required, must be valid format, and must be unique"
|
||||
end
|
||||
|
||||
@ -17,7 +17,7 @@ end
|
||||
db:insert("users", {
|
||||
username = username,
|
||||
email = email,
|
||||
password = password.hash(ctx.form.password),
|
||||
password = password_hash(ctx.form.password),
|
||||
attributes_id = 0
|
||||
})
|
||||
|
9
routes/admin/get.lua
Normal file
9
routes/admin/get.lua
Normal file
@ -0,0 +1,9 @@
|
||||
return send_html(render(
|
||||
fs_read("templates/admin/layout.html"),
|
||||
{
|
||||
title = "Home",
|
||||
content = fs_read("templates/admin/home.html"),
|
||||
version = "v1.0.0",
|
||||
build = "Moonlight"
|
||||
}
|
||||
))
|
8
routes/admin/middleware.lua
Normal file
8
routes/admin/middleware.lua
Normal file
@ -0,0 +1,8 @@
|
||||
if not session_get("logged_in") then
|
||||
http_redirect("/")
|
||||
end
|
||||
|
||||
local d = sqlite("dk"):get_one("SELECT auth_level FROM users WHERE id = :i", {i = session_get("user_id")})
|
||||
if d.auth_level < 2 then
|
||||
http_redirect("/")
|
||||
end
|
@ -1,5 +1,5 @@
|
||||
if session.get("logged_in") then
|
||||
return "Hello, "..session.get("user_id").."!"
|
||||
if session_get("logged_in") then
|
||||
return "Welcome, "..session_get("user_id")
|
||||
else
|
||||
return "Hello, guest!"
|
||||
return "Welcome, guest!"
|
||||
end
|
||||
|
@ -1,6 +0,0 @@
|
||||
local base_template = fs.read("templates/base.html")
|
||||
local login_form = fs.read("templates/auth/login.html")
|
||||
return send.html(render(base_template, {
|
||||
title = "Login",
|
||||
content = login_form
|
||||
}))
|
@ -1,31 +0,0 @@
|
||||
local db = sqlite("dk")
|
||||
|
||||
local username = string.trim(ctx.form.username)
|
||||
if username == "" or not db:exists("users", "username = :u", {u = username}) then
|
||||
return "username required and must exist"
|
||||
end
|
||||
|
||||
if ctx.form.password == "" then
|
||||
return "password required"
|
||||
end
|
||||
|
||||
local user_row = db:get_one("SELECT id, username, password, auth_level FROM users WHERE username = :u", {u = username})
|
||||
if not password.verify(ctx.form.password, user_row.password) then
|
||||
return "wrong username or password"
|
||||
end
|
||||
|
||||
local token = util.generate_token()
|
||||
local expires = os.time() + (30 * 24 * 60 * 60) -- 30 days
|
||||
db:insert("user_sessions", {
|
||||
user_id = user_row.id,
|
||||
token = token,
|
||||
expires = expires
|
||||
})
|
||||
|
||||
cookie.set("dkauth", token, { expires = expires })
|
||||
|
||||
session.set("logged_in", true)
|
||||
session.set("user_id", user_row.id)
|
||||
session.set("auth_level", user_row.auth_level)
|
||||
|
||||
return "Logged in!"
|
20
routes/middleware.lua
Normal file
20
routes/middleware.lua
Normal file
@ -0,0 +1,20 @@
|
||||
if not session_get("logged_in") then
|
||||
local cookie = cookie_get("dkauth")
|
||||
|
||||
if cookie then
|
||||
local db = sqlite("dk")
|
||||
local d = db:get_one("SELECT * FROM user_sessions WHERE token = :t", {t = cookie})
|
||||
|
||||
if d then
|
||||
if d.expires < os.time() then
|
||||
db:exec("DELETE FROM user_sessions WHERE token = :t", {t = cookie})
|
||||
session_set("logged_in", false)
|
||||
else
|
||||
session_set("logged_in", true)
|
||||
session_set("user_id", d.user_id)
|
||||
end
|
||||
else
|
||||
session_set("logged_in", false)
|
||||
end
|
||||
end
|
||||
end
|
@ -1,6 +0,0 @@
|
||||
local base_template = fs.read("templates/base.html")
|
||||
local register_form = fs.read("templates/auth/register.html")
|
||||
return send.html(render(base_template, {
|
||||
title = "Register",
|
||||
content = register_form
|
||||
}))
|
Loading…
x
Reference in New Issue
Block a user