Feature user and admin panels (#30)

This commit is contained in:
2026-02-16 20:30:36 +00:00
parent c5866ae785
commit 2fc4f6980c
15 changed files with 1805 additions and 111 deletions

View File

@@ -86,6 +86,19 @@ func (h *AuthHandler) Register(c *gin.Context) {
req.Email = strings.ToLower(strings.TrimSpace(req.Email))
req.Username = strings.TrimSpace(req.Username)
// Check if this is the first user (will become admin)
var userCount int
_ = database.DB.QueryRow(`SELECT COUNT(*) FROM users`).Scan(&userCount)
isFirstUser := userCount == 0
// If not first user, check if registration is enabled
if !isFirstUser {
if !IsRegistrationEnabled() {
c.JSON(http.StatusForbidden, gin.H{"error": "registration is disabled"})
return
}
}
// Hash password
hash, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcryptCost)
if err != nil {
@@ -93,13 +106,19 @@ func (h *AuthHandler) Register(c *gin.Context) {
return
}
// First user gets admin role
role := "user"
if isFirstUser {
role = "admin"
}
// Insert user
var user userResponse
err = database.DB.QueryRow(`
INSERT INTO users (username, email, password_hash, role)
VALUES ($1, $2, $3, 'user')
VALUES ($1, $2, $3, $4)
RETURNING id, username, email, display_name, role
`, req.Username, req.Email, string(hash)).Scan(
`, req.Username, req.Email, string(hash), role).Scan(
&user.ID, &user.Username, &user.Email, &user.DisplayName, &user.Role,
)
if err != nil {
@@ -125,6 +144,23 @@ func (h *AuthHandler) Register(c *gin.Context) {
c.JSON(http.StatusCreated, resp)
}
// IsRegistrationEnabled checks the global_settings table.
// Returns true if the table doesn't exist (pre-migration), DB is nil, or setting is enabled.
func IsRegistrationEnabled() bool {
if database.DB == nil {
return true
}
var enabled bool
err := database.DB.QueryRow(`
SELECT COALESCE((value->>'enabled')::boolean, true)
FROM global_settings WHERE key = 'registration'
`).Scan(&enabled)
if err != nil {
return true // Default to open if setting missing
}
return enabled
}
// ── Login ───────────────────────────────────
func (h *AuthHandler) Login(c *gin.Context) {