Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
141 lines
3.8 KiB
Go
141 lines
3.8 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/descrybe/descrybe-v2/apps/api/internal/auth"
|
|
"github.com/descrybe/descrybe-v2/apps/api/internal/support"
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// handleAdminListStaff returns platform staff users (admin|developer only).
|
|
// GET /api/admin/staff
|
|
func (s *Server) handleAdminListStaff(w http.ResponseWriter, r *http.Request) {
|
|
if s.Auth == nil {
|
|
Error(w, http.StatusServiceUnavailable, "auth unavailable")
|
|
return
|
|
}
|
|
limit, offset := ParseLimitOffset(r)
|
|
users, err := s.Auth.ListStaffUsers(r.Context(), limit, offset)
|
|
if err != nil {
|
|
Error(w, http.StatusInternalServerError, "list failed")
|
|
return
|
|
}
|
|
JSON(w, http.StatusOK, map[string]any{
|
|
"staff": users,
|
|
"limit": limit,
|
|
"offset": offset,
|
|
})
|
|
}
|
|
|
|
// handleAdminSetStaffRole assigns or clears a platform staff role (admin|developer only).
|
|
// PATCH /api/admin/users/{id}/staff-role
|
|
// Body: {"staff_role":"admin"|"developer"|"support_staff"|null}
|
|
func (s *Server) handleAdminSetStaffRole(w http.ResponseWriter, r *http.Request) {
|
|
if s.Auth == nil {
|
|
Error(w, http.StatusServiceUnavailable, "auth unavailable")
|
|
return
|
|
}
|
|
actorID, ok := UserIDFromContext(r.Context())
|
|
if !ok {
|
|
Error(w, http.StatusUnauthorized, "unauthorized")
|
|
return
|
|
}
|
|
targetID, err := uuid.Parse(chi.URLParam(r, "id"))
|
|
if err != nil {
|
|
Error(w, http.StatusBadRequest, "invalid id")
|
|
return
|
|
}
|
|
if targetID == actorID {
|
|
Error(w, http.StatusForbidden, "cannot change own staff role")
|
|
return
|
|
}
|
|
|
|
var body struct {
|
|
StaffRole *string `json:"staff_role"`
|
|
}
|
|
dec := json.NewDecoder(r.Body)
|
|
dec.DisallowUnknownFields()
|
|
if err := dec.Decode(&body); err != nil {
|
|
Error(w, http.StatusBadRequest, "invalid json")
|
|
return
|
|
}
|
|
role := ""
|
|
if body.StaffRole != nil {
|
|
role = strings.TrimSpace(*body.StaffRole)
|
|
}
|
|
user, err := s.Auth.SetStaffRole(r.Context(), targetID, role)
|
|
if err != nil {
|
|
if errors.Is(err, auth.ErrInvalidStaffRole) {
|
|
Error(w, http.StatusBadRequest, "invalid staff_role")
|
|
return
|
|
}
|
|
if errors.Is(err, auth.ErrStaffUserNotFound) {
|
|
Error(w, http.StatusNotFound, "user not found")
|
|
return
|
|
}
|
|
Error(w, http.StatusInternalServerError, "update failed")
|
|
return
|
|
}
|
|
JSON(w, http.StatusOK, map[string]any{
|
|
"user": user,
|
|
"staff_capabilities": auth.StaffCapabilities(user.ResolvedRole),
|
|
})
|
|
}
|
|
|
|
// handleAdminSetSupportAgent grants or revokes support_staff only (full-admin exclusive).
|
|
// PUT /api/admin/support/agents/{id}
|
|
// Body: {"enabled": true|false} or {"is_support_agent": true|false}
|
|
func (s *Server) handleAdminSetSupportAgent(w http.ResponseWriter, r *http.Request) {
|
|
if s.Support == nil {
|
|
Error(w, http.StatusServiceUnavailable, "support unavailable")
|
|
return
|
|
}
|
|
actorID, ok := UserIDFromContext(r.Context())
|
|
if !ok {
|
|
Error(w, http.StatusUnauthorized, "unauthorized")
|
|
return
|
|
}
|
|
targetID, err := uuid.Parse(chi.URLParam(r, "id"))
|
|
if err != nil {
|
|
Error(w, http.StatusBadRequest, "invalid id")
|
|
return
|
|
}
|
|
if targetID == actorID {
|
|
Error(w, http.StatusForbidden, "cannot change own support agent flag")
|
|
return
|
|
}
|
|
var body struct {
|
|
Enabled *bool `json:"enabled"`
|
|
IsSupportAgent *bool `json:"is_support_agent"`
|
|
}
|
|
if err := DecodeJSON(r, &body); err != nil {
|
|
Error(w, http.StatusBadRequest, "invalid json")
|
|
return
|
|
}
|
|
enable := false
|
|
switch {
|
|
case body.Enabled != nil:
|
|
enable = *body.Enabled
|
|
case body.IsSupportAgent != nil:
|
|
enable = *body.IsSupportAgent
|
|
default:
|
|
Error(w, http.StatusBadRequest, "enabled required")
|
|
return
|
|
}
|
|
agent, err := s.Support.SetSupportAgent(r.Context(), targetID, enable)
|
|
if errors.Is(err, support.ErrNotFound) {
|
|
Error(w, http.StatusNotFound, "user not found")
|
|
return
|
|
}
|
|
if err != nil {
|
|
LogAndError(w, http.StatusInternalServerError, "update failed", err)
|
|
return
|
|
}
|
|
JSON(w, http.StatusOK, map[string]any{"agent": agent})
|
|
}
|