118 lines
2.8 KiB
Go
118 lines
2.8 KiB
Go
package useCases
|
|
|
|
import (
|
|
"RenewCMS/internal/domain/audit"
|
|
"RenewCMS/internal/domain/builtintype"
|
|
"RenewCMS/internal/domain/contenttype"
|
|
"RenewCMS/internal/domain/role"
|
|
"RenewCMS/internal/domain/user"
|
|
"context"
|
|
"errors"
|
|
"slices"
|
|
)
|
|
|
|
func roleTarget(found role.Role) audit.Target {
|
|
return audit.NewTarget(audit.TargetRole, found.ID, found.Name)
|
|
}
|
|
|
|
func allowedTypeKeys(contentTypes contenttype.Repository) ([]string, error) {
|
|
types, err := contentTypes.List()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
keys := []string{builtintype.KeyArticle}
|
|
for _, contentType := range types {
|
|
keys = append(keys, contentType.Key)
|
|
}
|
|
slices.Sort(keys)
|
|
return keys, nil
|
|
}
|
|
|
|
func ensureCovered(caller ContentCaller, contentTypes contenttype.Repository, candidate role.Role) error {
|
|
typeKeys, err := allowedTypeKeys(contentTypes)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return caller.Grants.Covers(candidate.GrantSet(), typeKeys)
|
|
}
|
|
|
|
func ensureNotOwnRole(roles role.Repository, users user.Repository, caller ContentCaller, target role.Role) error {
|
|
account, err := users.Get(caller.UserID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
own, err := resolveRole(roles, account)
|
|
if errors.Is(err, role.ErrRoleNotFound) {
|
|
return nil
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if own.ID == target.ID {
|
|
return role.ErrOwnRole
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func ensureEditable(target role.Role) error {
|
|
if target.Locked {
|
|
return role.ErrRoleLocked
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func ensureNotBuiltIn(target role.Role) error {
|
|
if target.BuiltIn {
|
|
return role.ErrBuiltInRole
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func ensureNameFree(roles role.Repository, name string, excludedID uint32) error {
|
|
existing, err := roles.List()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, other := range existing {
|
|
if other.ID != excludedID && role.SameName(other.Name, name) {
|
|
return role.ErrRoleNameTaken
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateRoleGrants(contentTypes contenttype.Repository, grants []role.Grant) error {
|
|
if err := role.ValidateGrants(false, grants); err != nil {
|
|
return err
|
|
}
|
|
typeKeys, err := allowedTypeKeys(contentTypes)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return role.ValidateGrantTypes(grants, typeKeys)
|
|
}
|
|
|
|
func normalizedGrants(grants []role.Grant) []role.Grant {
|
|
return role.Role{Grants: grants}.EffectiveGrants()
|
|
}
|
|
|
|
var writeRefusals = []error{role.ErrRoleConflict, role.ErrRoleHasMembers, role.ErrRoleNotFound, role.ErrRoleNameTaken, role.ErrInvalidReassign}
|
|
|
|
func recordRoleWriteFailure(ctx context.Context, recorder audit.Recorder, event audit.Event, err error) {
|
|
for _, refusal := range writeRefusals {
|
|
if errors.Is(err, refusal) {
|
|
return
|
|
}
|
|
}
|
|
recordFailure(ctx, recorder, event, err)
|
|
}
|
|
|
|
func grantsParams(diff role.GrantDiff, members int) map[string]any {
|
|
return map[string]any{
|
|
audit.ParamAdded: diff.Added,
|
|
audit.ParamRemoved: diff.Removed,
|
|
audit.ParamChanged: diff.Changed,
|
|
audit.ParamMembers: members,
|
|
}
|
|
}
|