package storage import ( "slices" "gorm.io/gorm" ) // A role is, in concept, similar to how Discord handles roles // Some permission can be either disallowed (&false), don't care (nil) or allowed (&true) // Don't care just says to use the value from the next lower role where it is set type Role struct { // TODO: More control options // Extend upon whatever Masto, Akkoma and Misskey have // Lots of details please // --- Role metadata --- // Include full db model stuff gorm.Model // Name of the role Name string // Priority of the role // Lower priority gets applied first and thus overwritten by higher priority ones // If two roles have the same priority, the order is undetermined and may be random // Default priority for new roles is 1 to always overwrite default user // And full admin has max priority possible Priority uint // Whether this role is for a for a single user only (like custom, per user permissions in Discord) // If yes, Name will be the id of the user in question IsUserRole bool // Whether this role is one built into Linstrom from the start or not // Note: Built-in roles can't be modified IsBuiltIn bool // --- User permissions --- CanSendMedia *bool CanSendCustomEmotes *bool CanSendCustomReactions *bool CanSendPublicNotes *bool CanSendLocalNotes *bool CanSendFollowerOnlyNotes *bool CanSendPrivateNotes *bool CanSendReplies *bool CanQuote *bool CanBoost *bool CanIncludeLinks *bool CanIncludeSurvey *bool CanChangeDisplayName *bool BlockedUsers []string `gorm:"type:bytes;serializer:gob"` CanSubmitReports *bool CanLogin *bool CanMentionOthers *bool HasMentionCountLimit *bool MentionLimit *uint32 // CanViewBoosts *bool // CanViewQuotes *bool // CanViewMedia *bool // CanViewCustomEmotes *bool // --- Automod --- AutoNsfwMedia *bool AutoCwPosts *bool AutoCwPostsText *string ScanCreatedPublicNotes *bool ScanCreatedLocalNotes *bool ScanCreatedFollowerOnlyNotes *bool ScanCreatedPrivateNotes *bool DisallowInteractionsWith []string `gorm:"type:bytes;serializer:gob"` WithholdNotesForManualApproval *bool WithholdNotesBasedOnRegex *bool WithholdNotesRegexes []string `gorm:"type:bytes;serializer:gob"` // --- Admin perms --- // If set, counts as all permissions being set as given and all restrictions being disabled FullAdmin *bool CanAffectOtherAdmins *bool CanDeleteNotes *bool CanConfirmWithheldNotes *bool CanAssignRoles *bool CanSupressInteractionsBetweenUsers *bool CanOverwriteDisplayNames *bool CanManageCustomEmotes *bool CanViewDeletedNotes *bool CanRecoverDeletedNotes *bool CanManageAvatarDecorations *bool CanManageAds *bool CanSendAnnouncements *bool } /* Mastodon permissions (highest permission to lowest): - Admin - Devops - View Audit log - View Dashboard - Manage Reports - Manage Federation - Manage Settings - Manage Blocks - Manage Taxonomies - Manage Appeals - Manage Users - Manage Invites - Manage Rules - Manage Announcements - Manage Custom Emojis - Manage Webhooks - Invite Users - Manage Roles - Manage User Access - Delete User Data */ /* Misskey "permissions" (no order): - Global timeline available (interact with global timeline I think) - Local timeline available (same as global, but for local) - b-something timeline available - Can send public notes - How many mentions a note can have - Can invite others - How many invites can be sent - InviteLimitCycle (whatever that means) - Invite Expiration time (duration of how long invites stay valid I think) - Manage custom emojis - Manage custom avatar decorations - Seach for notes - Use translator - Hide ads from self - How much storage space the user has - Whether to mark all posts from account as nsfw - max number of pinned messages - max number of antennas - max number of muted words - max number of webhooks - max number of clips - max number of notes contained in a clip (? I think. Don't know enough about clips) - Max number of lists of users - max number of users in a user list - rate limit multiplier - max number of applied avatar decorations */ func (s *Storage) NewEmptyRole(name string) (*Role, error) { _, err := s.FindRoleByName(name) switch err { case nil: return nil, ErrEntryAlreadyExists case ErrEntryNotFound: // Empty case, since this is what we want default: return nil, err } newRole := Role{Name: name} err = s.db.Create(&newRole).Error if err != nil { return nil, err } return &newRole, nil } func (s *Storage) FindRoleByName(name string) (*Role, error) { role := Role{} err := s.db.Where("name = ?", name).First(&role).Error switch err { case nil: return &role, nil case gorm.ErrRecordNotFound: return nil, ErrEntryNotFound default: return nil, err } } func CollapseRolesIntoOne(roles ...*Role) *Role { // TODO: Can I make a fucking script for automating this bullshit function? // I. Do. Not. Want. To. Manually adjust this every time I change something about Roles startingRole := DefaultUserRole slices.SortFunc(roles, func(a, b *Role) int { return int(int64(a.Priority) - int64(b.Priority)) }) for _, role := range roles { if role.CanSendMedia != nil { *startingRole.CanSendMedia = *role.CanSendMedia } if role.CanSendCustomEmotes != nil { *startingRole.CanSendCustomEmotes = *role.CanSendCustomEmotes } if role.CanSendCustomReactions != nil { *startingRole.CanSendCustomReactions = *role.CanSendCustomReactions } if role.CanSendPublicNotes != nil { *startingRole.CanSendPublicNotes = *role.CanSendPublicNotes } if role.CanSendLocalNotes != nil { *startingRole.CanSendLocalNotes = *role.CanSendLocalNotes } if role.CanSendFollowerOnlyNotes != nil { *startingRole.CanSendFollowerOnlyNotes = *role.CanSendFollowerOnlyNotes } if role.CanSendPrivateNotes != nil { *startingRole.CanSendPrivateNotes = *role.CanSendPrivateNotes } if role.CanSendReplies != nil { *startingRole.CanSendReplies = *role.CanSendReplies } if role.CanQuote != nil { *startingRole.CanQuote = *role.CanQuote } if role.CanBoost != nil { *startingRole.CanBoost = *role.CanBoost } if role.CanIncludeLinks != nil { *startingRole.CanIncludeLinks = *role.CanIncludeLinks } if role.CanIncludeSurvey != nil { *startingRole.CanIncludeSurvey = *role.CanIncludeSurvey } if role.CanChangeDisplayName != nil { *startingRole.CanChangeDisplayName = *role.CanChangeDisplayName } if role.BlockedUsers != nil { startingRole.BlockedUsers = append(startingRole.BlockedUsers, role.BlockedUsers...) } if role.CanSubmitReports != nil { *startingRole.CanSubmitReports = *role.CanSubmitReports } if role.CanLogin != nil { *startingRole.CanLogin = *role.CanLogin } if role.CanMentionOthers != nil { *startingRole.CanMentionOthers = *role.CanMentionOthers } if role.HasMentionCountLimit != nil { *startingRole.HasMentionCountLimit = *role.HasMentionCountLimit *startingRole.MentionLimit = *role.MentionLimit } if role.AutoNsfwMedia != nil { *startingRole.AutoNsfwMedia = *role.AutoNsfwMedia } if role.AutoCwPosts != nil { *startingRole.AutoCwPosts = *role.AutoCwPosts } if role.AutoCwPostsText != nil { *startingRole.AutoCwPostsText = *role.AutoCwPostsText } if role.ScanCreatedPublicNotes != nil { *startingRole.ScanCreatedPublicNotes = *role.ScanCreatedPublicNotes } if role.ScanCreatedLocalNotes != nil { *startingRole.ScanCreatedLocalNotes = *role.ScanCreatedLocalNotes } if role.ScanCreatedFollowerOnlyNotes != nil { *startingRole.ScanCreatedFollowerOnlyNotes = *role.ScanCreatedFollowerOnlyNotes } if role.ScanCreatedPrivateNotes != nil { *startingRole.ScanCreatedPrivateNotes = *role.ScanCreatedPrivateNotes } if role.DisallowInteractionsWith != nil { startingRole.DisallowInteractionsWith = append(startingRole.DisallowInteractionsWith, role.DisallowInteractionsWith...) } if role.WithholdNotesForManualApproval != nil { *startingRole.WithholdNotesForManualApproval = *role.WithholdNotesForManualApproval } if role.WithholdNotesBasedOnRegex != nil { *startingRole.WithholdNotesBasedOnRegex = *role.WithholdNotesBasedOnRegex startingRole.WithholdNotesRegexes = append(startingRole.WithholdNotesRegexes, role.WithholdNotesRegexes...) } if role.FullAdmin != nil { *startingRole.FullAdmin = *role.FullAdmin } if role.CanAffectOtherAdmins != nil { *startingRole.CanAffectOtherAdmins = *role.CanAffectOtherAdmins } if role.CanDeleteNotes != nil { *startingRole.CanDeleteNotes = *role.CanDeleteNotes } if role.CanConfirmWithheldNotes != nil { *startingRole.CanConfirmWithheldNotes = *role.CanConfirmWithheldNotes } if role.CanAssignRoles != nil { *startingRole.CanAssignRoles = *role.CanAssignRoles } if role.CanSupressInteractionsBetweenUsers != nil { *startingRole.CanSupressInteractionsBetweenUsers = *role.CanSupressInteractionsBetweenUsers } if role.CanOverwriteDisplayNames != nil { *startingRole.CanOverwriteDisplayNames = *role.CanOverwriteDisplayNames } if role.CanManageCustomEmotes != nil { *startingRole.CanManageCustomEmotes = *role.CanManageCustomEmotes } if role.CanViewDeletedNotes != nil { *startingRole.CanViewDeletedNotes = *role.CanViewDeletedNotes } if role.CanRecoverDeletedNotes != nil { *startingRole.CanRecoverDeletedNotes = *role.CanRecoverDeletedNotes } if role.CanManageAvatarDecorations != nil { *startingRole.CanManageAvatarDecorations = *role.CanManageAvatarDecorations } if role.CanManageAds != nil { *startingRole.CanManageAds = *role.CanManageAds } if role.CanSendAnnouncements != nil { *startingRole.CanSendAnnouncements = *role.CanSendAnnouncements } } return &startingRole }