fix: upload part tmp+rename (B4), transactional last-admin DeleteUser (B5), RowsAffected order (B13)

This commit is contained in:
2026-09-14 19:42:11 +08:00
parent 8fbc58eaaa
commit b82a891c50
4 changed files with 108 additions and 27 deletions
+6 -15
View File
@@ -8,15 +8,13 @@ import (
"github.com/gin-gonic/gin"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn"
"booklib/internal/auth"
"booklib/internal/store"
)
func isUnique(e error) bool {
var pgErr *pgconn.PgError
return errors.As(e, &pgErr) && pgErr.Code == "23505"
}
// isUnique is a convenience alias for store.IsUniqueViolation.
func isUnique(e error) bool { return store.IsUniqueViolation(e) }
func (h *H) ListUsers(c *gin.Context) {
users, e := h.st.ListUsers(c)
@@ -73,23 +71,16 @@ func (h *H) DeleteUser(c *gin.Context) {
err(c, http.StatusBadRequest, "bad_request", "cannot delete yourself")
return
}
target, e := h.st.GetUserByID(c, id)
if e != nil {
// B5: transactional last-admin check eliminates TOCTOU race.
if e := h.st.DeleteUser(c, id); e != nil {
if errors.Is(e, pgx.ErrNoRows) {
err(c, http.StatusNotFound, "not_found", "no such user")
return
}
dbErr(c, e)
return
}
if target.Role == "admin" {
n, _ := h.st.CountAdmins(c) // 防删光最后一个 admin
if n <= 1 {
if errors.Is(e, store.ErrLastAdmin) {
err(c, http.StatusBadRequest, "bad_request", "cannot delete the last admin")
return
}
}
if e := h.st.DeleteUser(c, id); e != nil {
dbErr(c, e)
return
}