package server import ( "net/http" "sort" "strings" "github.com/gin-gonic/gin" "warpbox/lib/metastore" ) type adminUserRow struct { ID string Username string Email string Tags string CreatedAt string Disabled bool IsCurrent bool } func (app *App) handleAdminUsers(ctx *gin.Context) { if !app.requireAdminFlag(ctx, func(perms metastore.EffectivePermissions) bool { return perms.AdminUsersManage }) { return } app.renderAdminUsers(ctx, "") } func (app *App) handleAdminUsersPost(ctx *gin.Context) { if !app.requireAdminFlag(ctx, func(perms metastore.EffectivePermissions) bool { return perms.AdminUsersManage }) { return } if ctx.PostForm("action") == "toggle_disabled" { userID := strings.TrimSpace(ctx.PostForm("user_id")) user, ok, err := app.store.GetUser(userID) if err != nil || !ok { app.renderAdminUsers(ctx, "User not found.") return } if current, ok := ctx.Get("adminUser"); ok { if currentUser, ok := current.(metastore.User); ok && currentUser.ID == user.ID { app.renderAdminUsers(ctx, "You cannot disable the user for the active session.") return } } user.Disabled = !user.Disabled if err := app.store.UpdateUser(user); err != nil { app.renderAdminUsers(ctx, err.Error()) return } ctx.Redirect(http.StatusSeeOther, "/admin/users") return } username := ctx.PostForm("username") email := ctx.PostForm("email") password := ctx.PostForm("password") tagIDs := ctx.PostFormArray("tag_ids") if _, err := app.store.CreateUserWithPassword(username, email, password, tagIDs); err != nil { app.renderAdminUsers(ctx, err.Error()) return } ctx.Redirect(http.StatusSeeOther, "/admin/users") } func (app *App) renderAdminUsers(ctx *gin.Context, errorMessage string) { users, err := app.store.ListUsers() if err != nil { ctx.String(http.StatusInternalServerError, "Could not list users") return } tags, err := app.store.ListTags() if err != nil { ctx.String(http.StatusInternalServerError, "Could not list tags") return } tagNames := make(map[string]string, len(tags)) for _, tag := range tags { tagNames[tag.ID] = tag.Name } sort.Slice(users, func(i int, j int) bool { return strings.ToLower(users[i].Username) < strings.ToLower(users[j].Username) }) currentID := "" if current, ok := ctx.Get("adminUser"); ok { if currentUser, ok := current.(metastore.User); ok { currentID = currentUser.ID } } rows := make([]adminUserRow, 0, len(users)) for _, user := range users { names := make([]string, 0, len(user.TagIDs)) for _, tagID := range user.TagIDs { if name := tagNames[tagID]; name != "" { names = append(names, name) } } rows = append(rows, adminUserRow{ ID: user.ID, Username: user.Username, Email: user.Email, Tags: strings.Join(names, ", "), CreatedAt: formatAdminTime(user.CreatedAt), Disabled: user.Disabled, IsCurrent: user.ID == currentID, }) } ctx.HTML(http.StatusOK, "admin_users.html", gin.H{ "AdminSection": "users", "CurrentUser": app.currentAdminUsername(ctx), "CSRFToken": app.currentCSRFToken(ctx), "Users": rows, "Tags": tags, "Error": errorMessage, }) }