Files
GoMFT/internal/db/role_store.go
T

144 lines
4.0 KiB
Go

package db
import (
"errors"
"fmt"
"gorm.io/gorm"
)
// --- Role Store Methods ---
// CreateRole creates a new role record
func (db *DB) CreateRole(role *Role) error {
return db.Create(role).Error
}
// GetRole retrieves a role by ID, preloading permissions
func (db *DB) GetRole(id uint) (*Role, error) {
var role Role
// Assuming Permissions are handled correctly by GORM or custom type
err := db.First(&role, id).Error
if err != nil {
return nil, err
}
return &role, nil
}
// GetRoleByName retrieves a role by name, preloading permissions
func (db *DB) GetRoleByName(name string) (*Role, error) {
var role Role
err := db.Where("name = ?", name).First(&role).Error
if err != nil {
return nil, err
}
return &role, nil
}
// UpdateRole updates an existing role record
func (db *DB) UpdateRole(role *Role) error {
// Use Omit Users to prevent GORM from trying to update the many2many relationship directly here
return db.Omit("Users").Save(role).Error
}
// DeleteRole deletes a role after checking dependencies and removing assignments
func (db *DB) DeleteRole(id uint) error {
var role Role
if err := db.First(&role, id).Error; err != nil {
return fmt.Errorf("role not found: %w", err)
}
if role.IsSystemRole() {
return errors.New("cannot delete system role")
}
// Start transaction
tx := db.Begin()
if err := tx.Error; err != nil {
return err
}
// Manually delete role assignments from the join table
if err := tx.Exec("DELETE FROM user_roles WHERE role_id = ?", id).Error; err != nil {
tx.Rollback()
return fmt.Errorf("failed to delete role assignments: %w", err)
}
// Delete the role itself
if err := tx.Delete(&role).Error; err != nil {
tx.Rollback()
return fmt.Errorf("failed to delete role: %w", err)
}
// Commit transaction
return tx.Commit().Error
}
// ListRoles retrieves all roles
func (db *DB) ListRoles() ([]Role, error) {
var roles []Role
err := db.Find(&roles).Error
return roles, err
}
// GetUserRoles retrieves all roles assigned to a specific user ID
func (db *DB) GetUserRoles(userID uint) ([]Role, error) {
var user User
// Preload the Roles association
if err := db.Preload("Roles").First(&user, userID).Error; err != nil {
// Handle case where user might not be found vs. other errors
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, fmt.Errorf("user with ID %d not found", userID)
}
return nil, fmt.Errorf("failed to get user %d roles: %w", userID, err)
}
return user.Roles, nil
}
// AssignRoleToUser assigns a role to a user, handling the join table
func (db *DB) AssignRoleToUser(roleID, userID, assignedByID uint) error {
var role Role
if err := db.First(&role, roleID).Error; err != nil {
return fmt.Errorf("role with ID %d not found: %w", roleID, err)
}
var user User
if err := db.First(&user, userID).Error; err != nil {
return fmt.Errorf("user with ID %d not found: %w", userID, err)
}
// Use GORM's Association API for many2many
err := db.Model(&user).Association("Roles").Append(&role)
if err != nil {
return fmt.Errorf("failed to assign role %d to user %d: %w", roleID, userID, err)
}
// Optionally, log the assignment (consider moving audit logging to a dedicated service/hook)
// db.Create(&AuditLog{...})
return nil
}
// UnassignRoleFromUser removes a role from a user, handling the join table
func (db *DB) UnassignRoleFromUser(roleID, userID, unassignedByID uint) error {
var role Role
if err := db.First(&role, roleID).Error; err != nil {
return fmt.Errorf("role with ID %d not found: %w", roleID, err)
}
var user User
// Need to preload roles to check if the association exists before deleting
if err := db.Preload("Roles").First(&user, userID).Error; err != nil {
return fmt.Errorf("user with ID %d not found: %w", userID, err)
}
// Use GORM's Association API for many2many deletion
err := db.Model(&user).Association("Roles").Delete(&role)
if err != nil {
return fmt.Errorf("failed to unassign role %d from user %d: %w", roleID, userID, err)
}
// Optionally, log the unassignment
// db.Create(&AuditLog{...})
return nil
}