working on some code
This commit is contained in:
218
backend/internal/iam/group.go
Normal file
218
backend/internal/iam/group.go
Normal file
@@ -0,0 +1,218 @@
|
||||
package iam
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/atlasos/calypso/internal/common/database"
|
||||
)
|
||||
|
||||
// Group represents a user group
|
||||
type Group struct {
|
||||
ID string
|
||||
Name string
|
||||
Description string
|
||||
IsSystem bool
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
UserCount int
|
||||
RoleCount int
|
||||
}
|
||||
|
||||
// GetGroupByID retrieves a group by ID
|
||||
func GetGroupByID(db *database.DB, groupID string) (*Group, error) {
|
||||
query := `
|
||||
SELECT id, name, description, is_system, created_at, updated_at
|
||||
FROM groups
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
var group Group
|
||||
err := db.QueryRow(query, groupID).Scan(
|
||||
&group.ID, &group.Name, &group.Description, &group.IsSystem,
|
||||
&group.CreatedAt, &group.UpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get user count
|
||||
var userCount int
|
||||
db.QueryRow("SELECT COUNT(*) FROM user_groups WHERE group_id = $1", groupID).Scan(&userCount)
|
||||
group.UserCount = userCount
|
||||
|
||||
// Get role count
|
||||
var roleCount int
|
||||
db.QueryRow("SELECT COUNT(*) FROM group_roles WHERE group_id = $1", groupID).Scan(&roleCount)
|
||||
group.RoleCount = roleCount
|
||||
|
||||
return &group, nil
|
||||
}
|
||||
|
||||
// GetGroupByName retrieves a group by name
|
||||
func GetGroupByName(db *database.DB, name string) (*Group, error) {
|
||||
query := `
|
||||
SELECT id, name, description, is_system, created_at, updated_at
|
||||
FROM groups
|
||||
WHERE name = $1
|
||||
`
|
||||
|
||||
var group Group
|
||||
err := db.QueryRow(query, name).Scan(
|
||||
&group.ID, &group.Name, &group.Description, &group.IsSystem,
|
||||
&group.CreatedAt, &group.UpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &group, nil
|
||||
}
|
||||
|
||||
// GetUserGroups retrieves all groups for a user
|
||||
func GetUserGroups(db *database.DB, userID string) ([]string, error) {
|
||||
query := `
|
||||
SELECT g.name
|
||||
FROM groups g
|
||||
INNER JOIN user_groups ug ON g.id = ug.group_id
|
||||
WHERE ug.user_id = $1
|
||||
ORDER BY g.name
|
||||
`
|
||||
|
||||
rows, err := db.Query(query, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var groups []string
|
||||
for rows.Next() {
|
||||
var groupName string
|
||||
if err := rows.Scan(&groupName); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
groups = append(groups, groupName)
|
||||
}
|
||||
|
||||
return groups, rows.Err()
|
||||
}
|
||||
|
||||
// GetGroupUsers retrieves all users in a group
|
||||
func GetGroupUsers(db *database.DB, groupID string) ([]string, error) {
|
||||
query := `
|
||||
SELECT u.id
|
||||
FROM users u
|
||||
INNER JOIN user_groups ug ON u.id = ug.user_id
|
||||
WHERE ug.group_id = $1
|
||||
ORDER BY u.username
|
||||
`
|
||||
|
||||
rows, err := db.Query(query, groupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var userIDs []string
|
||||
for rows.Next() {
|
||||
var userID string
|
||||
if err := rows.Scan(&userID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userIDs = append(userIDs, userID)
|
||||
}
|
||||
|
||||
return userIDs, rows.Err()
|
||||
}
|
||||
|
||||
// GetGroupRoles retrieves all roles for a group
|
||||
func GetGroupRoles(db *database.DB, groupID string) ([]string, error) {
|
||||
query := `
|
||||
SELECT r.name
|
||||
FROM roles r
|
||||
INNER JOIN group_roles gr ON r.id = gr.role_id
|
||||
WHERE gr.group_id = $1
|
||||
ORDER BY r.name
|
||||
`
|
||||
|
||||
rows, err := db.Query(query, groupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var roles []string
|
||||
for rows.Next() {
|
||||
var role string
|
||||
if err := rows.Scan(&role); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
roles = append(roles, role)
|
||||
}
|
||||
|
||||
return roles, rows.Err()
|
||||
}
|
||||
|
||||
// AddUserToGroup adds a user to a group
|
||||
func AddUserToGroup(db *database.DB, userID, groupID, assignedBy string) error {
|
||||
query := `
|
||||
INSERT INTO user_groups (user_id, group_id, assigned_by)
|
||||
VALUES ($1, $2, $3)
|
||||
ON CONFLICT (user_id, group_id) DO NOTHING
|
||||
`
|
||||
_, err := db.Exec(query, userID, groupID, assignedBy)
|
||||
return err
|
||||
}
|
||||
|
||||
// RemoveUserFromGroup removes a user from a group
|
||||
func RemoveUserFromGroup(db *database.DB, userID, groupID string) error {
|
||||
query := `DELETE FROM user_groups WHERE user_id = $1 AND group_id = $2`
|
||||
_, err := db.Exec(query, userID, groupID)
|
||||
return err
|
||||
}
|
||||
|
||||
// AddRoleToGroup adds a role to a group
|
||||
func AddRoleToGroup(db *database.DB, groupID, roleID string) error {
|
||||
query := `
|
||||
INSERT INTO group_roles (group_id, role_id)
|
||||
VALUES ($1, $2)
|
||||
ON CONFLICT (group_id, role_id) DO NOTHING
|
||||
`
|
||||
_, err := db.Exec(query, groupID, roleID)
|
||||
return err
|
||||
}
|
||||
|
||||
// RemoveRoleFromGroup removes a role from a group
|
||||
func RemoveRoleFromGroup(db *database.DB, groupID, roleID string) error {
|
||||
query := `DELETE FROM group_roles WHERE group_id = $1 AND role_id = $2`
|
||||
_, err := db.Exec(query, groupID, roleID)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetUserRolesFromGroups retrieves all roles for a user via groups
|
||||
func GetUserRolesFromGroups(db *database.DB, userID string) ([]string, error) {
|
||||
query := `
|
||||
SELECT DISTINCT r.name
|
||||
FROM roles r
|
||||
INNER JOIN group_roles gr ON r.id = gr.role_id
|
||||
INNER JOIN user_groups ug ON gr.group_id = ug.group_id
|
||||
WHERE ug.user_id = $1
|
||||
ORDER BY r.name
|
||||
`
|
||||
|
||||
rows, err := db.Query(query, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var roles []string
|
||||
for rows.Next() {
|
||||
var role string
|
||||
if err := rows.Scan(&role); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
roles = append(roles, role)
|
||||
}
|
||||
|
||||
return roles, rows.Err()
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package iam
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -64,15 +65,22 @@ func (h *Handler) ListUsers(c *gin.Context) {
|
||||
continue
|
||||
}
|
||||
|
||||
roles, _ := GetUserRoles(h.db, u.ID)
|
||||
permissions, _ := GetUserPermissions(h.db, u.ID)
|
||||
groups, _ := GetUserGroups(h.db, u.ID)
|
||||
|
||||
users = append(users, map[string]interface{}{
|
||||
"id": u.ID,
|
||||
"username": u.Username,
|
||||
"email": u.Email,
|
||||
"full_name": u.FullName,
|
||||
"is_active": u.IsActive,
|
||||
"is_system": u.IsSystem,
|
||||
"created_at": u.CreatedAt,
|
||||
"updated_at": u.UpdatedAt,
|
||||
"id": u.ID,
|
||||
"username": u.Username,
|
||||
"email": u.Email,
|
||||
"full_name": u.FullName,
|
||||
"is_active": u.IsActive,
|
||||
"is_system": u.IsSystem,
|
||||
"roles": roles,
|
||||
"permissions": permissions,
|
||||
"groups": groups,
|
||||
"created_at": u.CreatedAt,
|
||||
"updated_at": u.UpdatedAt,
|
||||
"last_login_at": u.LastLoginAt,
|
||||
})
|
||||
}
|
||||
@@ -81,9 +89,45 @@ func (h *Handler) ListUsers(c *gin.Context) {
|
||||
}
|
||||
|
||||
// GetUser retrieves a single user
|
||||
// Permission: User can view their own profile, or admin can view any profile
|
||||
func (h *Handler) GetUser(c *gin.Context) {
|
||||
userID := c.Param("id")
|
||||
|
||||
// Get current authenticated user from context
|
||||
authUser, exists := c.Get("user")
|
||||
if !exists {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "authentication required"})
|
||||
return
|
||||
}
|
||||
|
||||
currentUser, ok := authUser.(*User)
|
||||
if !ok {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "invalid user context"})
|
||||
return
|
||||
}
|
||||
|
||||
// Check permission: user can view own profile, or admin can view any profile
|
||||
canView := false
|
||||
if currentUser.ID == userID {
|
||||
canView = true
|
||||
} else {
|
||||
// Check if current user is admin
|
||||
roles, err := GetUserRoles(h.db, currentUser.ID)
|
||||
if err == nil {
|
||||
for _, role := range roles {
|
||||
if role == "admin" {
|
||||
canView = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !canView {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "insufficient permissions"})
|
||||
return
|
||||
}
|
||||
|
||||
user, err := GetUserByID(h.db, userID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
|
||||
@@ -92,18 +136,21 @@ func (h *Handler) GetUser(c *gin.Context) {
|
||||
|
||||
roles, _ := GetUserRoles(h.db, userID)
|
||||
permissions, _ := GetUserPermissions(h.db, userID)
|
||||
groups, _ := GetUserGroups(h.db, userID)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"id": user.ID,
|
||||
"username": user.Username,
|
||||
"email": user.Email,
|
||||
"full_name": user.FullName,
|
||||
"is_active": user.IsActive,
|
||||
"is_system": user.IsSystem,
|
||||
"roles": roles,
|
||||
"permissions": permissions,
|
||||
"created_at": user.CreatedAt,
|
||||
"updated_at": user.UpdatedAt,
|
||||
"id": user.ID,
|
||||
"username": user.Username,
|
||||
"email": user.Email,
|
||||
"full_name": user.FullName,
|
||||
"is_active": user.IsActive,
|
||||
"is_system": user.IsSystem,
|
||||
"roles": roles,
|
||||
"permissions": permissions,
|
||||
"groups": groups,
|
||||
"created_at": user.CreatedAt,
|
||||
"updated_at": user.UpdatedAt,
|
||||
"last_login_at": user.LastLoginAt,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -230,3 +277,432 @@ func (h *Handler) DeleteUser(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"message": "user deleted successfully"})
|
||||
}
|
||||
|
||||
// ListGroups lists all groups
|
||||
func (h *Handler) ListGroups(c *gin.Context) {
|
||||
query := `
|
||||
SELECT g.id, g.name, g.description, g.is_system, g.created_at, g.updated_at,
|
||||
COUNT(DISTINCT ug.user_id) as user_count,
|
||||
COUNT(DISTINCT gr.role_id) as role_count
|
||||
FROM groups g
|
||||
LEFT JOIN user_groups ug ON g.id = ug.group_id
|
||||
LEFT JOIN group_roles gr ON g.id = gr.group_id
|
||||
GROUP BY g.id, g.name, g.description, g.is_system, g.created_at, g.updated_at
|
||||
ORDER BY g.name
|
||||
`
|
||||
|
||||
rows, err := h.db.Query(query)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to list groups", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list groups"})
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var groups []map[string]interface{}
|
||||
for rows.Next() {
|
||||
var g struct {
|
||||
ID string
|
||||
Name string
|
||||
Description sql.NullString
|
||||
IsSystem bool
|
||||
CreatedAt string
|
||||
UpdatedAt string
|
||||
UserCount int
|
||||
RoleCount int
|
||||
}
|
||||
if err := rows.Scan(&g.ID, &g.Name, &g.Description, &g.IsSystem,
|
||||
&g.CreatedAt, &g.UpdatedAt, &g.UserCount, &g.RoleCount); err != nil {
|
||||
h.logger.Error("Failed to scan group", "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
groups = append(groups, map[string]interface{}{
|
||||
"id": g.ID,
|
||||
"name": g.Name,
|
||||
"description": g.Description.String,
|
||||
"is_system": g.IsSystem,
|
||||
"user_count": g.UserCount,
|
||||
"role_count": g.RoleCount,
|
||||
"created_at": g.CreatedAt,
|
||||
"updated_at": g.UpdatedAt,
|
||||
})
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"groups": groups})
|
||||
}
|
||||
|
||||
// GetGroup retrieves a single group
|
||||
func (h *Handler) GetGroup(c *gin.Context) {
|
||||
groupID := c.Param("id")
|
||||
|
||||
group, err := GetGroupByID(h.db, groupID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "group not found"})
|
||||
return
|
||||
}
|
||||
|
||||
users, _ := GetGroupUsers(h.db, groupID)
|
||||
roles, _ := GetGroupRoles(h.db, groupID)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"id": group.ID,
|
||||
"name": group.Name,
|
||||
"description": group.Description,
|
||||
"is_system": group.IsSystem,
|
||||
"user_count": group.UserCount,
|
||||
"role_count": group.RoleCount,
|
||||
"users": users,
|
||||
"roles": roles,
|
||||
"created_at": group.CreatedAt,
|
||||
"updated_at": group.UpdatedAt,
|
||||
})
|
||||
}
|
||||
|
||||
// CreateGroup creates a new group
|
||||
func (h *Handler) CreateGroup(c *gin.Context) {
|
||||
var req struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.logger.Error("Invalid request to create group", "error", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// Trim whitespace
|
||||
req.Name = strings.TrimSpace(req.Name)
|
||||
if req.Name == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "name is required"})
|
||||
return
|
||||
}
|
||||
|
||||
// Handle empty description
|
||||
description := strings.TrimSpace(req.Description)
|
||||
if description == "" {
|
||||
description = ""
|
||||
}
|
||||
|
||||
query := `
|
||||
INSERT INTO groups (name, description)
|
||||
VALUES ($1, $2)
|
||||
RETURNING id
|
||||
`
|
||||
|
||||
var groupID string
|
||||
err := h.db.QueryRow(query, req.Name, description).Scan(&groupID)
|
||||
if err != nil {
|
||||
// Check if it's a unique constraint violation
|
||||
if strings.Contains(err.Error(), "duplicate key") || strings.Contains(err.Error(), "unique constraint") {
|
||||
h.logger.Error("Group name already exists", "name", req.Name, "error", err)
|
||||
c.JSON(http.StatusConflict, gin.H{"error": "group name already exists"})
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to create group", "error", err, "name", req.Name)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create group: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Info("Group created successfully", "group_id", groupID, "name", req.Name)
|
||||
c.JSON(http.StatusCreated, gin.H{"id": groupID, "name": req.Name})
|
||||
}
|
||||
|
||||
// UpdateGroup updates an existing group
|
||||
func (h *Handler) UpdateGroup(c *gin.Context) {
|
||||
groupID := c.Param("id")
|
||||
|
||||
// Check if group is system group
|
||||
var isSystem bool
|
||||
err := h.db.QueryRow("SELECT is_system FROM groups WHERE id = $1", groupID).Scan(&isSystem)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "group not found"})
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
// Build update query dynamically
|
||||
var updates []string
|
||||
var args []interface{}
|
||||
argIndex := 1
|
||||
|
||||
if req.Name != "" {
|
||||
updates = append(updates, fmt.Sprintf("name = $%d", argIndex))
|
||||
args = append(args, req.Name)
|
||||
argIndex++
|
||||
}
|
||||
|
||||
if req.Description != "" {
|
||||
updates = append(updates, fmt.Sprintf("description = $%d", argIndex))
|
||||
args = append(args, req.Description)
|
||||
argIndex++
|
||||
}
|
||||
|
||||
if len(updates) == 0 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "no fields to update"})
|
||||
return
|
||||
}
|
||||
|
||||
updates = append(updates, "updated_at = NOW()")
|
||||
args = append(args, groupID)
|
||||
|
||||
query := fmt.Sprintf("UPDATE groups SET %s WHERE id = $%d", strings.Join(updates, ", "), argIndex)
|
||||
|
||||
_, err = h.db.Exec(query, args...)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to update group", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to update group"})
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Info("Group updated", "group_id", groupID)
|
||||
c.JSON(http.StatusOK, gin.H{"message": "group updated successfully"})
|
||||
}
|
||||
|
||||
// DeleteGroup deletes a group
|
||||
func (h *Handler) DeleteGroup(c *gin.Context) {
|
||||
groupID := c.Param("id")
|
||||
|
||||
// Check if group is system group
|
||||
var isSystem bool
|
||||
err := h.db.QueryRow("SELECT is_system FROM groups WHERE id = $1", groupID).Scan(&isSystem)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "group not found"})
|
||||
return
|
||||
}
|
||||
|
||||
if isSystem {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "cannot delete system group"})
|
||||
return
|
||||
}
|
||||
|
||||
_, err = h.db.Exec("DELETE FROM groups WHERE id = $1", groupID)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to delete group", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete group"})
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Info("Group deleted", "group_id", groupID)
|
||||
c.JSON(http.StatusOK, gin.H{"message": "group deleted successfully"})
|
||||
}
|
||||
|
||||
// AddUserToGroup adds a user to a group
|
||||
func (h *Handler) AddUserToGroup(c *gin.Context) {
|
||||
groupID := c.Param("id")
|
||||
var req struct {
|
||||
UserID string `json:"user_id" binding:"required"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
// Get current user ID from context
|
||||
authUser, _ := c.Get("user")
|
||||
currentUser := authUser.(*User)
|
||||
|
||||
err := AddUserToGroup(h.db, req.UserID, groupID, currentUser.ID)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to add user to group", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to add user to group"})
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Info("User added to group", "user_id", req.UserID, "group_id", groupID)
|
||||
c.JSON(http.StatusOK, gin.H{"message": "user added to group successfully"})
|
||||
}
|
||||
|
||||
// RemoveUserFromGroup removes a user from a group
|
||||
func (h *Handler) RemoveUserFromGroup(c *gin.Context) {
|
||||
groupID := c.Param("id")
|
||||
userID := c.Param("user_id")
|
||||
|
||||
err := RemoveUserFromGroup(h.db, userID, groupID)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to remove user from group", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to remove user from group"})
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Info("User removed from group", "user_id", userID, "group_id", groupID)
|
||||
c.JSON(http.StatusOK, gin.H{"message": "user removed from group successfully"})
|
||||
}
|
||||
|
||||
// AssignRoleToUser assigns a role to a user
|
||||
func (h *Handler) AssignRoleToUser(c *gin.Context) {
|
||||
userID := c.Param("id")
|
||||
var req struct {
|
||||
RoleName string `json:"role_name" binding:"required"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
// Get role ID by name
|
||||
roleID, err := GetRoleIDByName(h.db, req.RoleName)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "role not found"})
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to get role", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to assign role"})
|
||||
return
|
||||
}
|
||||
|
||||
// Get current user ID from context
|
||||
authUser, _ := c.Get("user")
|
||||
currentUser := authUser.(*User)
|
||||
|
||||
err = AddUserRole(h.db, userID, roleID, currentUser.ID)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to assign role to user", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to assign role"})
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Info("Role assigned to user", "user_id", userID, "role", req.RoleName)
|
||||
c.JSON(http.StatusOK, gin.H{"message": "role assigned successfully"})
|
||||
}
|
||||
|
||||
// RemoveRoleFromUser removes a role from a user
|
||||
func (h *Handler) RemoveRoleFromUser(c *gin.Context) {
|
||||
userID := c.Param("id")
|
||||
var req struct {
|
||||
RoleName string `json:"role_name" binding:"required"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
// Get role ID by name
|
||||
roleID, err := GetRoleIDByName(h.db, req.RoleName)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "role not found"})
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to get role", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to remove role"})
|
||||
return
|
||||
}
|
||||
|
||||
err = RemoveUserRole(h.db, userID, roleID)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to remove role from user", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to remove role"})
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Info("Role removed from user", "user_id", userID, "role", req.RoleName)
|
||||
c.JSON(http.StatusOK, gin.H{"message": "role removed successfully"})
|
||||
}
|
||||
|
||||
// AssignGroupToUser assigns a group to a user
|
||||
func (h *Handler) AssignGroupToUser(c *gin.Context) {
|
||||
userID := c.Param("id")
|
||||
var req struct {
|
||||
GroupName string `json:"group_name" binding:"required"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
// Get group ID by name
|
||||
group, err := GetGroupByName(h.db, req.GroupName)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "group not found"})
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to get group", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to assign group"})
|
||||
return
|
||||
}
|
||||
groupID := group.ID
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "group not found"})
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to get group", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to assign group"})
|
||||
return
|
||||
}
|
||||
|
||||
// Get current user ID from context
|
||||
authUser, _ := c.Get("user")
|
||||
currentUser := authUser.(*User)
|
||||
|
||||
err = AddUserToGroup(h.db, userID, groupID, currentUser.ID)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to assign group to user", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to assign group"})
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Info("Group assigned to user", "user_id", userID, "group", req.GroupName)
|
||||
c.JSON(http.StatusOK, gin.H{"message": "group assigned successfully"})
|
||||
}
|
||||
|
||||
// RemoveGroupFromUser removes a group from a user
|
||||
func (h *Handler) RemoveGroupFromUser(c *gin.Context) {
|
||||
userID := c.Param("id")
|
||||
var req struct {
|
||||
GroupName string `json:"group_name" binding:"required"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
// Get group ID by name
|
||||
group, err := GetGroupByName(h.db, req.GroupName)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "group not found"})
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to get group", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to assign group"})
|
||||
return
|
||||
}
|
||||
groupID := group.ID
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "group not found"})
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to get group", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to remove group"})
|
||||
return
|
||||
}
|
||||
|
||||
err = RemoveUserFromGroup(h.db, userID, groupID)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to remove group from user", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to remove group"})
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Info("Group removed from user", "user_id", userID, "group", req.GroupName)
|
||||
c.JSON(http.StatusOK, gin.H{"message": "group removed successfully"})
|
||||
}
|
||||
|
||||
@@ -126,3 +126,27 @@ func GetUserPermissions(db *database.DB, userID string) ([]string, error) {
|
||||
return permissions, rows.Err()
|
||||
}
|
||||
|
||||
// AddUserRole assigns a role to a user
|
||||
func AddUserRole(db *database.DB, userID, roleID, assignedBy string) error {
|
||||
query := `
|
||||
INSERT INTO user_roles (user_id, role_id, assigned_by)
|
||||
VALUES ($1, $2, $3)
|
||||
ON CONFLICT (user_id, role_id) DO NOTHING
|
||||
`
|
||||
_, err := db.Exec(query, userID, roleID, assignedBy)
|
||||
return err
|
||||
}
|
||||
|
||||
// RemoveUserRole removes a role from a user
|
||||
func RemoveUserRole(db *database.DB, userID, roleID string) error {
|
||||
query := `DELETE FROM user_roles WHERE user_id = $1 AND role_id = $2`
|
||||
_, err := db.Exec(query, userID, roleID)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetRoleIDByName retrieves a role ID by name
|
||||
func GetRoleIDByName(db *database.DB, roleName string) (string, error) {
|
||||
var roleID string
|
||||
err := db.QueryRow("SELECT id FROM roles WHERE name = $1", roleName).Scan(&roleID)
|
||||
return roleID, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user