fix(users): allow superadmin to list all users without tenant restriction
- Modified ListUsers handler to check for admin/superadmin role - Superadmins can now list all users across tenants - Added ListUsers method to AdminService - Added Status field to dto.User Fixes 403 error when superadmin tries to access /api/v1/users
This commit is contained in:
parent
546e253a5f
commit
73967ca52b
3 changed files with 85 additions and 3 deletions
|
|
@ -279,15 +279,58 @@ func (h *CoreHandlers) CreateUser(w http.ResponseWriter, r *http.Request) {
|
|||
// @Router /api/v1/users [get]
|
||||
func (h *CoreHandlers) ListUsers(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
// Check if user is admin/superadmin (they can list all users)
|
||||
roles := middleware.ExtractRoles(ctx.Value(middleware.ContextRoles))
|
||||
isAdmin := false
|
||||
for _, role := range roles {
|
||||
if role == "ADMIN" || role == "SUPERADMIN" || role == "admin" || role == "superadmin" {
|
||||
isAdmin = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
page, _ := strconv.Atoi(r.URL.Query().Get("page"))
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||
if limit < 1 {
|
||||
limit = 10
|
||||
}
|
||||
if limit > 100 {
|
||||
limit = 100
|
||||
}
|
||||
|
||||
if isAdmin {
|
||||
// Admin view: List all users using AdminService
|
||||
users, total, err := h.adminService.ListUsers(ctx, page, limit)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
response := map[string]interface{}{
|
||||
"data": users,
|
||||
"pagination": map[string]interface{}{
|
||||
"page": page,
|
||||
"limit": limit,
|
||||
"total": total,
|
||||
},
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(response)
|
||||
return
|
||||
}
|
||||
|
||||
// Non-admin: require tenant ID
|
||||
tenantID, ok := ctx.Value(middleware.ContextTenantID).(string)
|
||||
if !ok || tenantID == "" {
|
||||
http.Error(w, "Tenant ID not found in context", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
page, _ := strconv.Atoi(r.URL.Query().Get("page"))
|
||||
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||
|
||||
users, err := h.listUsersUC.Execute(ctx, tenantID, page, limit)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ type User struct {
|
|||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
Role string `json:"role"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
CompanyID *string `json:"companyId,omitempty"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,44 @@ func (s *AdminService) ListCompanies(ctx context.Context, verified *bool, page,
|
|||
return companies, total, nil
|
||||
}
|
||||
|
||||
// ListUsers returns all users with pagination (for admin view)
|
||||
func (s *AdminService) ListUsers(ctx context.Context, page, limit int) ([]dto.User, int, error) {
|
||||
offset := (page - 1) * limit
|
||||
|
||||
// Count Total
|
||||
var total int
|
||||
if err := s.DB.QueryRowContext(ctx, `SELECT COUNT(*) FROM users`).Scan(&total); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// Fetch Data
|
||||
query := `
|
||||
SELECT id, COALESCE(name, full_name, identifier, ''), email, role, COALESCE(status, 'active'), created_at
|
||||
FROM users
|
||||
ORDER BY created_at DESC
|
||||
LIMIT $1 OFFSET $2
|
||||
`
|
||||
|
||||
rows, err := s.DB.QueryContext(ctx, query, limit, offset)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
users := []dto.User{}
|
||||
for rows.Next() {
|
||||
var u dto.User
|
||||
var roleStr string
|
||||
if err := rows.Scan(&u.ID, &u.Name, &u.Email, &roleStr, &u.Status, &u.CreatedAt); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
u.Role = roleStr
|
||||
users = append(users, u)
|
||||
}
|
||||
|
||||
return users, total, nil
|
||||
}
|
||||
|
||||
func (s *AdminService) UpdateCompanyStatus(ctx context.Context, id string, active *bool, verified *bool) (*models.Company, error) {
|
||||
company, err := s.getCompanyByID(ctx, id)
|
||||
if err != nil {
|
||||
|
|
|
|||
Loading…
Reference in a new issue