137 lines
3.2 KiB
Go
137 lines
3.2 KiB
Go
package acl
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// GetRoles returns all roles.
|
|
// May return [ErrNotInitialized] or db error.
|
|
func (s *Service) GetRoles() ([]Role, error) {
|
|
if !s.isInitialized() {
|
|
return nil, ErrNotInitialized
|
|
}
|
|
|
|
var roles []Role
|
|
if err := s.db.Preload("Resources").Order("id").Find(&roles).Error; err != nil {
|
|
return nil, fmt.Errorf("db error: %w", err)
|
|
}
|
|
|
|
return roles, nil
|
|
}
|
|
|
|
// CreateRole creates a new role with the given name or returns existing one.
|
|
// Returns the ID of the created role.
|
|
// May return [ErrNotInitialized], [ErrInvalidRoleName], [ErrRoleAlreadyExists] or db error.
|
|
func (s *Service) CreateRole(name string) (uint, error) {
|
|
if !s.isInitialized() {
|
|
return 0, ErrNotInitialized
|
|
}
|
|
|
|
name = strings.TrimSpace(name)
|
|
if name == "" {
|
|
return 0, ErrInvalidRoleName
|
|
}
|
|
|
|
var role Role
|
|
if err := s.db.Where("name = ?", name).First(&role).Error; err == nil {
|
|
// already exists
|
|
return role.ID, ErrRoleAlreadyExists
|
|
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
// other database error
|
|
return 0, fmt.Errorf("db error: %w", err)
|
|
}
|
|
|
|
role = Role{Name: name}
|
|
if err := s.db.Create(&role).Error; err != nil {
|
|
return 0, fmt.Errorf("db error: %w", err)
|
|
}
|
|
|
|
return role.ID, nil
|
|
}
|
|
|
|
// GetRoleByID returns the role with the given ID or an error.
|
|
// May return [ErrNotInitialized], [ErrRoleNotFound] or db error.
|
|
func (s *Service) GetRoleByID(roleID uint) (*Role, error) {
|
|
if !s.isInitialized() {
|
|
return nil, ErrNotInitialized
|
|
}
|
|
var role Role
|
|
err := s.db.Preload("Resources").First(&role, roleID).Error
|
|
if err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, ErrRoleNotFound
|
|
}
|
|
return nil, fmt.Errorf("db error: %w", err)
|
|
}
|
|
|
|
return &role, nil
|
|
}
|
|
|
|
// UpdateRole updates the name of a role.
|
|
// May return [ErrNotInitialized], [ErrInvalidRoleName], [ErrRoleNotFound], [ErrSameRoleName], or db error.
|
|
func (s *Service) UpdateRole(roleID uint, newName string) error {
|
|
if !s.isInitialized() {
|
|
return ErrNotInitialized
|
|
}
|
|
|
|
newName = strings.TrimSpace(newName)
|
|
if newName == "" {
|
|
return ErrInvalidRoleName
|
|
}
|
|
|
|
var role Role
|
|
err := s.db.First(&role, roleID).Error
|
|
if err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return ErrRoleNotFound
|
|
}
|
|
return fmt.Errorf("db error: %w", err)
|
|
}
|
|
|
|
// check for name conflicts
|
|
if role.Name == newName {
|
|
return ErrSameRoleName
|
|
}
|
|
var count int64
|
|
err = s.db.Model(&Role{}).Where("name = ? AND id != ?", newName, roleID).Count(&count).Error
|
|
if err != nil {
|
|
return fmt.Errorf("db error: %w", err)
|
|
}
|
|
if count > 0 {
|
|
return ErrSameRoleName
|
|
}
|
|
|
|
role.Name = newName
|
|
if err := s.db.Save(&role).Error; err != nil {
|
|
return fmt.Errorf("failed to update role: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// DeleteRole deletes a role.
|
|
// May return [ErrNotInitialized], [ErrRoleNotFound], [ErrRoleInUse] or db error.
|
|
func (s *Service) DeleteRole(roleID uint) error {
|
|
if !s.isInitialized() {
|
|
return ErrNotInitialized
|
|
}
|
|
|
|
result := s.db.Delete(&Role{}, roleID)
|
|
if err := result.Error; err != nil {
|
|
if strings.Contains(err.Error(), "FOREIGN KEY constraint failed") {
|
|
return ErrRoleInUse
|
|
}
|
|
return fmt.Errorf("db error: %w", err)
|
|
}
|
|
|
|
if result.RowsAffected == 0 {
|
|
return ErrRoleNotFound
|
|
}
|
|
|
|
return nil
|
|
}
|