Files
calypso/backend/internal/iam/user.go
2025-12-27 16:58:19 +00:00

153 lines
3.6 KiB
Go

package iam
import (
"database/sql"
"time"
"github.com/atlasos/calypso/internal/common/database"
)
// User represents a system user
type User struct {
ID string
Username string
Email string
PasswordHash string
FullName string
IsActive bool
IsSystem bool
CreatedAt time.Time
UpdatedAt time.Time
LastLoginAt sql.NullTime
Roles []string
Permissions []string
}
// GetUserByID retrieves a user by ID
func GetUserByID(db *database.DB, userID string) (*User, error) {
query := `
SELECT id, username, email, password_hash, full_name, is_active, is_system,
created_at, updated_at, last_login_at
FROM users
WHERE id = $1
`
var user User
var lastLogin sql.NullTime
err := db.QueryRow(query, userID).Scan(
&user.ID, &user.Username, &user.Email, &user.PasswordHash,
&user.FullName, &user.IsActive, &user.IsSystem,
&user.CreatedAt, &user.UpdatedAt, &lastLogin,
)
if err != nil {
return nil, err
}
user.LastLoginAt = lastLogin
return &user, nil
}
// GetUserByUsername retrieves a user by username
func GetUserByUsername(db *database.DB, username string) (*User, error) {
query := `
SELECT id, username, email, password_hash, full_name, is_active, is_system,
created_at, updated_at, last_login_at
FROM users
WHERE username = $1
`
var user User
var lastLogin sql.NullTime
err := db.QueryRow(query, username).Scan(
&user.ID, &user.Username, &user.Email, &user.PasswordHash,
&user.FullName, &user.IsActive, &user.IsSystem,
&user.CreatedAt, &user.UpdatedAt, &lastLogin,
)
if err != nil {
return nil, err
}
user.LastLoginAt = lastLogin
return &user, nil
}
// GetUserRoles retrieves all roles for a user
func GetUserRoles(db *database.DB, userID string) ([]string, error) {
query := `
SELECT r.name
FROM roles r
INNER JOIN user_roles ur ON r.id = ur.role_id
WHERE ur.user_id = $1
`
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()
}
// GetUserPermissions retrieves all permissions for a user (via roles)
func GetUserPermissions(db *database.DB, userID string) ([]string, error) {
query := `
SELECT DISTINCT p.name
FROM permissions p
INNER JOIN role_permissions rp ON p.id = rp.permission_id
INNER JOIN user_roles ur ON rp.role_id = ur.role_id
WHERE ur.user_id = $1
`
rows, err := db.Query(query, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var permissions []string
for rows.Next() {
var perm string
if err := rows.Scan(&perm); err != nil {
return nil, err
}
permissions = append(permissions, perm)
}
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
}