fix: upload part tmp+rename (B4), transactional last-admin DeleteUser (B5), RowsAffected order (B13)
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user