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 }