Changeset 0.8.1 (#44)
This commit is contained in:
@@ -17,15 +17,22 @@ import (
|
||||
// ── Types ───────────────────────────────────
|
||||
|
||||
type adminUserResponse struct {
|
||||
ID string `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
DisplayName *string `json:"display_name"`
|
||||
Role string `json:"role"`
|
||||
IsActive bool `json:"is_active"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
LastLoginAt *string `json:"last_login_at"`
|
||||
ID string `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
DisplayName *string `json:"display_name"`
|
||||
Role string `json:"role"`
|
||||
IsActive bool `json:"is_active"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
LastLoginAt *string `json:"last_login_at"`
|
||||
Teams []userTeamMembership `json:"teams,omitempty"`
|
||||
}
|
||||
|
||||
type userTeamMembership struct {
|
||||
TeamID string `json:"team_id"`
|
||||
TeamName string `json:"team_name"`
|
||||
Role string `json:"role"`
|
||||
}
|
||||
|
||||
type adminCreateUserRequest struct {
|
||||
@@ -44,7 +51,9 @@ type updateUserRoleRequest struct {
|
||||
}
|
||||
|
||||
type updateUserActiveRequest struct {
|
||||
IsActive bool `json:"is_active"`
|
||||
IsActive bool `json:"is_active"`
|
||||
TeamIDs []string `json:"team_ids,omitempty"` // assign to teams on activation
|
||||
TeamRole string `json:"team_role,omitempty"` // role for team assignment (default: member)
|
||||
}
|
||||
|
||||
type globalSettingResponse struct {
|
||||
@@ -98,6 +107,38 @@ func (h *AdminHandler) ListUsers(c *gin.Context) {
|
||||
users = append(users, u)
|
||||
}
|
||||
|
||||
// Batch-load team memberships for all users
|
||||
if len(users) > 0 {
|
||||
userIDs := make([]interface{}, len(users))
|
||||
placeholders := make([]string, len(users))
|
||||
userIdx := make(map[string]int) // user_id → index in users slice
|
||||
for i, u := range users {
|
||||
userIDs[i] = u.ID
|
||||
placeholders[i] = "$" + strconv.Itoa(i+1)
|
||||
userIdx[u.ID] = i
|
||||
}
|
||||
tmRows, err := database.DB.Query(`
|
||||
SELECT tm.user_id, t.id, t.name, tm.role
|
||||
FROM team_members tm
|
||||
JOIN teams t ON t.id = tm.team_id
|
||||
WHERE tm.user_id IN (`+strings.Join(placeholders, ",")+`)
|
||||
ORDER BY t.name ASC
|
||||
`, userIDs...)
|
||||
if err == nil {
|
||||
defer tmRows.Close()
|
||||
for tmRows.Next() {
|
||||
var uid, tid, tname, trole string
|
||||
if tmRows.Scan(&uid, &tid, &tname, &trole) == nil {
|
||||
if idx, ok := userIdx[uid]; ok {
|
||||
users[idx].Teams = append(users[idx].Teams, userTeamMembership{
|
||||
TeamID: tid, TeamName: tname, Role: trole,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, paginatedResponse{
|
||||
Data: users,
|
||||
Page: page,
|
||||
@@ -251,7 +292,30 @@ func (h *AdminHandler) ToggleUserActive(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "user updated", "is_active": req.IsActive})
|
||||
// On activation, optionally assign to teams
|
||||
teamsAssigned := 0
|
||||
if req.IsActive && len(req.TeamIDs) > 0 {
|
||||
role := req.TeamRole
|
||||
if role == "" {
|
||||
role = "member"
|
||||
}
|
||||
for _, teamID := range req.TeamIDs {
|
||||
_, err := database.DB.Exec(`
|
||||
INSERT INTO team_members (team_id, user_id, role)
|
||||
VALUES ($1, $2, $3)
|
||||
ON CONFLICT (team_id, user_id) DO NOTHING
|
||||
`, teamID, targetID, role)
|
||||
if err == nil {
|
||||
teamsAssigned++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"message": "user updated",
|
||||
"is_active": req.IsActive,
|
||||
"teams_assigned": teamsAssigned,
|
||||
})
|
||||
}
|
||||
|
||||
// ── Delete User ─────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user