admin page updates

This commit is contained in:
2026-02-13 20:51:39 +11:00
parent ea8b74c5e3
commit 136adabb92
34 changed files with 1737 additions and 164 deletions

View File

@@ -75,7 +75,7 @@ func setupHTTPServer(
return nil, errors.Wrap(err, "addRoutes")
}
err = addMiddleware(httpServer, auth, cfg, perms, discordAPI, store)
err = addMiddleware(httpServer, auth, cfg, perms, discordAPI, store, bun)
if err != nil {
return nil, errors.Wrap(err, "addMiddleware")
}

View File

@@ -27,9 +27,11 @@ func addMiddleware(
perms *rbac.Checker,
discordAPI *discord.APIClient,
store *store.Store,
conn *bun.DB,
) error {
err := server.AddMiddleware(
auth.Authenticate(tokenRefresh(auth, discordAPI, store)),
rbac.LoadPreviewRoleMiddleware(server, conn),
perms.LoadPermissionsMiddleware(),
devMode(cfg),
)

View File

@@ -229,26 +229,22 @@ func migrateStatus(ctx context.Context, migrator *migrate.Migrator) error {
fmt.Println("║ DATABASE MIGRATION STATUS ║")
fmt.Println("╚══════════════════════════════════════════════════════════╝")
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
_, _ = fmt.Fprintln(w, "STATUS\tMIGRATION\tGROUP\tMIGRATED AT")
_, _ = fmt.Fprintln(w, "------\t---------\t-----\t-----------")
w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
_, _ = fmt.Fprintln(w, "STATUS\tMIGRATION\tGROUP\tCOMMENT")
_, _ = fmt.Fprintln(w, "----------\t---------------\t-----\t---------------------------")
appliedCount := 0
for _, m := range ms {
status := "⏳ Pending"
migratedAt := "-"
group := "-"
if m.GroupID > 0 {
status = "✅ Applied"
appliedCount++
group = fmt.Sprint(m.GroupID)
if !m.MigratedAt.IsZero() {
migratedAt = m.MigratedAt.Format("2006-01-02 15:04:05")
}
}
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", status, m.Name, group, migratedAt)
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", status, m.Name, group, m.Comment)
}
_ = w.Flush()
@@ -357,12 +353,12 @@ import (
func init() {
Migrations.MustRegister(
// UP migration
func(ctx context.Context, dbConn *bun.DB) error {
func(ctx context.Context, conn *bun.DB) error {
// Add your migration code here
return nil
},
// DOWN migration
func(ctx context.Context, dbConn *bun.DB) error {
func(ctx context.Context, conn *bun.DB) error {
// Add your rollback code here
return nil
},
@@ -378,7 +374,7 @@ func init() {
fmt.Printf("✅ Created migration: %s\n", filename)
fmt.Println("📝 Next steps:")
fmt.Println(" 1. Edit the file and implement the UP and DOWN functions")
fmt.Println(" 2. Run: make migrate")
fmt.Println(" 2. Run: just migrate up")
return nil
}

View File

@@ -0,0 +1,44 @@
package migrations
import (
"context"
"time"
"git.haelnorr.com/h/oslstats/internal/db"
"github.com/pkg/errors"
"github.com/uptrace/bun"
)
func init() {
Migrations.MustRegister(
// UP migration
func(ctx context.Context, conn *bun.DB) error {
// Add your migration code here
now := time.Now().Unix()
permissionsData := []*db.Permission{
{Name: "seasons.add_league", DisplayName: "Add Leagues to Season", Description: "Assign an existing league to Seasons", Resource: "seasons", Action: "add_league", IsSystem: true, CreatedAt: now},
{Name: "seasons.remove_league", DisplayName: "Remove Leagues from a Season", Description: "Remove an assigned league league from Seasons", Resource: "seasons", Action: "remove_league", IsSystem: true, CreatedAt: now},
{Name: "leagues.create", DisplayName: "Create Leagues", Description: "Create new leagues", Resource: "leagues", Action: "create", IsSystem: true, CreatedAt: now},
{Name: "leagues.update", DisplayName: "Update Leagues", Description: "Update existing leagues", Resource: "leagues", Action: "update", IsSystem: true, CreatedAt: now},
{Name: "leagues.delete", DisplayName: "Delete Leagues", Description: "Delete leagues", Resource: "leagues", Action: "delete", IsSystem: true, CreatedAt: now},
{Name: "teams.create", DisplayName: "Create Teams", Description: "Create new teams", Resource: "teams", Action: "create", IsSystem: true, CreatedAt: now},
{Name: "teams.update", DisplayName: "Update Teams", Description: "Update existing teams", Resource: "teams", Action: "update", IsSystem: true, CreatedAt: now},
{Name: "teams.delete", DisplayName: "Delete Teams", Description: "Delete teams", Resource: "teams", Action: "delete", IsSystem: true, CreatedAt: now},
{Name: "teams.add_to_league", DisplayName: "Add Teams to League", Description: "Add an existing team to a league/season", Resource: "teams", Action: "add_to_league", IsSystem: true, CreatedAt: now},
}
_, err := conn.NewInsert().
Model(&permissionsData).
Exec(ctx)
if err != nil {
return errors.Wrap(err, "dbConn.NewInsert")
}
return nil
},
// DOWN migration
func(ctx context.Context, dbConn *bun.DB) error {
// Add your rollback code here
return nil
},
)
}

View File

@@ -214,13 +214,13 @@ func addRoutes(
},
{
Path: "/admin/users",
Method: hws.MethodGET,
Methods: []hws.Method{hws.MethodGET, hws.MethodPOST},
Handler: perms.RequireAdmin(s)(handlers.AdminUsersPage(s, conn)),
},
{
Path: "/admin/roles",
Method: hws.MethodGET,
Handler: perms.RequireAdmin(s)(handlers.AdminRolesPage(s, conn)),
Methods: []hws.Method{hws.MethodGET, hws.MethodPOST},
Handler: perms.RequireAdmin(s)(handlers.AdminRoles(s, conn)),
},
{
Path: "/admin/permissions",
@@ -232,17 +232,6 @@ func addRoutes(
Method: hws.MethodGET,
Handler: perms.RequireAdmin(s)(handlers.AdminAuditLogsPage(s, conn)),
},
// HTMX content fragment routes (for section swapping)
{
Path: "/admin/users",
Method: hws.MethodPOST,
Handler: perms.RequireAdmin(s)(handlers.AdminUsersList(s, conn)),
},
{
Path: "/admin/roles",
Method: hws.MethodPOST,
Handler: perms.RequireAdmin(s)(handlers.AdminRolesList(s, conn)),
},
{
Path: "/admin/permissions",
Method: hws.MethodPOST,
@@ -253,6 +242,52 @@ func addRoutes(
Method: hws.MethodPOST,
Handler: perms.RequireAdmin(s)(handlers.AdminAuditLogsList(s, conn)),
},
// Role management routes
{
Path: "/admin/roles/create",
Method: hws.MethodGET,
Handler: perms.RequireAdmin(s)(handlers.AdminRoleCreateForm(s)),
},
{
Path: "/admin/roles/create",
Method: hws.MethodPOST,
Handler: perms.RequireAdmin(s)(handlers.AdminRoleCreate(s, conn, audit)),
},
{
Path: "/admin/roles/{id}/manage",
Method: hws.MethodGET,
Handler: perms.RequireAdmin(s)(handlers.AdminRoleManage(s, conn)),
},
{
Path: "/admin/roles/{id}",
Method: hws.MethodDELETE,
Handler: perms.RequireAdmin(s)(handlers.AdminRoleDelete(s, conn, audit)),
},
{
Path: "/admin/roles/{id}/delete-confirm",
Method: hws.MethodGET,
Handler: perms.RequireAdmin(s)(handlers.AdminRoleDeleteConfirm(s, conn)),
},
{
Path: "/admin/roles/{id}/permissions",
Method: hws.MethodGET,
Handler: perms.RequireAdmin(s)(handlers.AdminRolePermissionsModal(s, conn)),
},
{
Path: "/admin/roles/{id}/permissions",
Method: hws.MethodPOST,
Handler: perms.RequireAdmin(s)(handlers.AdminRolePermissionsUpdate(s, conn, audit)),
},
{
Path: "/admin/roles/{id}/preview-start",
Method: hws.MethodPOST,
Handler: perms.RequireAdmin(s)(handlers.AdminPreviewRoleStart(s, conn, cfg)),
},
{
Path: "/admin/roles/preview-stop",
Method: hws.MethodPOST,
Handler: perms.RequireActualAdmin(s)(handlers.AdminPreviewRoleStop(s)),
},
// Audit log filtering (returns only results table, no URL push)
{
Path: "/admin/audit/filter",