start user editing

This commit is contained in:
Sky Johnson 2025-08-27 17:48:23 -05:00
parent c7c76b413c
commit 245dd909d4
4 changed files with 237 additions and 0 deletions

Binary file not shown.

View File

@ -2,14 +2,19 @@ package routes
import ( import (
"dk/internal/components" "dk/internal/components"
"dk/internal/database"
"dk/internal/helpers"
"dk/internal/models/news" "dk/internal/models/news"
"dk/internal/models/users" "dk/internal/models/users"
"fmt"
"runtime" "runtime"
"strconv"
"strings" "strings"
"time" "time"
sushi "git.sharkk.net/Sharkk/Sushi" sushi "git.sharkk.net/Sharkk/Sushi"
"git.sharkk.net/Sharkk/Sushi/auth" "git.sharkk.net/Sharkk/Sushi/auth"
"git.sharkk.net/Sharkk/Sushi/password"
) )
func RegisterAdminRoutes(app *sushi.App) { func RegisterAdminRoutes(app *sushi.App) {
@ -26,6 +31,9 @@ func RegisterAdminRoutes(app *sushi.App) {
group.Get("/", adminIndex) group.Get("/", adminIndex)
group.Get("/news", adminNewsForm) group.Get("/news", adminNewsForm)
group.Post("/news", adminNewsCreate) group.Post("/news", adminNewsCreate)
group.Get("/users", adminUsersIndex)
group.Get("/users/:id", adminUserEdit)
group.Post("/users/:id", adminUserUpdate)
} }
func adminIndex(ctx sushi.Ctx) { func adminIndex(ctx sushi.Ctx) {
@ -78,6 +86,131 @@ func adminNewsCreate(ctx sushi.Ctx) {
ctx.Redirect("/admin") ctx.Redirect("/admin")
} }
func adminUsersIndex(ctx sushi.Ctx) {
pagination := helpers.Pagination{
Page: max(int(ctx.QueryArgs().GetUintOrZero("page")), 1),
PerPage: 30,
}
type UserData struct {
ID int
Username string
Email string
Level int
Auth int
ClassID int
ClassName string
HP int
MaxHP int
Registered int64
LastOnline int64
}
var userList []*UserData
err := database.Select(&userList, `
SELECT u.id, u.username, u.email, u.level, u.auth, u.class_id,
COALESCE(c.name, 'Unknown') as class_name,
u.hp, u.max_hp, u.registered, u.last_online
FROM users u
LEFT JOIN classes c ON u.class_id = c.id
ORDER BY u.id ASC
LIMIT %d OFFSET %d`, pagination.PerPage, pagination.Offset())
if err != nil {
fmt.Printf("Error getting user list for admin index: %s", err.Error())
userList = make([]*UserData, 0)
}
type CountResult struct{ Count int }
var result CountResult
database.Get(&result, "SELECT COUNT(*) as count FROM users")
pagination.Total = result.Count
components.RenderAdminPage(ctx, "User Management", "admin/users/index.html", map[string]any{
"users": userList,
"currentPage": pagination.Page,
"totalPages": pagination.TotalPages(),
"hasNext": pagination.HasNext(),
"hasPrev": pagination.HasPrev(),
})
}
func adminUserEdit(ctx sushi.Ctx) {
sess := ctx.GetCurrentSession()
id := ctx.Param("id").Int()
user, err := users.Find(id)
if err != nil {
sess.SetFlash("error", fmt.Sprintf("User %d not found", id))
ctx.Redirect("/admin/users")
return
}
components.RenderAdminPage(ctx, fmt.Sprintf("Edit User: %s", user.Username), "admin/users/edit.html", map[string]any{
"user": user,
})
}
func adminUserUpdate(ctx sushi.Ctx) {
sess := ctx.GetCurrentSession()
id := ctx.Param("id").Int()
user, err := users.Find(id)
if err != nil {
sess.SetFlash("error", fmt.Sprintf("User %d not found", id))
ctx.Redirect("/admin/users")
return
}
// Update fields
username := strings.TrimSpace(ctx.Form("username").String())
email := strings.TrimSpace(ctx.Form("email").String())
level, _ := strconv.Atoi(ctx.Form("level").String())
auth, _ := strconv.Atoi(ctx.Form("auth").String())
hp, _ := strconv.Atoi(ctx.Form("hp").String())
maxHP, _ := strconv.Atoi(ctx.Form("max_hp").String())
newPassword := strings.TrimSpace(ctx.Form("new_password").String())
if username == "" || email == "" {
sess.SetFlash("error", "Username and email are required")
ctx.Redirect(fmt.Sprintf("/admin/users/%d", id))
return
}
user.Username = username
user.Email = email
user.Level = level
user.Auth = auth
user.HP = hp
user.MaxHP = maxHP
if newPassword != "" {
user.Password = password.HashPassword(newPassword)
}
fields := map[string]any{
"username": user.Username,
"email": user.Email,
"level": user.Level,
"auth": user.Auth,
"hp": user.HP,
"max_hp": user.MaxHP,
}
if newPassword != "" {
fields["password"] = user.Password
}
if err := database.Update("users", fields, "id", id); err != nil {
sess.SetFlash("error", "Failed to update user")
ctx.Redirect(fmt.Sprintf("/admin/users/%d", id))
return
}
sess.SetFlash("success", fmt.Sprintf("User %s updated successfully", user.Username))
ctx.Redirect("/admin/users")
}
func bToMb(b uint64) uint64 { func bToMb(b uint64) uint64 {
return b / 1024 / 1024 return b / 1024 / 1024
} }

View File

@ -0,0 +1,46 @@
{include "admin/layout.html"}
{block "content"}
<h1>Edit User: {user.Username}</h1>
<form class="standard" method="post">
{csrf}
<div>
<label for="username">Username:</label>
<input type="text" name="username" id="username" value="{user.Username}" required>
</div>
<div>
<label for="email">Email:</label>
<input type="email" name="email" id="email" value="{user.Email}" required>
</div>
<div>
<label for="level">Level:</label>
<input type="number" name="level" id="level" value="{user.Level}" min="1">
</div>
<div>
<label for="auth">Auth Level:</label>
<select name="auth" id="auth">
<option value="1"{if user.Auth == 1} selected{/if}>User</option>
<option value="2"{if user.Auth == 2} selected{/if}>Moderator</option>
<option value="3"{if user.Auth == 3} selected{/if}>Admin</option>
<option value="4"{if user.Auth == 4} selected{/if}>Super Admin</option>
</select>
</div>
<div>
<label for="hp">Current HP:</label>
<input type="number" name="hp" id="hp" value="{user.HP}" min="0">
</div>
<div>
<label for="max_hp">Max HP:</label>
<input type="number" name="max_hp" id="max_hp" value="{user.MaxHP}" min="1">
</div>
<div>
<label for="new_password">New Password (leave blank to keep current):</label>
<input type="password" name="new_password" id="new_password" placeholder="Enter new password">
</div>
<div>
<a href="/admin/users"><button type="button" class="btn">Cancel</button></a>
<button type="submit" class="btn btn-primary">Update User</button>
</div>
</form>
{/block}

View File

@ -0,0 +1,58 @@
{include "admin/layout.html"}
{block "content"}
<h1>User Management</h1>
<p>
Total users: {#users} | Page {currentPage} of {totalPages}
</p>
{if #users > 0}
<table>
<thead>
<tr>
<th>ID</th>
<th>Username</th>
<th>Email</th>
<th>Level</th>
<th>Class</th>
<th>Auth</th>
<th>HP</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{for user in users}
<tr>
<td>{user.ID}</td>
<td>{user.Username}</td>
<td>{user.Email}</td>
<td>{user.Level}</td>
<td>{user.ClassName}</td>
<td>{user.Auth}</td>
<td>{user.HP}/{user.MaxHP}</td>
<td>
<a href="/admin/users/{user.ID}">Edit</a>
</td>
</tr>
{/for}
</tbody>
</table>
{if totalPages > 1}
<div class="pagination">
{if hasPrev}
<a href="/admin/users?page={currentPage - 1}">← Previous</a>
{/if}
{if hasNext}
<a href="/admin/users?page={currentPage + 1}">Next →</a>
{/if}
</div>
{/if}
{else}
<div>
No users found.
</div>
{/if}
{/block}