Files
RenewCMS/internal/infrastructure/useCases/ListUsersAndInvites.go
T

129 lines
3.1 KiB
Go

package useCases
import (
"RenewCMS/internal/domain/invite"
"RenewCMS/internal/domain/role"
"RenewCMS/internal/domain/user"
"errors"
"sort"
"time"
)
const (
EntryKindUser = "user"
EntryKindInvite = "invite"
)
type ListUsersAndInvitesUseCase struct {
userRepository user.Repository
inviteRepository invite.Repository
roles role.Repository
}
type RoleAssigner struct {
ID uint32
Name string
}
func newRoleAssigner(account user.User) *RoleAssigner {
return &RoleAssigner{ID: account.ID, Name: account.NameOrUsername()}
}
func resolveRoleAssigner(users user.Repository, id uint32) (*RoleAssigner, error) {
if id == 0 {
return nil, nil
}
found, err := users.Get(id)
if errors.Is(err, user.ErrUserNotFound) {
return nil, nil
}
if err != nil {
return nil, err
}
return newRoleAssigner(found), nil
}
type DirectoryEntry struct {
ID uint32
Kind string
Username string
DisplayName string
Email string
Role *RoleRef
RoleAssignedBy *RoleAssigner
Status string
CreatedAt time.Time
}
func NewListUsersAndInvitesUseCase(userRepository user.Repository, inviteRepository invite.Repository, roles role.Repository) *ListUsersAndInvitesUseCase {
return &ListUsersAndInvitesUseCase{userRepository, inviteRepository, roles}
}
func userEntry(account user.User, found *RoleRef, assigner *RoleAssigner) DirectoryEntry {
return DirectoryEntry{
ID: account.ID,
Kind: EntryKindUser,
Username: account.Username,
DisplayName: account.DisplayName,
Email: account.Email,
Role: found,
RoleAssignedBy: assigner,
Status: string(invite.StatusAccepted),
CreatedAt: account.CreatedAt,
}
}
func assignerAmong(loaded map[uint32]user.User, id uint32) *RoleAssigner {
found, present := loaded[id]
if id == 0 || !present {
return nil
}
return newRoleAssigner(found)
}
func (g *ListUsersAndInvitesUseCase) ListUsersAndInvites() ([]DirectoryEntry, error) {
refs, err := roleRefsByID(g.roles)
if err != nil {
return nil, err
}
now := time.Now()
entries := []DirectoryEntry{}
users, err := g.userRepository.GetAll()
if err != nil {
return nil, err
}
loaded := make(map[uint32]user.User, len(users))
for _, existingUser := range users {
loaded[existingUser.ID] = existingUser
}
for _, existingUser := range users {
entries = append(entries, userEntry(existingUser, lookupRoleRef(refs, existingUser.RoleID), assignerAmong(loaded, existingUser.RoleAssignedByID)))
}
invites, err := g.inviteRepository.GetAll()
if err != nil {
return nil, err
}
for _, existingInvite := range invites {
status := existingInvite.StatusAt(now)
if status == invite.StatusAccepted {
continue
}
entries = append(entries, DirectoryEntry{
ID: existingInvite.ID,
Kind: EntryKindInvite,
Email: existingInvite.Email,
Role: lookupRoleRef(refs, existingInvite.RoleID),
Status: string(status),
CreatedAt: existingInvite.CreatedAt,
})
}
sort.SliceStable(entries, func(i, j int) bool {
return entries[i].CreatedAt.After(entries[j].CreatedAt)
})
return entries, nil
}