Address PR review: graceful shutdown, Role/NewUser, drop SQLite.

This commit is contained in:
2026-08-21 23:40:59 -07:00
parent d167b9216a
commit 3391cce7bd
13 changed files with 152 additions and 337 deletions
+1 -1
View File
@@ -47,7 +47,7 @@ func (s *Server) handleAdminSetRole(w http.ResponseWriter, r *http.Request) {
return
}
id := chi.URLParam(r, "id")
role := r.PostFormValue("role")
role := store.Role(r.PostFormValue("role"))
err := s.store.SetRole(r.Context(), id, role)
if errors.Is(err, store.ErrLastAdmin) {
users, listErr := s.store.ListUsers(r.Context())
+9 -3
View File
@@ -88,16 +88,22 @@ func (s *Server) handleRegister(w http.ResponseWriter, r *http.Request) {
http.Error(w, "could not save password", http.StatusInternalServerError)
return
}
asAdmin := false
role := store.RoleUser
if s.cfg.AdminUsername != "" && store.NormalizeUsername(username) == store.NormalizeUsername(s.cfg.AdminUsername) {
n, err := s.store.CountAdmins(r.Context())
if err != nil {
http.Error(w, "could not create account", http.StatusInternalServerError)
return
}
asAdmin = n == 0
if n == 0 {
role = store.RoleAdmin
}
}
u, err := s.store.CreateUser(r.Context(), username, string(hash), asAdmin)
u, err := s.store.CreateUser(r.Context(), store.NewUser{
Username: username,
PasswordHash: string(hash),
Role: role,
})
if err != nil {
p.Error = "That username is taken."
s.exec(w, "register", p)
+16 -17
View File
@@ -18,11 +18,11 @@ import (
// memDB is an in-memory store.DB for tests.
type memDB struct {
mu sync.Mutex
users map[string]*store.User // id -> user
byName map[string]string // username -> id
questions map[string]*store.RankedQuestion // id -> question
votes map[string]int // userID|questionID -> value
answers map[string]*store.Answer // questionID -> answer
users map[string]*store.User // id -> user
byName map[string]string // username -> id
questions map[string]*store.RankedQuestion // id -> question
votes map[string]int // userID|questionID -> value
answers map[string]*store.Answer // questionID -> answer
}
func newMemDB() *memDB {
@@ -39,23 +39,22 @@ func voteKey(userID, questionID string) string {
return userID + "|" + questionID
}
func (m *memDB) CreateUser(_ context.Context, username, passwordHash string, asAdmin bool) (*store.User, error) {
func (m *memDB) CreateUser(_ context.Context, nu store.NewUser) (*store.User, error) {
m.mu.Lock()
defer m.mu.Unlock()
username = store.NormalizeUsername(username)
username := store.NormalizeUsername(nu.Username)
if _, ok := m.byName[username]; ok {
return nil, fmt.Errorf("username taken")
}
role := "user"
if asAdmin {
role = "admin"
if nu.Role != store.RoleUser && nu.Role != store.RoleAdmin {
return nil, fmt.Errorf("invalid role")
}
u := &store.User{
ID: uuid.NewString(),
Username: username,
Name: username,
Role: role,
PasswordHash: passwordHash,
Role: nu.Role,
PasswordHash: nu.PasswordHash,
CreatedAt: time.Now().UTC().Format(time.RFC3339),
}
m.users[u.ID] = u
@@ -92,7 +91,7 @@ func (m *memDB) CountAdmins(_ context.Context) (int, error) {
defer m.mu.Unlock()
n := 0
for _, u := range m.users {
if u.Role == "admin" {
if u.Role == store.RoleAdmin {
n++
}
}
@@ -114,8 +113,8 @@ func (m *memDB) ListUsers(_ context.Context) ([]store.User, error) {
return out, nil
}
func (m *memDB) SetRole(_ context.Context, userID, role string) error {
if role != "user" && role != "admin" {
func (m *memDB) SetRole(_ context.Context, userID string, role store.Role) error {
if role != store.RoleUser && role != store.RoleAdmin {
return fmt.Errorf("invalid role")
}
m.mu.Lock()
@@ -124,10 +123,10 @@ func (m *memDB) SetRole(_ context.Context, userID, role string) error {
if !ok {
return sql.ErrNoRows
}
if u.Role == "admin" && role == "user" {
if u.Role == store.RoleAdmin && role == store.RoleUser {
n := 0
for _, x := range m.users {
if x.Role == "admin" {
if x.Role == store.RoleAdmin {
n++
}
}