diff --git a/auth-new/auth.go b/auth-new/auth.go index 0e7079f..03ea594 100644 --- a/auth-new/auth.go +++ b/auth-new/auth.go @@ -13,10 +13,13 @@ import ( "github.com/go-webauthn/webauthn/webauthn" ) +// An Authenticator is used for authenticating user requests against the server type Authenticator struct { webauthn *webauthn.WebAuthn recentlyUsedTotpTokens map[string]time.Time } + +// The next state of a login process type LoginNextState uint8 const ( diff --git a/auth-new/helpers.go b/auth-new/helpers.go index 5bf4153..f3b1ea5 100644 --- a/auth-new/helpers.go +++ b/auth-new/helpers.go @@ -18,6 +18,7 @@ import ( // Len of salt for passwords in bytes const saltLen = 32 +// Generate a random salt with the given nr of bytes func generateSalt(length int) ([]byte, error) { salt := make([]byte, length) if _, err := rand.Read(salt); err != nil { @@ -26,18 +27,19 @@ func generateSalt(length int) ([]byte, error) { return salt, nil } -func hashPassword(password string) ([]byte, error) { +// Hash a password with salt +func hashPassword(password string) (hash []byte, err error) { salt, err := generateSalt(saltLen) if err != nil { return nil, err } - hash := argon2.IDKey([]byte(password), salt, 1, 64*1024, 4, 32) + hash = argon2.IDKey([]byte(password), salt, 1, 64*1024, 4, 32) hash = append(hash, salt...) // return bcrypt.GenerateFromPassword([]byte(password), 14) return hash, nil } -// Compare a raw password against a hash + salt +// Check wether a password matches a hash func comparePassword(password string, hash []byte) bool { // Hash is actually hash(password)+salt salt := hash[len(hash)-saltLen:] @@ -47,6 +49,7 @@ func comparePassword(password string, hash []byte) bool { // Copied and adjusted from: https://bruinsslot.jp/post/golang-crypto/ +// Encrypt some data using a key func Encrypt(key, data []byte) ([]byte, error) { key, salt, err := deriveKey(key, nil) if err != nil { @@ -75,6 +78,7 @@ func Encrypt(key, data []byte) ([]byte, error) { return ciphertext, nil } +// Decrypt some data using a key func Decrypt(key, data []byte) ([]byte, error) { salt, data := data[len(data)-32:], data[:len(data)-32] @@ -103,6 +107,8 @@ func Decrypt(key, data []byte) ([]byte, error) { return plaintext, nil } +// Derive a key from a password and optionally salt. +// Returns the hash and salt used func deriveKey(password, salt []byte) ([]byte, []byte, error) { if salt == nil { salt = make([]byte, 32) @@ -115,12 +121,16 @@ func deriveKey(password, salt []byte) ([]byte, []byte, error) { return key, salt, nil } +// Calculate the expiration timestamp from the call of the function func calcAccessExpirationTimestamp() time.Time { // For now, the default expiration is one month after creation // though "never" might also be a good option return time.Now().Add(time.Hour * 24 * 30) } +// Convert a list of authentication methods into a [LoginNextState] bitflag. +// [isStart] determines whether to allow authentication methods that start +// a login process or complete one func ConvertNewStorageAuthMethodsToLoginState( methods []models.AuthenticationMethodType, isStart bool, @@ -141,6 +151,7 @@ func ConvertNewStorageAuthMethodsToLoginState( ) } +// Translate one [models.AuthenticationMethodType] to one [LoginNextState] func oneStorageAuthToLoginState(in models.AuthenticationMethodType) LoginNextState { switch in { case models.AuthMethodGAuth: diff --git a/auth-new/totp.go b/auth-new/totp.go index 14b90ee..bcb5f58 100644 --- a/auth-new/totp.go +++ b/auth-new/totp.go @@ -20,6 +20,7 @@ import ( const totpUnverifiedSuffix = "-NOT_VERIFIED" const totpTokenNoLongerRecentlyUsed = time.Second * 90 +// Perform a 2nd factor totp based login func (a *Authenticator) PerformTotpLogin( username string, sessionId uint64, @@ -119,6 +120,8 @@ func (a *Authenticator) PerformTotpLogin( return LoginNextSucess, token.Token, nil } +// Create a new totp key for a user. +// The key is marked as not verified until it is sucessfully used once func (a *Authenticator) StartTotpRegistration( username string, tokenName string, diff --git a/cmd/NewRoleHelperGenerator/main.go b/cmd/NewRoleHelperGenerator/main.go index 54fd8d6..58903a5 100644 --- a/cmd/NewRoleHelperGenerator/main.go +++ b/cmd/NewRoleHelperGenerator/main.go @@ -1,5 +1,5 @@ /* -Tool for generating helper functions for storage.Role structs inside of the storage package +Tool for generating helper functions for [new-storage.Role] structs inside of the storage package It generates the following functions: - CollapseRolesIntoOne: Collapse a list of roles into one singular role. Each value will be set to the value of the role with the highest priority @@ -116,7 +116,12 @@ func main() { // Build role collapse function outBuilder.WriteString( - `func CollapseRolesIntoOne(roles ...models.Role) models.Role { + `// CollapseRolesIntoOne takes a list of roles and collapses them down into one. +// It ensures to follow the priority of each role. +// All results will use [models.DefaultUserRole] as the baseline. +// The resulting role will have each entry filled with the value of the highest priority. +// If multiple roles have the same priority, the order in which they are applied is not stable. +func CollapseRolesIntoOne(roles ...models.Role) models.Role { startingRole := RoleDeepCopy(models.DefaultUserRole) slices.SortFunc(roles, func(a, b models.Role) int { return int(int64(a.Priority)-int64(b.Priority)) }) for _, role := range roles { @@ -143,7 +148,12 @@ func main() { `) // Then build the deep copy function - outBuilder.WriteString("\nfunc RoleDeepCopy(o models.Role) models.Role {\n") + outBuilder.WriteString(` +// RoleDeepCopy performs a deep copy of a given role. +// Each element will point to a newly stored value. +// The new and old role will contain identical information. +func RoleDeepCopy(o models.Role) models.Role { +`) outBuilder.WriteString(` n := models.Role{} n.Model = o.Model n.Name = o.Name @@ -165,7 +175,10 @@ func main() { outBuilder.WriteString(" return n\n}\n\n") // Build compare function - outBuilder.WriteString("func CompareRoles(a, b *models.Role) bool {\n") + outBuilder.WriteString(`// Compare two roles for equality. +// If a permission is nil in one of the roles, that permission is ignored. +func CompareRoles(a, b *models.Role) bool { +`) outBuilder.WriteString(" return ") lastName, lastType := "", "" for valName, valType := range nameTypeMap { diff --git a/cmd/migrate-new/main.go b/cmd/migrate-new/main.go index 23a9759..297a3ed 100644 --- a/cmd/migrate-new/main.go +++ b/cmd/migrate-new/main.go @@ -1,3 +1,7 @@ +/* +migrate-new is a helper script for auto-migrating Linstrom's +database layout into a database defined in the given config +*/ package main import ( diff --git a/cmd/model-gen/main.go b/cmd/model-gen/main.go index 88c181c..adc420f 100644 --- a/cmd/model-gen/main.go +++ b/cmd/model-gen/main.go @@ -1,3 +1,7 @@ +/* +model-gen generates the gorm-gen interface for interacting +with the database. It does not perform migrations on the database. +*/ package main import ( diff --git a/storage-new/migrations.go b/storage-new/migrations.go index 4482e76..260415c 100644 --- a/storage-new/migrations.go +++ b/storage-new/migrations.go @@ -11,6 +11,7 @@ import ( "git.mstar.dev/mstar/linstrom/storage-new/models" ) +// Auto-migrate all tables and types used func Migrate(db *gorm.DB) error { if err := createAccountAuthMethodType(db); err != nil { return other.Error("storage", "Failed to create Auth Method type", err) diff --git a/storage-new/models/0allTypes.go b/storage-new/models/0allTypes.go index 05f1433..3f562fc 100644 --- a/storage-new/models/0allTypes.go +++ b/storage-new/models/0allTypes.go @@ -1,6 +1,6 @@ package models -// Just a list of all models stored in the database +// A list of all models stored in the database var AllTypes = []any{ &Emote{}, &Feed{}, diff --git a/storage-new/models/Emote.go b/storage-new/models/Emote.go index f94ce34..b0142ef 100644 --- a/storage-new/models/Emote.go +++ b/storage-new/models/Emote.go @@ -2,15 +2,17 @@ package models import "gorm.io/gorm" -// An emote is effectively an assignment of a name and server +// Emotes are combinations of a name, the server it originated from +// and the media for it +// +// TODO: Include the case of unicode icons being used as emote type Emote struct { - gorm.Model - // Media used for this emote - Metadata MediaMetadata // `gorm:"foreignKey:MetadataId"` - MetadataId string + gorm.Model // Standard gorm model for id and timestamps + Metadata MediaMetadata // The media used by this emote + MetadataId string // Id of the media information, primarily for gorm // Name of the emote. Also the text for using it in a message (ex. :bob:) Name string - // Server the emote is from - Server RemoteServer // `gorm:"foreignKey:ServerId;references:ID"` - ServerId uint + + Server RemoteServer // Server the emote is from + ServerId uint // Id of the server } diff --git a/storage-new/models/Feed.go b/storage-new/models/Feed.go index 9ad9d1c..6376d6d 100644 --- a/storage-new/models/Feed.go +++ b/storage-new/models/Feed.go @@ -6,26 +6,27 @@ import ( "gorm.io/gorm" ) -// A feed is the initial entry point for all inbound Activitypub events. +// A feed is the initial entry point for inbound Activitypub events. // However, its primary and only user-facing use case is to be a collection // of inbound messages, nothing else. // -// Thus, the flow for inbound events is the following: -// If the event is a note: +// Feeds are split into two groups, default and non-default. +// Default feeds are feeds automatically created for each user, where their normal +// timeline lives in. Additionally, they also relay inbound non-note events, +// such as likes/reactions, boosts or follow requests, to their owner. +// Default feeds also act using their owner's username (others would ge a follow request from +// `username@host`). // -// Add it to the receiving feed. If it's a reply and the feed is a default -// create a notification for the owner -// -// If it's an event: -// -// If the feed is not a default feed for a user, discard the event -// If it is the default feed for a user, create a notification for the owner +// Non-default feeds, in comparison, are explicitly created by users and can be shared +// between them. Thus, they also only accept note events, dropping everything else. +// They also are explicitly labeled as such when issuing follow requests (ex `somename-feed@host`) type Feed struct { gorm.Model + // The name of the feed. Will be equal to the owner username if a default feed Name string - Owner User - OwnerId string - IsDefault bool // Whether the feed is the default one for the user + Owner User // The owner of the feed + OwnerId string // Id of the owner + IsDefault bool // Whether the feed is the default one for the user // If a feed is the default one for a user, use that user's public key. // Otherwise, use its own key PublicKey sql.NullString diff --git a/storage-new/models/MediaMetadata.go b/storage-new/models/MediaMetadata.go index eca359c..a090bb4 100644 --- a/storage-new/models/MediaMetadata.go +++ b/storage-new/models/MediaMetadata.go @@ -6,9 +6,10 @@ import ( "gorm.io/gorm" ) -// Metadata for describing some media -// Media is, at least for Linstrom, always stored on a separate server, -// be that the remote server it originated from or an s3 bucket +// MediaMetadata contains metadata about some media file. +// These files are never stored directly by Linstrom. +// Instead, they are either stored on the remote server they originated from +// or an s3 bucket if uploaded to Linstrom. type MediaMetadata struct { ID string `gorm:"primarykey;type:uuid;default:gen_random_uuid()"` // The unique ID of this media file CreatedAt time.Time // When this entry was created @@ -17,7 +18,7 @@ type MediaMetadata struct { // Soft delete means that this entry still exists in the db, but gorm won't include it anymore unless specifically told to // If not null, this entry is marked as deleted DeletedAt gorm.DeletedAt `gorm:"index"` - OwnedBy string // Account id this media belongs to + OwnedById string // Account id this media belongs to Remote bool // whether the attachment is a remote one // Where the media is stored. Url Location string diff --git a/storage-new/models/Note.go b/storage-new/models/Note.go index bb14c9a..f8c0907 100644 --- a/storage-new/models/Note.go +++ b/storage-new/models/Note.go @@ -6,14 +6,7 @@ import ( "gorm.io/gorm" ) -// User created content, containing some message, maybe attachments, -// tags, pings or other extra things -// -// Data defined in extra structs (links are included at the bottom): -// - Attachments: models.NoteToAttachment -// - Emotes: models.NoteToEmote -// - Pings: models.NoteToPing -// - Tags: models.NoteTag +// A note describes some user generated text content. type Note struct { ID string `gorm:"primarykey;type:uuid;default:gen_random_uuid()"` // Make ID a string (uuid) for other implementations CreatedAt time.Time // When this entry was created @@ -22,9 +15,9 @@ type Note struct { // Soft delete means that this entry still exists in the db, but gorm won't include it anymore unless specifically told to // If not null, this entry is marked as deleted DeletedAt gorm.DeletedAt `gorm:"index"` - Creator User - CreatorId string - Remote bool // Whether the note is originally a remote one and just "cached" + Creator User // The user that created this note + CreatorId string // Id of the creator user + Remote bool // Whether the note is originally a remote one and just "cached" // Raw content of the note. So without additional formatting applied // Might already have formatting applied beforehand from the origin server RawContent string @@ -34,8 +27,8 @@ type Note struct { AccessLevel NoteAccessLevel // Where to send this message to (public, home, followers, dm) OriginServer string // Url of the origin server. Also the primary key for those - AttachmentRelations []NoteToAttachment `gorm:"foreignKey:NoteId"` - EmoteRelations []NoteToEmote `gorm:"foreignKey:NoteId"` - PingRelations []NoteToPing `gorm:"foreignKey:NoteId"` - Tags []NoteTag `gorm:"foreignKey:NoteId"` + AttachmentRelations []NoteToAttachment `gorm:"foreignKey:NoteId"` // Attachments added on to this note + EmoteRelations []NoteToEmote `gorm:"foreignKey:NoteId"` // Emotes used in this note + PingRelations []NoteToPing `gorm:"foreignKey:NoteId"` // Pings/mentions this note performs + Tags []NoteTag `gorm:"foreignKey:NoteId"` // Tags this note contains } diff --git a/storage-new/models/NoteToAttachments.go b/storage-new/models/NoteToAttachments.go index d562ac2..2ca7d84 100644 --- a/storage-new/models/NoteToAttachments.go +++ b/storage-new/models/NoteToAttachments.go @@ -3,8 +3,8 @@ package models // A binding of one note to one media attachment type NoteToAttachment struct { ID uint64 `gorm:"primarykey"` - Note Note + Note Note // The note being bound NoteId string - Attachment MediaMetadata + Attachment MediaMetadata // The media being bound to AttachmentId string } diff --git a/storage-new/models/NoteToEmotes.go b/storage-new/models/NoteToEmotes.go index 4c1af1e..1939ff8 100644 --- a/storage-new/models/NoteToEmotes.go +++ b/storage-new/models/NoteToEmotes.go @@ -3,8 +3,8 @@ package models // A binding of one note to one emote type NoteToEmote struct { ID uint64 `gorm:"primarykey"` - Note Note + Note Note // The note being bound NoteId string - Emote Emote + Emote Emote // The emote being included EmoteId string } diff --git a/storage-new/models/NoteToFeed.go b/storage-new/models/NoteToFeed.go index 7f49b38..2b73384 100644 --- a/storage-new/models/NoteToFeed.go +++ b/storage-new/models/NoteToFeed.go @@ -17,11 +17,13 @@ import "time" // Also need to store the boosts a user has performed somewhere // Maybe adjust Reaction? Though a separate table might be a better option -// Assigns a note to a feed +// Assigns a note to a feed. +// Multiple notes may be assigned to multiple feeds, but each feed may contain +// one note at most once. type NoteToFeed struct { ID uint64 `gorm:"primarykey"` CreatedAt time.Time - Note Note + Note Note // The note being assigned NoteId string // Feed Feed // FeedId uint64 diff --git a/storage-new/models/NoteToPing.go b/storage-new/models/NoteToPing.go index c2eb86a..f30a139 100644 --- a/storage-new/models/NoteToPing.go +++ b/storage-new/models/NoteToPing.go @@ -1,10 +1,12 @@ package models -// A binding of one note to one mentioned account +// A binding of one note to one mentioned account. +// A note may ping multiple users, but each ping wil be stored +// at most once type NoteToPing struct { ID uint64 `gorm:"primarykey"` - Note Note + Note Note // The note mentioning an account NoteId string - PingTarget User + PingTarget User // The account being mentioned PingTargetId string } diff --git a/storage-new/models/NoteToTag.go b/storage-new/models/NoteToTag.go index 7ac4271..f0b419c 100644 --- a/storage-new/models/NoteToTag.go +++ b/storage-new/models/NoteToTag.go @@ -1,9 +1,11 @@ package models -// A binding of one note to one string (hash)tag +// A binding of one note to one string (hash)tag. +// A note may contain multiple tags, but each tag will be stored at most +// once per note type NoteTag struct { ID uint64 `gorm:"primarykey"` - Note Note + Note Note // The note containing a tag NoteId string - Tag string + Tag string // The tag contained } diff --git a/storage-new/models/Reaction.go b/storage-new/models/Reaction.go index aefe3ba..64384f1 100644 --- a/storage-new/models/Reaction.go +++ b/storage-new/models/Reaction.go @@ -2,7 +2,7 @@ package models import "gorm.io/gorm" -// A binding of one note to one account reacting to it with one emote +// A Reaction is a user liking a note using an emote type Reaction struct { gorm.Model Note Note diff --git a/storage-new/models/RemoteServer.go b/storage-new/models/RemoteServer.go index be24b57..457d2c7 100644 --- a/storage-new/models/RemoteServer.go +++ b/storage-new/models/RemoteServer.go @@ -1,6 +1,10 @@ package models -import "gorm.io/gorm" +import ( + "database/sql" + + "gorm.io/gorm" +) // RemoteServer describes an ActivityPub server // This includes self too @@ -9,7 +13,7 @@ type RemoteServer struct { ServerType ServerSoftwareType // What software the server is running. Useful for formatting Domain string // `gorm:"primaryKey"` // Domain the server exists under. Additional primary key Name string // What the server wants to be known as (usually same as url) - Icon MediaMetadata - IconId string // ID of a media file - IsSelf bool // Whether this server is yours truly + Icon *MediaMetadata // The icon used by the server. May be empty + IconId sql.NullString // ID of a media file + IsSelf bool // Whether this server is yours truly } diff --git a/storage-new/models/RemoteServerSoftwareType.go b/storage-new/models/RemoteServerSoftwareType.go index 430b2ed..de63ca3 100644 --- a/storage-new/models/RemoteServerSoftwareType.go +++ b/storage-new/models/RemoteServerSoftwareType.go @@ -8,18 +8,19 @@ import ( type ServerSoftwareType string const ( - // Includes forks like glitch-soc, etc + // Mastodon and forks (glitch-soc, etc) ServerSoftwareMastodon = ServerSoftwareType("Mastodon") - // Includes forks like Ice Shrimp, Sharkey, Cutiekey, etc + // Misskey and forks (Ice Shrimp, Sharkey, Cutiekey, etc) ServerSoftwareMisskey = ServerSoftwareType("Misskey") - // Includes Akkoma + // Plemora and Akkoma ServerSoftwarePlemora = ServerSoftwareType("Plemora") - // Wafrn is a new entry + // Wafrn with no known forks ServerSoftwareWafrn = ServerSoftwareType("Wafrn") - // And of course, yours truly + // Linstrom with no known forks ServerSoftwareLinstrom = ServerSoftwareType("Linstrom") ) +// A list of all known server software systems var AllServerSoftwareTypes = []ServerSoftwareType{ ServerSoftwareMastodon, ServerSoftwareMisskey, diff --git a/storage-new/models/TokenAccess.go b/storage-new/models/TokenAccess.go index dca7aea..ccf9a99 100644 --- a/storage-new/models/TokenAccess.go +++ b/storage-new/models/TokenAccess.go @@ -2,21 +2,19 @@ package models import ( "time" - - "gorm.io/gen" ) +// AccessToken maps a unique token to one account. +// Access to server resource may only happen with a valid access token. +// Access tokens are granted by [auth-new/auth.Authenticator]. +// Each account may have multiple access tokens at any time type AccessToken struct { - User User + User User // The account the token belongs to UserId string - Token string `gorm:"primarykey;type:uuid;default:gen_random_uuid()"` - Name string // Token name will be empty if autogenerated with sucessful login + // The token itself is a uuid value + Token string `gorm:"primarykey;type:uuid;default:gen_random_uuid()"` + Name string // Token name will be empty if autogenerated with sucessful login // Every token expires, even if set to "not expire". If set to "not expire", it just expires // at a point in the future this server should never reach ExpiresAt time.Time `gorm:"default:TIMESTAMP WITH TIME ZONE '9999-12-30 23:59:59+00'"` } - -type IAccessToken interface { - // INSERT INTO @@table (user_id, token, name, {{if expiresAt != nil}}, ) - NewToken(user *User, name string, expiresAt *time.Time) (gen.T, error) -} diff --git a/storage-new/models/TokenLoginProcess.go b/storage-new/models/TokenLoginProcess.go index 645adc5..405fadc 100644 --- a/storage-new/models/TokenLoginProcess.go +++ b/storage-new/models/TokenLoginProcess.go @@ -2,10 +2,10 @@ package models import "time" -// A token used during the login process -// Each user may only have at most one login process active at the same time -// Technically, that could be used to permanently block someone from logging in -// by starting a new login process every time the target has just started one +// A LoginProcessToken contains a token used during the login process. +// Login tokens are used during login to identify and track the login process +// if said process involves multiple steps (2fa and passkey).. +// Each user may have multiple active login processes at the same time. type LoginProcessToken struct { ID uint64 `gorm:"primarykey"` User User diff --git a/storage-new/models/User.go b/storage-new/models/User.go index 9da82a2..9e8bf70 100644 --- a/storage-new/models/User.go +++ b/storage-new/models/User.go @@ -7,11 +7,11 @@ import ( "gorm.io/gorm" ) -// A user describes an account for creating content. +// A user describes an account for creating content and events. // This may be controlled by either a human or some external script // // Data stored externally: -// - Feed connections (which note belongs in the feed of this user, for what reason) +// - Feed connections (which note belongs in the feed of this user, for what reason), see [NoteToFeed] type User struct { // ID is a uuid for this account // diff --git a/storage-new/models/UserAuthenticationMethod.go b/storage-new/models/UserAuthenticationMethod.go index bd185a2..39d82dc 100644 --- a/storage-new/models/UserAuthenticationMethod.go +++ b/storage-new/models/UserAuthenticationMethod.go @@ -6,13 +6,15 @@ import "database/sql/driver" type AuthenticationMethodType string const ( - AuthMethodPassword AuthenticationMethodType = "password" - AuthMethodGAuth AuthenticationMethodType = "g-auth" // Google Authenticator / totp - AuthMethodMail AuthenticationMethodType = "mail" - AuthMethodPasskey2fa AuthenticationMethodType = "passkey-2fa" // Passkey used as 2fa factor + AuthMethodPassword AuthenticationMethodType = "password" // Password based authentication + AuthMethodGAuth AuthenticationMethodType = "g-auth" // Totp based 2nd factor + AuthMethodMail AuthenticationMethodType = "mail" // Mail based 2nd factor. Unused + AuthMethodPasskey2fa AuthenticationMethodType = "passkey-2fa" // Passkey based 2nd factor. Unused AuthMethodPasskey AuthenticationMethodType = "passkey" // Passkey as only auth key ) +// A list of all known authentication methods. +// Known != supported var AllAuthMethods = []AuthenticationMethodType{ AuthMethodPassword, AuthMethodGAuth, AuthMethodMail, AuthMethodPasskey, AuthMethodPasskey2fa, } diff --git a/storage-new/models/UserBeingType.go b/storage-new/models/UserBeingType.go index e2a084a..aefe74b 100644 --- a/storage-new/models/UserBeingType.go +++ b/storage-new/models/UserBeingType.go @@ -10,12 +10,12 @@ import ( type BeingType string const ( - BEING_HUMAN = BeingType("human") - BEING_CAT = BeingType("cat") - BEING_FOX = BeingType("fox") - BEING_DOG = BeingType("dog") - BEING_ROBOT = BeingType("robot") - BEING_DOLL = BeingType("doll") + BEING_HUMAN = BeingType("human") // Is a human + BEING_CAT = BeingType("cat") // Is a cat + BEING_FOX = BeingType("fox") // Is a fox + BEING_DOG = BeingType("dog") // Is a dog + BEING_ROBOT = BeingType("robot") // Is a robot + BEING_DOLL = BeingType("doll") // Is a doll ) var AllBeings = []BeingType{BEING_HUMAN, BEING_CAT, BEING_FOX, BEING_DOG, BEING_ROBOT, BEING_DOLL} diff --git a/storage-new/models/UserBeings.go b/storage-new/models/UserBeings.go index fb0bd59..f4d767f 100644 --- a/storage-new/models/UserBeings.go +++ b/storage-new/models/UserBeings.go @@ -1,7 +1,9 @@ package models -// Defines an account to be a being of the set type -// Multiple are possible for combination +// Defines an user to be a being of the set type +// Each user may have multiple mappings +// +// TODO: Decide whether Being here could be changed to an open string instead type UserToBeing struct { ID uint64 `gorm:"primarykey"` User User diff --git a/storage-new/models/UserInfoField.go b/storage-new/models/UserInfoField.go index 15a5a1f..ae0efe1 100644 --- a/storage-new/models/UserInfoField.go +++ b/storage-new/models/UserInfoField.go @@ -6,7 +6,8 @@ import ( "gorm.io/gorm" ) -// One key-value field attached to an account +// A UserInfoField describes one custom key-value information field. +// Each user may have none, one or more of these fields. // If the value is an uri, the server may attempt to verify ownership // over that uri by checking the content for a `rel="me"` anchor // linking back to the account the field is attached to diff --git a/storage-new/models/UserRelationType.go b/storage-new/models/UserRelationType.go index 4d9b462..673852b 100644 --- a/storage-new/models/UserRelationType.go +++ b/storage-new/models/UserRelationType.go @@ -6,14 +6,14 @@ import "database/sql/driver" type RelationType string const ( - RelationFollow RelationType = "follow" - RelationMute RelationType = "mute" - RelationNoBoosts RelationType = "no-boosts" - RelationBlock RelationType = "block" - RelationPreventFollow RelationType = "prevent-follow" + RelationFollow RelationType = "follow" // X follows Y + RelationMute RelationType = "mute" // X has Y muted (X doesn't see Y, but Y still X) + RelationNoBoosts RelationType = "no-boosts" // X has Ys boosts muted + RelationBlock RelationType = "block" // X has Y blocked (X doesn't see Y and Y doesn't see X) + RelationPreventFollow RelationType = "prevent-follow" // X blocks Y from following (Y can still see X) ) -// var AllBeings = []BeingType{BEING_HUMAN, BEING_CAT, BEING_FOX, BEING_DOG, BEING_ROBOT, BEING_DOLL} +// List of all relation types known var AllRelations = []RelationType{ RelationFollow, RelationMute, diff --git a/storage-new/models/UserRemote.go b/storage-new/models/UserRemote.go index 6112a3a..23f9fa4 100644 --- a/storage-new/models/UserRemote.go +++ b/storage-new/models/UserRemote.go @@ -2,7 +2,7 @@ package models import "gorm.io/gorm" -// "Cached" extra data for accounts, in case they are remote +// UserRemoteLinks contains cached links for remote users type UserRemoteLinks struct { // ---- Section: gorm // Sets this struct up as a value that an Account may have diff --git a/storage-new/models/UserTags.go b/storage-new/models/UserTags.go index da0942a..1860a30 100644 --- a/storage-new/models/UserTags.go +++ b/storage-new/models/UserTags.go @@ -1,7 +1,8 @@ package models // A (hash)tag appearing on an account's profile description -// Accounts may have multiple tags, but each tag may only be stored once at most +// Users may have multiple tags, but each user to tag relation may only +// appear at most once type UserToTag struct { ID uint64 `gorm:"primarykey"` User User diff --git a/storage-new/models/UserToPronoun.go b/storage-new/models/UserToPronoun.go index 09436fc..e99d7e6 100644 --- a/storage-new/models/UserToPronoun.go +++ b/storage-new/models/UserToPronoun.go @@ -1,5 +1,8 @@ package models +// Adds one pronoun to a user. +// Each user may have zero, one or more pronouns +// but each user to pronoun relation may appear at most once type UserToPronoun struct { ID uint64 `gorm:"primarykey"` User User diff --git a/storage-new/models/UserToRole.go b/storage-new/models/UserToRole.go index 68fad40..829f375 100644 --- a/storage-new/models/UserToRole.go +++ b/storage-new/models/UserToRole.go @@ -1,8 +1,9 @@ package models // A link of one account to one role -// There may be multiple of these links per user and per role -// But a role may only be linked at most once to the same user +// Each user may have one or more roles +// (every user has the default role and their personal one) +// but each user to role combination may appear at most once type UserToRole struct { ID uint64 `gorm:"primarykey"` User User diff --git a/storage-new/models/UserToUserRelation.go b/storage-new/models/UserToUserRelation.go index ce0130d..162dcfa 100644 --- a/storage-new/models/UserToUserRelation.go +++ b/storage-new/models/UserToUserRelation.go @@ -5,9 +5,9 @@ package models // each describing a different aspect type UserToUserRelation struct { ID uint64 `gorm:"primarykey"` - User User + User User // The user X described in [RelationType] UserId string - TargetUser User + TargetUser User // The user Y described in [RelationType] TargetUserId string Relation RelationType `gorm:"type:relation_type"` }