diff options
Diffstat (limited to 'internal/gtsmodel')
26 files changed, 474 insertions, 935 deletions
diff --git a/internal/gtsmodel/account.go b/internal/gtsmodel/account.go index a59746be5..67ce05d0b 100644 --- a/internal/gtsmodel/account.go +++ b/internal/gtsmodel/account.go @@ -27,124 +27,73 @@ import ( "time" ) -// Account represents either a local or a remote fediverse account, gotosocial or otherwise (mastodon, pleroma, etc) +// Account represents either a local or a remote fediverse account, gotosocial or otherwise (mastodon, pleroma, etc). type Account struct { - /* - BASIC INFO - */ - - // id of this account in the local database - ID string `bun:"type:CHAR(26),pk,nullzero,notnull,unique"` - // Username of the account, should just be a string of [a-z0-9_]. Can be added to domain to create the full username in the form ``[username]@[domain]`` eg., ``user_96@example.org`` - Username string `bun:",notnull,unique:userdomain,nullzero"` // username and domain should be unique *with* each other - // Domain of the account, will be null if this is a local account, otherwise something like ``example.org`` or ``mastodon.social``. Should be unique with username. - Domain string `bun:",unique:userdomain,nullzero"` // username and domain should be unique *with* each other - - /* - ACCOUNT METADATA - */ - - // ID of the avatar as a media attachment - AvatarMediaAttachmentID string `bun:"type:CHAR(26),nullzero"` - AvatarMediaAttachment *MediaAttachment `bun:"rel:belongs-to"` - // For a non-local account, where can the header be fetched? - AvatarRemoteURL string `bun:",nullzero"` - // ID of the header as a media attachment - HeaderMediaAttachmentID string `bun:"type:CHAR(26),nullzero"` - HeaderMediaAttachment *MediaAttachment `bun:"rel:belongs-to"` - // For a non-local account, where can the header be fetched? - HeaderRemoteURL string `bun:",nullzero"` - // DisplayName for this account. Can be empty, then just the Username will be used for display purposes. - DisplayName string `bun:",nullzero"` - // a key/value map of fields that this account has added to their profile - Fields []Field - // A note that this account has on their profile (ie., the account's bio/description of themselves) - Note string `bun:",nullzero"` - // Is this a memorial account, ie., has the user passed away? - Memorial bool `bun:",nullzero"` - // This account has moved this account id in the database - MovedToAccountID string `bun:"type:CHAR(26),nullzero"` - // When was this account created? - CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // When was this account last updated? - UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // Does this account identify itself as a bot? - Bot bool - // What reason was given for signing up when this account was created? - Reason string `bun:",nullzero"` - - /* - USER AND PRIVACY PREFERENCES - */ - - // Does this account need an approval for new followers? - Locked bool `bun:",default:true"` - // Should this account be shown in the instance's profile directory? - Discoverable bool `bun:",default:false"` - // Default post privacy for this account - Privacy Visibility `bun:",default:'public'"` - // Set posts from this account to sensitive by default? - Sensitive bool `bun:",default:false"` - // What language does this account post in? - Language string `bun:",default:'en'"` - - /* - ACTIVITYPUB THINGS - */ - - // What is the activitypub URI for this account discovered by webfinger? - URI string `bun:",unique,nullzero"` - // At which URL can we see the user account in a web browser? - URL string `bun:",unique,nullzero"` - // Last time this account was located using the webfinger API. - LastWebfingeredAt time.Time `bun:",nullzero"` - // Address of this account's activitypub inbox, for sending activity to - InboxURI string `bun:",unique,nullzero"` - // Address of this account's activitypub outbox - OutboxURI string `bun:",unique,nullzero"` - // URI for getting the following list of this account - FollowingURI string `bun:",unique,nullzero"` - // URI for getting the followers list of this account - FollowersURI string `bun:",unique,nullzero"` - // URL for getting the featured collection list of this account - FeaturedCollectionURI string `bun:",unique,nullzero"` - // What type of activitypub actor is this account? - ActorType string `bun:",nullzero"` - // This account is associated with x account id - AlsoKnownAs string `bun:",nullzero"` - - /* - CRYPTO FIELDS - */ - - // Privatekey for validating activitypub requests, will only be defined for local accounts - PrivateKey *rsa.PrivateKey - // Publickey for encoding activitypub requests, will be defined for both local and remote accounts - PublicKey *rsa.PublicKey - // Web-reachable location of this account's public key - PublicKeyURI string `bun:",nullzero"` - - /* - ADMIN FIELDS - */ - - // When was this account set to have all its media shown as sensitive? - SensitizedAt time.Time `bun:",nullzero"` - // When was this account silenced (eg., statuses only visible to followers, not public)? - SilencedAt time.Time `bun:",nullzero"` - // When was this account suspended (eg., don't allow it to log in/post, don't accept media/posts from this account) - SuspendedAt time.Time `bun:",nullzero"` - // Should we hide this account's collections? - HideCollections bool - // id of the database entry that caused this account to become suspended -- can be an account ID or a domain block ID - SuspensionOrigin string `bun:"type:CHAR(26),nullzero"` + ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated + Username string `validate:"required" bun:",nullzero,notnull,unique:userdomain"` // Username of the account, should just be a string of [a-zA-Z0-9_]. Can be added to domain to create the full username in the form ``[username]@[domain]`` eg., ``user_96@example.org``. Username and domain should be unique *with* each other + Domain string `validate:"omitempty,fqdn" bun:",nullzero,unique:userdomain"` // Domain of the account, will be null if this is a local account, otherwise something like ``example.org`` or ``mastodon.social``. Should be unique with username. + AvatarMediaAttachmentID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // Database ID of the media attachment, if present + AvatarMediaAttachment *MediaAttachment `validate:"-" bun:"rel:belongs-to"` // MediaAttachment corresponding to avatarMediaAttachmentID + AvatarRemoteURL string `validate:"omitempty,url" bun:",nullzero"` // For a non-local account, where can the header be fetched? + HeaderMediaAttachmentID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // Database ID of the media attachment, if present + HeaderMediaAttachment *MediaAttachment `validate:"-" bun:"rel:belongs-to"` // MediaAttachment corresponding to headerMediaAttachmentID + HeaderRemoteURL string `validate:"omitempty,url" bun:",nullzero"` // For a non-local account, where can the header be fetched? + DisplayName string `validate:"-" bun:",nullzero"` // DisplayName for this account. Can be empty, then just the Username will be used for display purposes. + Fields []Field `validate:"-"` // a key/value map of fields that this account has added to their profile + Note string `validate:"-" bun:",nullzero"` // A note that this account has on their profile (ie., the account's bio/description of themselves) + Memorial bool `validate:"-" bun:",nullzero,default:false"` // Is this a memorial account, ie., has the user passed away? + AlsoKnownAs string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // This account is associated with x account id + MovedToAccountID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // This account has moved this account id in the database + Bot bool `validate:"-" bun:",nullzero,default:false"` // Does this account identify itself as a bot? + Reason string `validate:"-" bun:",nullzero"` // What reason was given for signing up when this account was created? + Locked bool `validate:"-" bun:",nullzero,default:true"` // Does this account need an approval for new followers? + Discoverable bool `validate:"-" bun:",nullzero,default:false"` // Should this account be shown in the instance's profile directory? + Privacy Visibility `validate:"required_without=Domain,omitempty,oneof=public unlocked followers_only mutuals_only direct" bun:",nullzero"` // Default post privacy for this account + Sensitive bool `validate:"-" bun:",nullzero,default:false"` // Set posts from this account to sensitive by default? + Language string `validate:"omitempty,bcp47_language_tag" bun:",nullzero,notnull,default:'en'"` // What language does this account post in? + URI string `validate:"required,url" bun:",nullzero,notnull,unique"` // ActivityPub URI for this account. + URL string `validate:"required_without=Domain,omitempty,url" bun:",nullzero,unique"` // Web URL for this account's profile + LastWebfingeredAt time.Time `validate:"required_with=Domain" bun:"type:timestamp,nullzero"` // Last time this account was refreshed/located with webfinger. + InboxURI string `validate:"required_without=Domain,omitempty,url" bun:",nullzero,unique"` // Address of this account's ActivityPub inbox, for sending activity to + OutboxURI string `validate:"required_without=Domain,omitempty,url" bun:",nullzero,unique"` // Address of this account's activitypub outbox + FollowingURI string `validate:"required_without=Domain,omitempty,url" bun:",nullzero,unique"` // URI for getting the following list of this account + FollowersURI string `validate:"required_without=Domain,omitempty,url" bun:",nullzero,unique"` // URI for getting the followers list of this account + FeaturedCollectionURI string `validate:"required_without=Domain,omitempty,url" bun:",nullzero,unique"` // URL for getting the featured collection list of this account + ActorType string `validate:"oneof=Application Group Organization Person Service" bun:",nullzero,notnull"` // What type of activitypub actor is this account? + PrivateKey *rsa.PrivateKey `validate:"required_without=Domain"` // Privatekey for validating activitypub requests, will only be defined for local accounts + PublicKey *rsa.PublicKey `validate:"required"` // Publickey for encoding activitypub requests, will be defined for both local and remote accounts + PublicKeyURI string `validate:"required,url" bun:",nullzero,notnull,unique"` // Web-reachable location of this account's public key + SensitizedAt time.Time `validate:"-" bun:"type:timestamp,nullzero"` // When was this account set to have all its media shown as sensitive? + SilencedAt time.Time `validate:"-" bun:"type:timestamp,nullzero"` // When was this account silenced (eg., statuses only visible to followers, not public)? + SuspendedAt time.Time `validate:"-" bun:"type:timestamp,nullzero"` // When was this account suspended (eg., don't allow it to log in/post, don't accept media/posts from this account) + HideCollections bool `validate:"-" bun:",nullzero,default:false"` // Hide this account's collections + SuspensionOrigin string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // id of the database entry that caused this account to become suspended -- can be an account ID or a domain block ID } // Field represents a key value field on an account, for things like pronouns, website, etc. // VerifiedAt is optional, to be used only if Value is a URL to a webpage that contains the // username of the user. type Field struct { - Name string - Value string - VerifiedAt time.Time `bun:",nullzero"` + Name string `validate:"required"` // Name of this field. + Value string `validate:"required"` // Value of this field. + VerifiedAt time.Time `validate:"-" bun:",nullzero"` // This field was verified at (optional). +} + +// Relationship describes a requester's relationship with another account. +type Relationship struct { + ID string // The account id. + Following bool // Are you following this user? + ShowingReblogs bool // Are you receiving this user's boosts in your home timeline? + Notifying bool // Have you enabled notifications for this user? + FollowedBy bool // Are you followed by this user? + Blocking bool // Are you blocking this user? + BlockedBy bool // Is this user blocking you? + Muting bool // Are you muting this user? + MutingNotifications bool // Are you muting notifications from this user? + Requested bool // Do you have a pending follow request for this user? + DomainBlocking bool // Are you blocking this user's domain? + Endorsed bool // Are you featuring this user on your profile? + Note string // Your note on this account. } diff --git a/internal/gtsmodel/activitystreams.go b/internal/gtsmodel/activitystreams.go deleted file mode 100644 index 5cd92015c..000000000 --- a/internal/gtsmodel/activitystreams.go +++ /dev/null @@ -1,122 +0,0 @@ -/* - GoToSocial - Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -package gtsmodel - -const ( - // ActivityStreamsArticle https://www.w3.org/TR/activitystreams-vocabulary/#dfn-article - ActivityStreamsArticle = "Article" - // ActivityStreamsAudio https://www.w3.org/TR/activitystreams-vocabulary/#dfn-audio - ActivityStreamsAudio = "Audio" - // ActivityStreamsDocument https://www.w3.org/TR/activitystreams-vocabulary/#dfn-document - ActivityStreamsDocument = "Document" - // ActivityStreamsEvent https://www.w3.org/TR/activitystreams-vocabulary/#dfn-event - ActivityStreamsEvent = "Event" - // ActivityStreamsImage https://www.w3.org/TR/activitystreams-vocabulary/#dfn-image - ActivityStreamsImage = "Image" - // ActivityStreamsNote https://www.w3.org/TR/activitystreams-vocabulary/#dfn-note - ActivityStreamsNote = "Note" - // ActivityStreamsPage https://www.w3.org/TR/activitystreams-vocabulary/#dfn-page - ActivityStreamsPage = "Page" - // ActivityStreamsPlace https://www.w3.org/TR/activitystreams-vocabulary/#dfn-place - ActivityStreamsPlace = "Place" - // ActivityStreamsProfile https://www.w3.org/TR/activitystreams-vocabulary/#dfn-profile - ActivityStreamsProfile = "Profile" - // ActivityStreamsRelationship https://www.w3.org/TR/activitystreams-vocabulary/#dfn-relationship - ActivityStreamsRelationship = "Relationship" - // ActivityStreamsTombstone https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tombstone - ActivityStreamsTombstone = "Tombstone" - // ActivityStreamsVideo https://www.w3.org/TR/activitystreams-vocabulary/#dfn-video - ActivityStreamsVideo = "Video" - //ActivityStreamsCollection https://www.w3.org/TR/activitystreams-vocabulary/#dfn-collection - ActivityStreamsCollection = "Collection" - // ActivityStreamsCollectionPage https://www.w3.org/TR/activitystreams-vocabulary/#dfn-collectionpage - ActivityStreamsCollectionPage = "CollectionPage" -) - -const ( - // ActivityStreamsApplication https://www.w3.org/TR/activitystreams-vocabulary/#dfn-application - ActivityStreamsApplication = "Application" - // ActivityStreamsGroup https://www.w3.org/TR/activitystreams-vocabulary/#dfn-group - ActivityStreamsGroup = "Group" - // ActivityStreamsOrganization https://www.w3.org/TR/activitystreams-vocabulary/#dfn-organization - ActivityStreamsOrganization = "Organization" - // ActivityStreamsPerson https://www.w3.org/TR/activitystreams-vocabulary/#dfn-person - ActivityStreamsPerson = "Person" - // ActivityStreamsService https://www.w3.org/TR/activitystreams-vocabulary/#dfn-service - ActivityStreamsService = "Service" -) - -const ( - // ActivityStreamsAccept https://www.w3.org/TR/activitystreams-vocabulary/#dfn-accept - ActivityStreamsAccept = "Accept" - // ActivityStreamsAdd https://www.w3.org/TR/activitystreams-vocabulary/#dfn-add - ActivityStreamsAdd = "Add" - // ActivityStreamsAnnounce https://www.w3.org/TR/activitystreams-vocabulary/#dfn-announce - ActivityStreamsAnnounce = "Announce" - // ActivityStreamsArrive https://www.w3.org/TR/activitystreams-vocabulary/#dfn-arrive - ActivityStreamsArrive = "Arrive" - // ActivityStreamsBlock https://www.w3.org/TR/activitystreams-vocabulary/#dfn-block - ActivityStreamsBlock = "Block" - // ActivityStreamsCreate https://www.w3.org/TR/activitystreams-vocabulary/#dfn-create - ActivityStreamsCreate = "Create" - // ActivityStreamsDelete https://www.w3.org/TR/activitystreams-vocabulary/#dfn-delete - ActivityStreamsDelete = "Delete" - // ActivityStreamsDislike https://www.w3.org/TR/activitystreams-vocabulary/#dfn-dislike - ActivityStreamsDislike = "Dislike" - // ActivityStreamsFlag https://www.w3.org/TR/activitystreams-vocabulary/#dfn-flag - ActivityStreamsFlag = "Flag" - // ActivityStreamsFollow https://www.w3.org/TR/activitystreams-vocabulary/#dfn-follow - ActivityStreamsFollow = "Follow" - // ActivityStreamsIgnore https://www.w3.org/TR/activitystreams-vocabulary/#dfn-ignore - ActivityStreamsIgnore = "Ignore" - // ActivityStreamsInvite https://www.w3.org/TR/activitystreams-vocabulary/#dfn-invite - ActivityStreamsInvite = "Invite" - // ActivityStreamsJoin https://www.w3.org/TR/activitystreams-vocabulary/#dfn-join - ActivityStreamsJoin = "Join" - // ActivityStreamsLeave https://www.w3.org/TR/activitystreams-vocabulary/#dfn-leave - ActivityStreamsLeave = "Leave" - // ActivityStreamsLike https://www.w3.org/TR/activitystreams-vocabulary/#dfn-like - ActivityStreamsLike = "Like" - // ActivityStreamsListen https://www.w3.org/TR/activitystreams-vocabulary/#dfn-listen - ActivityStreamsListen = "Listen" - // ActivityStreamsMove https://www.w3.org/TR/activitystreams-vocabulary/#dfn-move - ActivityStreamsMove = "Move" - // ActivityStreamsOffer https://www.w3.org/TR/activitystreams-vocabulary/#dfn-offer - ActivityStreamsOffer = "Offer" - // ActivityStreamsQuestion https://www.w3.org/TR/activitystreams-vocabulary/#dfn-question - ActivityStreamsQuestion = "Question" - // ActivityStreamsReject https://www.w3.org/TR/activitystreams-vocabulary/#dfn-reject - ActivityStreamsReject = "Reject" - // ActivityStreamsRead https://www.w3.org/TR/activitystreams-vocabulary/#dfn-read - ActivityStreamsRead = "Read" - // ActivityStreamsRemove https://www.w3.org/TR/activitystreams-vocabulary/#dfn-remove - ActivityStreamsRemove = "Remove" - // ActivityStreamsTentativeReject https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tentativereject - ActivityStreamsTentativeReject = "TentativeReject" - // ActivityStreamsTentativeAccept https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tentativeaccept - ActivityStreamsTentativeAccept = "TentativeAccept" - // ActivityStreamsTravel https://www.w3.org/TR/activitystreams-vocabulary/#dfn-travel - ActivityStreamsTravel = "Travel" - // ActivityStreamsUndo https://www.w3.org/TR/activitystreams-vocabulary/#dfn-undo - ActivityStreamsUndo = "Undo" - // ActivityStreamsUpdate https://www.w3.org/TR/activitystreams-vocabulary/#dfn-update - ActivityStreamsUpdate = "Update" - // ActivityStreamsView https://www.w3.org/TR/activitystreams-vocabulary/#dfn-view - ActivityStreamsView = "View" -) diff --git a/internal/gtsmodel/application.go b/internal/gtsmodel/application.go index 12a21d298..7ec71ec2e 100644 --- a/internal/gtsmodel/application.go +++ b/internal/gtsmodel/application.go @@ -18,23 +18,18 @@ package gtsmodel +import "time" + // Application represents an application that can perform actions on behalf of a user. // It is used to authorize tokens etc, and is associated with an oauth client id in the database. type Application struct { - // id of this application in the db - ID string `bun:"type:CHAR(26),pk,notnull"` - // name of the application given when it was created (eg., 'tusky') - Name string `bun:",nullzero"` - // website for the application given when it was created (eg., 'https://tusky.app') - Website string `bun:",nullzero"` - // redirect uri requested by the application for oauth2 flow - RedirectURI string `bun:",nullzero"` - // id of the associated oauth client entity in the db - ClientID string `bun:"type:CHAR(26),nullzero"` - // secret of the associated oauth client entity in the db - ClientSecret string `bun:",nullzero"` - // scopes requested when this app was created - Scopes string `bun:",nullzero"` - // a vapid key generated for this app when it was created - VapidKey string `bun:",nullzero"` + ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated + Name string `validate:"required" bun:",nullzero,notnull"` // name of the application given when it was created (eg., 'tusky') + Website string `validate:"omitempty,url" bun:",nullzero"` // website for the application given when it was created (eg., 'https://tusky.app') + RedirectURI string `validate:"required,uri" bun:",nullzero,notnull"` // redirect uri requested by the application for oauth2 flow + ClientID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // id of the associated oauth client entity in the db + ClientSecret string `validate:"required,uuid" bun:",nullzero,notnull"` // secret of the associated oauth client entity in the db + Scopes string `validate:"required" bun:",nullzero,notnull"` // scopes requested when this app was created } diff --git a/internal/gtsmodel/block.go b/internal/gtsmodel/block.go index 0c762837d..2cc089e6b 100644 --- a/internal/gtsmodel/block.go +++ b/internal/gtsmodel/block.go @@ -1,21 +1,33 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + package gtsmodel import "time" // Block refers to the blocking of one account by another. type Block struct { - // id of this block in the database - ID string `bun:"type:CHAR(26),pk,notnull"` - // When was this block created - CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // When was this block updated - UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // Who created this block? - AccountID string `bun:"type:CHAR(26),notnull"` - Account *Account `bun:"rel:belongs-to"` - // Who is targeted by this block? - TargetAccountID string `bun:"type:CHAR(26),notnull"` - TargetAccount *Account `bun:"rel:belongs-to"` - // Activitypub URI for this block - URI string `bun:",notnull"` + ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated + URI string `validate:"required,url" bun:",notnull,nullzero,unique"` // ActivityPub uri of this block. + AccountID string `validate:"required,ulid" bun:"type:CHAR(26),unique:blocksrctarget,notnull"` // Who does this block originate from? + Account *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to accountID + TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),unique:blocksrctarget,notnull"` // Who is the target of this block ? + TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to targetAccountID } diff --git a/internal/gtsmodel/client.go b/internal/gtsmodel/client.go new file mode 100644 index 000000000..e924bd190 --- /dev/null +++ b/internal/gtsmodel/client.go @@ -0,0 +1,31 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package gtsmodel + +import "time" + +// Client is a wrapper for OAuth client details. +type Client struct { + ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated + Secret string `validate:"required,uuid" bun:",nullzero,notnull"` // secret generated when client was created + Domain string `validate:"required,uri" bun:",nullzero,notnull"` // domain requested for client + UserID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // id of the user that this client acts on behalf of +} diff --git a/internal/gtsmodel/domainblock.go b/internal/gtsmodel/domainblock.go index 784e665a5..4c72b842a 100644 --- a/internal/gtsmodel/domainblock.go +++ b/internal/gtsmodel/domainblock.go @@ -22,23 +22,14 @@ import "time" // DomainBlock represents a federation block against a particular domain type DomainBlock struct { - // ID of this block in the database - ID string `bun:"type:CHAR(26),pk,notnull,unique"` - // blocked domain - Domain string `bun:",pk,notnull,unique"` - // When was this block created - CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // When was this block updated - UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // Account ID of the creator of this block - CreatedByAccountID string `bun:"type:CHAR(26),notnull"` - CreatedByAccount *Account `bun:"rel:belongs-to"` - // Private comment on this block, viewable to admins - PrivateComment string `bun:",nullzero"` - // Public comment on this block, viewable (optionally) by everyone - PublicComment string `bun:",nullzero"` - // whether the domain name should appear obfuscated when displaying it publicly - Obfuscate bool - // if this block was created through a subscription, what's the subscription ID? - SubscriptionID string `bun:"type:CHAR(26),nullzero"` + ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated + Domain string `validate:"required,fqdn" bun:",nullzero,notnull"` // domain to block. Eg. 'whatever.com' + CreatedByAccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // Account ID of the creator of this block + CreatedByAccount *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to createdByAccountID + PrivateComment string `validate:"-" bun:",nullzero"` // Private comment on this block, viewable to admins + PublicComment string `validate:"-" bun:",nullzero"` // Public comment on this block, viewable (optionally) by everyone + Obfuscate bool `validate:"-" bun:",nullzero,default:false"` // whether the domain name should appear obfuscated when displaying it publicly + SubscriptionID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // if this block was created through a subscription, what's the subscription ID? } diff --git a/internal/gtsmodel/emaildomainblock.go b/internal/gtsmodel/emaildomainblock.go index 1919172fa..2118068f2 100644 --- a/internal/gtsmodel/emaildomainblock.go +++ b/internal/gtsmodel/emaildomainblock.go @@ -22,15 +22,10 @@ import "time" // EmailDomainBlock represents a domain that the server should automatically reject sign-up requests from. type EmailDomainBlock struct { - // ID of this block in the database - ID string `bun:"type:CHAR(26),pk,notnull,unique"` - // Email domain to block. Eg. 'gmail.com' or 'hotmail.com' - Domain string `bun:",notnull"` - // When was this block created - CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // When was this block updated - UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // Account ID of the creator of this block - CreatedByAccountID string `bun:"type:CHAR(26),notnull"` - CreatedByAccount *Account `bun:"rel:belongs-to"` + ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated + Domain string `validate:"required,fqdn" bun:",nullzero,notnull"` // Email domain to block. Eg. 'gmail.com' or 'hotmail.com' + CreatedByAccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // Account ID of the creator of this block + CreatedByAccount *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to createdByAccountID } diff --git a/internal/gtsmodel/emoji.go b/internal/gtsmodel/emoji.go index 9723f0790..93c43c0f7 100644 --- a/internal/gtsmodel/emoji.go +++ b/internal/gtsmodel/emoji.go @@ -22,56 +22,24 @@ import "time" // Emoji represents a custom emoji that's been uploaded through the admin UI, and is useable by instance denizens. type Emoji struct { - // database ID of this emoji - ID string `bun:"type:CHAR(26),pk,notnull"` - // String shortcode for this emoji -- the part that's between colons. This should be lowercase a-z_ - // eg., 'blob_hug' 'purple_heart' Must be unique with domain. - Shortcode string `bun:",notnull,unique:shortcodedomain"` - // Origin domain of this emoji, eg 'example.org', 'queer.party'. empty string for local emojis. - Domain string `bun:",notnull,default:'',unique:shortcodedomain"` - // When was this emoji created. Must be unique with shortcode. - CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // When was this emoji updated - UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // Where can this emoji be retrieved remotely? Null for local emojis. - // For remote emojis, it'll be something like: - // https://hackers.town/system/custom_emojis/images/000/049/842/original/1b74481204feabfd.png - ImageRemoteURL string `bun:",nullzero"` - // Where can a static / non-animated version of this emoji be retrieved remotely? Null for local emojis. - // For remote emojis, it'll be something like: - // https://hackers.town/system/custom_emojis/images/000/049/842/static/1b74481204feabfd.png - ImageStaticRemoteURL string `bun:",nullzero"` - // Where can this emoji be retrieved from the local server? Null for remote emojis. - // Assuming our server is hosted at 'example.org', this will be something like: - // 'https://example.org/fileserver/6339820e-ef65-4166-a262-5a9f46adb1a7/emoji/original/bfa6c9c5-6c25-4ea4-98b4-d78b8126fb52.png' - ImageURL string `bun:",nullzero"` - // Where can a static version of this emoji be retrieved from the local server? Null for remote emojis. - // Assuming our server is hosted at 'example.org', this will be something like: - // 'https://example.org/fileserver/6339820e-ef65-4166-a262-5a9f46adb1a7/emoji/small/bfa6c9c5-6c25-4ea4-98b4-d78b8126fb52.png' - ImageStaticURL string `bun:",nullzero"` - // Path of the emoji image in the server storage system. Will be something like: - // '/gotosocial/storage/6339820e-ef65-4166-a262-5a9f46adb1a7/emoji/original/bfa6c9c5-6c25-4ea4-98b4-d78b8126fb52.png' - ImagePath string `bun:",notnull"` - // Path of a static version of the emoji image in the server storage system. Will be something like: - // '/gotosocial/storage/6339820e-ef65-4166-a262-5a9f46adb1a7/emoji/small/bfa6c9c5-6c25-4ea4-98b4-d78b8126fb52.png' - ImageStaticPath string `bun:",notnull"` - // MIME content type of the emoji image - // Probably "image/png" - ImageContentType string `bun:",notnull"` - // MIME content type of the static version of the emoji image. - ImageStaticContentType string `bun:",notnull"` - // Size of the emoji image file in bytes, for serving purposes. - ImageFileSize int `bun:",notnull"` - // Size of the static version of the emoji image file in bytes, for serving purposes. - ImageStaticFileSize int `bun:",notnull"` - // When was the emoji image last updated? - ImageUpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // Has a moderation action disabled this emoji from being shown? - Disabled bool `bun:",notnull,default:false"` - // ActivityStreams uri of this emoji. Something like 'https://example.org/emojis/1234' - URI string `bun:",notnull,unique"` - // Is this emoji visible in the admin emoji picker? - VisibleInPicker bool `bun:",notnull,default:true"` - // In which emoji category is this emoji visible? - CategoryID string `bun:"type:CHAR(26),nullzero"` + ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated + Shortcode string `validate:"required" bun:",notnull,unique:shortcodedomain"` // String shortcode for this emoji -- the part that's between colons. This should be lowercase a-z_ eg., 'blob_hug' 'purple_heart' Must be unique with domain. + Domain string `validate:"omitempty,fqdn" bun:",notnull,default:'',unique:shortcodedomain"` // Origin domain of this emoji, eg 'example.org', 'queer.party'. empty string for local emojis. + ImageRemoteURL string `validate:"required_without=ImageURL,omitempty,url" bun:",nullzero"` // Where can this emoji be retrieved remotely? Null for local emojis. + ImageStaticRemoteURL string `validate:"required_without=ImageStaticURL,omitempty,url" bun:",nullzero"` // Where can a static / non-animated version of this emoji be retrieved remotely? Null for local emojis. + ImageURL string `validate:"required_without=ImageRemoteURL,required_without=Domain,omitempty,url" bun:",nullzero"` // Where can this emoji be retrieved from the local server? Null for remote emojis. + ImageStaticURL string `validate:"required_without=ImageStaticRemoteURL,required_without=Domain,omitempty,url" bun:",nullzero"` // Where can a static version of this emoji be retrieved from the local server? Null for remote emojis. + ImagePath string `validate:"required,file" bun:",nullzero,notnull"` // Path of the emoji image in the server storage system. + ImageStaticPath string `validate:"required,file" bun:",nullzero,notnull"` // Path of a static version of the emoji image in the server storage system + ImageContentType string `validate:"required" bun:",nullzero,notnull"` // MIME content type of the emoji image + ImageStaticContentType string `validate:"required" bun:",nullzero,notnull"` // MIME content type of the static version of the emoji image. + ImageFileSize int `validate:"required,min=1" bun:",nullzero,notnull"` // Size of the emoji image file in bytes, for serving purposes. + ImageStaticFileSize int `validate:"required,min=1" bun:",nullzero,notnull"` // Size of the static version of the emoji image file in bytes, for serving purposes. + ImageUpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // When was the emoji image last updated? + Disabled bool `validate:"-" bun:",notnull,default:false"` // Has a moderation action disabled this emoji from being shown? + URI string `validate:"url" bun:",nullzero,notnull,unique"` // ActivityPub uri of this emoji. Something like 'https://example.org/emojis/1234' + VisibleInPicker bool `validate:"-" bun:",notnull,default:true"` // Is this emoji visible in the admin emoji picker? + CategoryID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // In which emoji category is this emoji visible? } diff --git a/internal/gtsmodel/follow.go b/internal/gtsmodel/follow.go index 1e1095af9..8c4617f48 100644 --- a/internal/gtsmodel/follow.go +++ b/internal/gtsmodel/follow.go @@ -22,22 +22,14 @@ import "time" // Follow represents one account following another, and the metadata around that follow. type Follow struct { - // id of this follow in the database - ID string `bun:"type:CHAR(26),pk,notnull,unique"` - // When was this follow created? - CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // When was this follow last updated? - UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // Who does this follow belong to? - AccountID string `bun:"type:CHAR(26),unique:srctarget,notnull"` - Account *Account `bun:"rel:belongs-to"` - // Who does AccountID follow? - TargetAccountID string `bun:"type:CHAR(26),unique:srctarget,notnull"` - TargetAccount *Account `bun:"rel:belongs-to"` - // Does this follow also want to see reblogs and not just posts? - ShowReblogs bool `bun:"default:true"` - // What is the activitypub URI of this follow? - URI string `bun:",unique,nullzero"` - // does the following account want to be notified when the followed account posts? - Notify bool + ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated + URI string `validate:"required,url" bun:",notnull,nullzero,unique"` // ActivityPub uri of this follow. + AccountID string `validate:"required,ulid" bun:"type:CHAR(26),unique:srctarget,notnull"` // Who does this follow originate from? + Account *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to accountID + TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),unique:srctarget,notnull"` // Who is the target of this follow ? + TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to targetAccountID + ShowReblogs bool `validate:"-" bun:",nullzero,default:true"` // Does this follow also want to see reblogs and not just posts? + Notify bool `validate:"-" bun:",nullzero,default:false"` // does the following account want to be notified when the followed account posts? } diff --git a/internal/gtsmodel/followrequest.go b/internal/gtsmodel/followrequest.go index 5a6cb5e02..9ffdb5938 100644 --- a/internal/gtsmodel/followrequest.go +++ b/internal/gtsmodel/followrequest.go @@ -22,22 +22,14 @@ import "time" // FollowRequest represents one account requesting to follow another, and the metadata around that request. type FollowRequest struct { - // id of this follow request in the database - ID string `bun:"type:CHAR(26),pk,notnull,unique"` - // When was this follow request created? - CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // When was this follow request last updated? - UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // Who does this follow request originate from? - AccountID string `bun:"type:CHAR(26),unique:frsrctarget,notnull"` - Account *Account `bun:"rel:belongs-to"` - // Who is the target of this follow request? - TargetAccountID string `bun:"type:CHAR(26),unique:frsrctarget,notnull"` - TargetAccount *Account `bun:"rel:belongs-to"` - // Does this follow also want to see reblogs and not just posts? - ShowReblogs bool `bun:"default:true"` - // What is the activitypub URI of this follow request? - URI string `bun:",unique,nullzero"` - // does the following account want to be notified when the followed account posts? - Notify bool + ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated + URI string `validate:"required,url" bun:",notnull,nullzero,unique"` // ActivityPub uri of this follow (request). + AccountID string `validate:"required,ulid" bun:"type:CHAR(26),unique:frsrctarget,notnull"` // Who does this follow request originate from? + Account *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to accountID + TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),unique:frsrctarget,notnull"` // Who is the target of this follow request? + TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to targetAccountID + ShowReblogs bool `validate:"-" bun:",nullzero,default:true"` // Does this follow also want to see reblogs and not just posts? + Notify bool `validate:"-" bun:",nullzero,default:false"` // does the following account want to be notified when the followed account posts? } diff --git a/internal/gtsmodel/instance.go b/internal/gtsmodel/instance.go index ca2857b95..a7cc8a034 100644 --- a/internal/gtsmodel/instance.go +++ b/internal/gtsmodel/instance.go @@ -1,41 +1,43 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + package gtsmodel import "time" // Instance represents a federated instance, either local or remote. type Instance struct { - // ID of this instance in the database - ID string `bun:"type:CHAR(26),pk,notnull,unique"` - // Instance domain eg example.org - Domain string `bun:",pk,notnull,unique"` - // Title of this instance as it would like to be displayed. - Title string `bun:",nullzero"` - // base URI of this instance eg https://example.org - URI string `bun:",notnull,unique"` - // When was this instance created in the db? - CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // When was this instance last updated in the db? - UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // When was this instance suspended, if at all? - SuspendedAt time.Time `bun:",nullzero"` - // ID of any existing domain block for this instance in the database - DomainBlockID string `bun:"type:CHAR(26),nullzero"` - DomainBlock *DomainBlock `bun:"rel:belongs-to"` - // Short description of this instance - ShortDescription string `bun:",nullzero"` - // Longer description of this instance - Description string `bun:",nullzero"` - // Terms and conditions of this instance - Terms string `bun:",nullzero"` - // Contact email address for this instance - ContactEmail string `bun:",nullzero"` - // Username of the contact account for this instance - ContactAccountUsername string `bun:",nullzero"` - // Contact account ID in the database for this instance - ContactAccountID string `bun:"type:CHAR(26),nullzero"` - ContactAccount *Account `bun:"rel:belongs-to"` - // Reputation score of this instance - Reputation int64 `bun:",notnull,default:0"` - // Version of the software used on this instance - Version string `bun:",nullzero"` + ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated + Domain string `validate:"required,fqdn" bun:",nullzero,notnull,unique"` // Instance domain eg example.org + Title string `validate:"-" bun:",nullzero"` // Title of this instance as it would like to be displayed. + URI string `validate:"required,url" bun:",nullzero,notnull,unique"` // base URI of this instance eg https://example.org + SuspendedAt time.Time `validate:"-" bun:"type:timestamp,nullzero"` // When was this instance suspended, if at all? + DomainBlockID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // ID of any existing domain block for this instance in the database + DomainBlock *DomainBlock `validate:"-" bun:"rel:belongs-to"` // Domain block corresponding to domainBlockID + ShortDescription string `validate:"-" bun:",nullzero"` // Short description of this instance + Description string `validate:"-" bun:",nullzero"` // Longer description of this instance + Terms string `validate:"-" bun:",nullzero"` // Terms and conditions of this instance + ContactEmail string `validate:"omitempty,email" bun:",nullzero"` // Contact email address for this instance + ContactAccountUsername string `validate:"required_with=ContactAccountID" bun:",nullzero"` // Username of the contact account for this instance + ContactAccountID string `validate:"required_with=ContactAccountUsername,omitempty,ulid" bun:"type:CHAR(26),nullzero"` // Contact account ID in the database for this instance + ContactAccount *Account `validate:"-" bun:"rel:belongs-to"` // account corresponding to contactAccountID + Reputation int64 `validate:"-" bun:",notnull,default:0"` // Reputation score of this instance + Version string `validate:"-" bun:",nullzero"` // Version of the software used on this instance } diff --git a/internal/gtsmodel/mediaattachment.go b/internal/gtsmodel/mediaattachment.go index 2acf6a6fc..59cf8aac1 100644 --- a/internal/gtsmodel/mediaattachment.go +++ b/internal/gtsmodel/mediaattachment.go @@ -25,127 +25,93 @@ import ( // MediaAttachment represents a user-uploaded media attachment: an image/video/audio/gif that is // somewhere in storage and that can be retrieved and served by the router. type MediaAttachment struct { - // ID of the attachment in the database - ID string `bun:"type:CHAR(26),pk,notnull,unique"` - // ID of the status to which this is attached - StatusID string `bun:"type:CHAR(26),nullzero"` - // Where can the attachment be retrieved on *this* server - URL string `bun:",nullzero"` - // Where can the attachment be retrieved on a remote server (empty for local media) - RemoteURL string `bun:",nullzero"` - // When was the attachment created - CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // When was the attachment last updated - UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // Type of file (image/gif/audio/video) - Type FileType `bun:",notnull"` - // Metadata about the file - FileMeta FileMeta - // To which account does this attachment belong - AccountID string `bun:"type:CHAR(26),notnull"` - Account *Account `bun:"rel:has-one"` - // Description of the attachment (for screenreaders) - Description string `bun:",nullzero"` - // To which scheduled status does this attachment belong - ScheduledStatusID string `bun:"type:CHAR(26),nullzero"` - // What is the generated blurhash of this attachment - Blurhash string `bun:",nullzero"` - // What is the processing status of this attachment - Processing ProcessingStatus - // metadata for the whole file - File File - // small image thumbnail derived from a larger image, video, or audio file. - Thumbnail Thumbnail - // Is this attachment being used as an avatar? - Avatar bool - // Is this attachment being used as a header? - Header bool + ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated + StatusID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // ID of the status to which this is attached + URL string `validate:"required_without=RemoteURL,omitempty,url" bun:",nullzero"` // Where can the attachment be retrieved on *this* server + RemoteURL string `validate:"required_without=URL,omitempty,url" bun:",nullzero"` // Where can the attachment be retrieved on a remote server (empty for local media) + Type FileType `validate:"oneof=Image Gif Audio Video Unknown" bun:",notnull"` // Type of file (image/gif/audio/video) + FileMeta FileMeta `validate:"required" bun:",nullzero,notnull"` // Metadata about the file + AccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // To which account does this attachment belong + Account *Account `validate:"-" bun:"rel:has-one"` // Account corresponding to accountID + Description string `validate:"-" bun:",nullzero"` // Description of the attachment (for screenreaders) + ScheduledStatusID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // To which scheduled status does this attachment belong + Blurhash string `validate:"required_if=Type Image,required_if=Type Gif,required_if=Type Video" bun:",nullzero"` // What is the generated blurhash of this attachment + Processing ProcessingStatus `validate:"oneof=0 1 2 666" bun:",notnull,default:2"` // What is the processing status of this attachment + File File `validate:"required" bun:",notnull,nullzero"` // metadata for the whole file + Thumbnail Thumbnail `validate:"required" bun:",notnull,nullzero"` // small image thumbnail derived from a larger image, video, or audio file. + Avatar bool `validate:"-" bun:",notnull,default:false"` // Is this attachment being used as an avatar? + Header bool `validate:"-" bun:",notnull,default:false"` // Is this attachment being used as a header? } // File refers to the metadata for the whole file type File struct { - // What is the path of the file in storage. - Path string `bun:",nullzero"` - // What is the MIME content type of the file. - ContentType string `bun:",nullzero"` - // What is the size of the file in bytes. - FileSize int - // When was the file last updated. - UpdatedAt time.Time `bun:",notnull,default:current_timestamp"` + Path string `validate:"required,file" bun:",nullzero,notnull"` // Path of the file in storage. + ContentType string `validate:"required" bun:",nullzero,notnull"` // MIME content type of the file. + FileSize int `validate:"required" bun:",nullzero,notnull"` // File size in bytes + UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // When was the file last updated. } // Thumbnail refers to a small image thumbnail derived from a larger image, video, or audio file. type Thumbnail struct { - // What is the path of the file in storage - Path string `bun:",nullzero"` - // What is the MIME content type of the file. - ContentType string `bun:",nullzero"` - // What is the size of the file in bytes - FileSize int - // When was the file last updated - UpdatedAt time.Time `bun:",notnull,default:current_timestamp"` - // What is the URL of the thumbnail on the local server - URL string `bun:",nullzero"` - // What is the remote URL of the thumbnail (empty for local media) - RemoteURL string `bun:",nullzero"` + Path string `validate:"required,file" bun:",nullzero,notnull"` // Path of the file in storage. + ContentType string `validate:"required" bun:",nullzero,notnull"` // MIME content type of the file. + FileSize int `validate:"required" bun:",nullzero,notnull"` // File size in bytes + UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // When was the file last updated. + URL string `validate:"required_without=RemoteURL,omitempty,url" bun:",nullzero"` // What is the URL of the thumbnail on the local server + RemoteURL string `validate:"required_without=URL,omitempty,url" bun:",nullzero"` // What is the remote URL of the thumbnail (empty for local media) } // ProcessingStatus refers to how far along in the processing stage the attachment is. type ProcessingStatus int +// MediaAttachment processing states. const ( - // ProcessingStatusReceived indicates the attachment has been received and is awaiting processing. No thumbnail available yet. - ProcessingStatusReceived ProcessingStatus = 0 - // ProcessingStatusProcessing indicates the attachment is currently being processed. Thumbnail is available but full media is not. - ProcessingStatusProcessing ProcessingStatus = 1 - // ProcessingStatusProcessed indicates the attachment has been fully processed and is ready to be served. - ProcessingStatusProcessed ProcessingStatus = 2 - // ProcessingStatusError indicates something went wrong processing the attachment and it won't be tried again--these can be deleted. - ProcessingStatusError ProcessingStatus = 666 + ProcessingStatusReceived ProcessingStatus = 0 // ProcessingStatusReceived indicates the attachment has been received and is awaiting processing. No thumbnail available yet. + ProcessingStatusProcessing ProcessingStatus = 1 // ProcessingStatusProcessing indicates the attachment is currently being processed. Thumbnail is available but full media is not. + ProcessingStatusProcessed ProcessingStatus = 2 // ProcessingStatusProcessed indicates the attachment has been fully processed and is ready to be served. + ProcessingStatusError ProcessingStatus = 666 // ProcessingStatusError indicates something went wrong processing the attachment and it won't be tried again--these can be deleted. ) // FileType refers to the file type of the media attaachment. type FileType string +// MediaAttachment file types. const ( - // FileTypeImage is for jpegs and pngs - FileTypeImage FileType = "Image" - // FileTypeGif is for native gifs and soundless videos that have been converted to gifs - FileTypeGif FileType = "Gif" - // FileTypeAudio is for audio-only files (no video) - FileTypeAudio FileType = "Audio" - // FileTypeVideo is for files with audio + visual - FileTypeVideo FileType = "Video" - // FileTypeUnknown is for unknown file types (surprise surprise!) - FileTypeUnknown FileType = "Unknown" + FileTypeImage FileType = "Image" // FileTypeImage is for jpegs and pngs + FileTypeGif FileType = "Gif" // FileTypeGif is for native gifs and soundless videos that have been converted to gifs + FileTypeAudio FileType = "Audio" // FileTypeAudio is for audio-only files (no video) + FileTypeVideo FileType = "Video" // FileTypeVideo is for files with audio + visual + FileTypeUnknown FileType = "Unknown" // FileTypeUnknown is for unknown file types (surprise surprise!) ) // FileMeta describes metadata about the actual contents of the file. type FileMeta struct { - Original Original + Original Original `validate:"required"` Small Small Focus Focus } // Small can be used for a thumbnail of any media type type Small struct { - Width int - Height int - Size int - Aspect float64 + Width int `validate:"required_with=Height Size Aspect"` // width in pixels + Height int `validate:"required_with=Width Size Aspect"` // height in pixels + Size int `validate:"required_with=Width Height Aspect"` // size in pixels (width * height) + Aspect float64 `validate:"required_with=Widhth Height Size"` // aspect ratio (width / height) } // Original can be used for original metadata for any media type type Original struct { - Width int - Height int - Size int - Aspect float64 + Width int `validate:"required_with=Height Size Aspect"` // width in pixels + Height int `validate:"required_with=Width Size Aspect"` // height in pixels + Size int `validate:"required_with=Width Height Aspect"` // size in pixels (width * height) + Aspect float64 `validate:"required_with=Widhth Height Size"` // aspect ratio (width / height) } // Focus describes the 'center' of the image for display purposes. // X and Y should each be between -1 and 1 type Focus struct { - X float32 - Y float32 + X float32 `validate:"omitempty,max=1,min=-1"` + Y float32 `validate:"omitempty,max=1,min=-1"` } diff --git a/internal/gtsmodel/mention.go b/internal/gtsmodel/mention.go index 79556500f..492740d77 100644 --- a/internal/gtsmodel/mention.go +++ b/internal/gtsmodel/mention.go @@ -22,25 +22,17 @@ import "time" // Mention refers to the 'tagging' or 'mention' of a user within a status. type Mention struct { - // ID of this mention in the database - ID string `bun:"type:CHAR(26),pk,notnull,unique"` - // ID of the status this mention originates from - StatusID string `bun:"type:CHAR(26),notnull,nullzero"` - Status *Status `bun:"rel:belongs-to"` - // When was this mention created? - CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // When was this mention last updated? - UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // What's the internal account ID of the originator of the mention? - OriginAccountID string `bun:"type:CHAR(26),notnull,nullzero"` - OriginAccount *Account `bun:"rel:belongs-to"` - // What's the AP URI of the originator of the mention? - OriginAccountURI string `bun:",notnull"` - // What's the internal account ID of the mention target? - TargetAccountID string `bun:"type:CHAR(26),notnull,nullzero"` - TargetAccount *Account `bun:"rel:belongs-to"` - // Prevent this mention from generating a notification? - Silent bool + ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated + StatusID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // ID of the status this mention originates from + Status *Status `validate:"-" bun:"rel:belongs-to"` // status referred to by statusID + OriginAccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // ID of the mention creator account + OriginAccountURI string `validate:"url" bun:",nullzero,notnull"` // ActivityPub URI of the originator/creator of the mention + OriginAccount *Account `validate:"-" bun:"rel:belongs-to"` // account referred to by originAccountID + TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // Mention target/receiver account ID + TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // account referred to by targetAccountID + Silent bool `validate:"-" bun:",notnull,default:false"` // Prevent this mention from generating a notification? /* NON-DATABASE CONVENIENCE FIELDS @@ -54,15 +46,14 @@ type Mention struct { // @whatever_username@example.org // // This will not be put in the database, it's just for convenience. - NameString string `bun:"-"` + NameString string `validate:"-" bun:"-"` // TargetAccountURI is the AP ID (uri) of the user mentioned. // // This will not be put in the database, it's just for convenience. - TargetAccountURI string `bun:"-"` + TargetAccountURI string `validate:"-" bun:"-"` // TargetAccountURL is the web url of the user mentioned. // // This will not be put in the database, it's just for convenience. - TargetAccountURL string `bun:"-"` + TargetAccountURL string `validate:"-" bun:"-"` // A pointer to the gtsmodel account of the mentioned account. - } diff --git a/internal/gtsmodel/messages.go b/internal/gtsmodel/messages.go deleted file mode 100644 index 62beb0adc..000000000 --- a/internal/gtsmodel/messages.go +++ /dev/null @@ -1,36 +0,0 @@ -/* - GoToSocial - Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -package gtsmodel - -// FromClientAPI wraps a message that travels from client API into the processor -type FromClientAPI struct { - APObjectType string - APActivityType string - GTSModel interface{} - OriginAccount *Account - TargetAccount *Account -} - -// FromFederator wraps a message that travels from the federator into the processor -type FromFederator struct { - APObjectType string - APActivityType string - GTSModel interface{} - ReceivingAccount *Account -} diff --git a/internal/gtsmodel/notification.go b/internal/gtsmodel/notification.go index 14ab90802..1b1f39a77 100644 --- a/internal/gtsmodel/notification.go +++ b/internal/gtsmodel/notification.go @@ -22,41 +22,29 @@ import "time" // Notification models an alert/notification sent to an account about something like a reblog, like, new follow request, etc. type Notification struct { - // ID of this notification in the database - ID string `bun:"type:CHAR(26),pk,notnull"` - // Type of this notification - NotificationType NotificationType `bun:",notnull"` - // Creation time of this notification - CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // Which account does this notification target (ie., who will receive the notification?) - TargetAccountID string `bun:"type:CHAR(26),notnull"` - TargetAccount *Account `bun:"rel:belongs-to"` - // Which account performed the action that created this notification? - OriginAccountID string `bun:"type:CHAR(26),notnull"` - OriginAccount *Account `bun:"rel:belongs-to"` - // If the notification pertains to a status, what is the database ID of that status? - StatusID string `bun:"type:CHAR(26),nullzero"` - Status *Status `bun:"rel:belongs-to"` - // Has this notification been read already? - Read bool + ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated // when was item created + NotificationType NotificationType `validate:"oneof=follow follow_request mention reblog favourite poll status" bun:",nullzero,notnull"` // Type of this notification + TargetAccountID string `validate:"ulid" bun:"type:CHAR(26),nullzero,notnull"` // Which account does this notification target (ie., who will receive the notification?) + TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // Which account performed the action that created this notification? + OriginAccountID string `validate:"ulid" bun:"type:CHAR(26),nullzero,notnull"` // ID of the account that performed the action that created the notification. + OriginAccount *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to originAccountID + StatusID string `validate:"required_if=NotificationType mention,required_if=NotificationType reblog,required_if=NotificationType favourite,required_if=NotificationType status,omitempty,ulid" bun:"type:CHAR(26),nullzero"` // If the notification pertains to a status, what is the database ID of that status? + Status *Status `validate:"-" bun:"rel:belongs-to"` // Status corresponding to statusID + Read bool `validate:"-" bun:",notnull,default:false"` // Notification has been seen/read } // NotificationType describes the reason/type of this notification. type NotificationType string +// Notification Types const ( - // NotificationFollow -- someone followed you - NotificationFollow NotificationType = "follow" - // NotificationFollowRequest -- someone requested to follow you - NotificationFollowRequest NotificationType = "follow_request" - // NotificationMention -- someone mentioned you in their status - NotificationMention NotificationType = "mention" - // NotificationReblog -- someone boosted one of your statuses - NotificationReblog NotificationType = "reblog" - // NotificationFave -- someone faved/liked one of your statuses - NotificationFave NotificationType = "favourite" - // NotificationPoll -- a poll you voted in or created has ended - NotificationPoll NotificationType = "poll" - // NotificationStatus -- someone you enabled notifications for has posted a status. - NotificationStatus NotificationType = "status" + NotificationFollow NotificationType = "follow" // NotificationFollow -- someone followed you + NotificationFollowRequest NotificationType = "follow_request" // NotificationFollowRequest -- someone requested to follow you + NotificationMention NotificationType = "mention" // NotificationMention -- someone mentioned you in their status + NotificationReblog NotificationType = "reblog" // NotificationReblog -- someone boosted one of your statuses + NotificationFave NotificationType = "favourite" // NotificationFave -- someone faved/liked one of your statuses + NotificationPoll NotificationType = "poll" // NotificationPoll -- a poll you voted in or created has ended + NotificationStatus NotificationType = "status" // NotificationStatus -- someone you enabled notifications for has posted a status. ) diff --git a/internal/gtsmodel/poll.go b/internal/gtsmodel/poll.go deleted file mode 100644 index c39497cdd..000000000 --- a/internal/gtsmodel/poll.go +++ /dev/null @@ -1,19 +0,0 @@ -/* - GoToSocial - Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -package gtsmodel diff --git a/internal/gtsmodel/relationship.go b/internal/gtsmodel/relationship.go deleted file mode 100644 index 4e6cc03f6..000000000 --- a/internal/gtsmodel/relationship.go +++ /dev/null @@ -1,49 +0,0 @@ -/* - GoToSocial - Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -package gtsmodel - -// Relationship describes a requester's relationship with another account. -type Relationship struct { - // The account id. - ID string - // Are you following this user? - Following bool - // Are you receiving this user's boosts in your home timeline? - ShowingReblogs bool - // Have you enabled notifications for this user? - Notifying bool - // Are you followed by this user? - FollowedBy bool - // Are you blocking this user? - Blocking bool - // Is this user blocking you? - BlockedBy bool - // Are you muting this user? - Muting bool - // Are you muting notifications from this user? - MutingNotifications bool - // Do you have a pending follow request for this user? - Requested bool - // Are you blocking this user's domain? - DomainBlocking bool - // Are you featuring this user on your profile? - Endorsed bool - // Your note on this account. - Note string -} diff --git a/internal/gtsmodel/routersession.go b/internal/gtsmodel/routersession.go index fbc1c7768..3edb8bc36 100644 --- a/internal/gtsmodel/routersession.go +++ b/internal/gtsmodel/routersession.go @@ -18,9 +18,13 @@ package gtsmodel +import "time" + // RouterSession is used to store and retrieve settings for a router session. type RouterSession struct { - ID string `bun:"type:CHAR(26),pk,notnull"` - Auth []byte `bun:"type:bytea,notnull,nullzero"` - Crypt []byte `bun:"type:bytea,notnull,nullzero"` + ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated + Auth []byte `validate:"required,len=32" bun:"type:bytea,notnull,nullzero"` + Crypt []byte `validate:"required,len=32" bun:"type:bytea,notnull,nullzero"` } diff --git a/internal/gtsmodel/status.go b/internal/gtsmodel/status.go index 1997ad5df..f298e71cd 100644 --- a/internal/gtsmodel/status.go +++ b/internal/gtsmodel/status.go @@ -24,87 +24,59 @@ import ( // Status represents a user-created 'post' or 'status' in the database, either remote or local type Status struct { - // id of the status in the database - ID string `bun:"type:CHAR(26),pk,notnull"` - // uri at which this status is reachable - URI string `bun:",unique,nullzero"` - // web url for viewing this status - URL string `bun:",unique,nullzero"` - // the html-formatted content of this status - Content string `bun:",nullzero"` - // Database IDs of any media attachments associated with this status - AttachmentIDs []string `bun:"attachments,array"` - Attachments []*MediaAttachment `bun:"attached_media,rel:has-many"` - // Database IDs of any tags used in this status - TagIDs []string `bun:"tags,array"` - Tags []*Tag `bun:"attached_tags,m2m:status_to_tags"` // https://bun.uptrace.dev/guide/relations.html#many-to-many-relation - // Database IDs of any mentions in this status - MentionIDs []string `bun:"mentions,array"` - Mentions []*Mention `bun:"attached_mentions,rel:has-many"` - // Database IDs of any emojis used in this status - EmojiIDs []string `bun:"emojis,array"` - Emojis []*Emoji `bun:"attached_emojis,m2m:status_to_emojis"` // https://bun.uptrace.dev/guide/relations.html#many-to-many-relation - // when was this status created? - CreatedAt time.Time `bun:",notnull,nullzero,default:current_timestamp"` - // when was this status updated? - UpdatedAt time.Time `bun:",notnull,nullzero,default:current_timestamp"` - // is this status from a local account? - Local bool - // which account posted this status? - AccountID string `bun:"type:CHAR(26),notnull"` - Account *Account `bun:"rel:belongs-to"` - // AP uri of the owner of this status - AccountURI string `bun:",nullzero"` - // id of the status this status is a reply to - InReplyToID string `bun:"type:CHAR(26),nullzero"` - InReplyTo *Status `bun:"-"` - // AP uri of the status this status is a reply to - InReplyToURI string `bun:",nullzero"` - // id of the account that this status replies to - InReplyToAccountID string `bun:"type:CHAR(26),nullzero"` - InReplyToAccount *Account `bun:"rel:belongs-to"` - // id of the status this status is a boost of - BoostOfID string `bun:"type:CHAR(26),nullzero"` - BoostOf *Status `bun:"-"` - // id of the account that owns the boosted status - BoostOfAccountID string `bun:"type:CHAR(26),nullzero"` - BoostOfAccount *Account `bun:"rel:belongs-to"` - // cw string for this status - ContentWarning string `bun:",nullzero"` - // visibility entry for this status - Visibility Visibility `bun:",notnull"` - // mark the status as sensitive? - Sensitive bool - // what language is this status written in? - Language string `bun:",nullzero"` - // Which application was used to create this status? - CreatedWithApplicationID string `bun:"type:CHAR(26),nullzero"` - CreatedWithApplication *Application `bun:"rel:belongs-to"` - // advanced visibility for this status - VisibilityAdvanced *VisibilityAdvanced - // What is the activitystreams type of this status? See: https://www.w3.org/TR/activitystreams-vocabulary/#object-types - // Will probably almost always be Note but who knows!. - ActivityStreamsType string `bun:",nullzero"` - // Original text of the status without formatting - Text string `bun:",nullzero"` - // Has this status been pinned by its owner? - Pinned bool + ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated + URI string `validate:"required,url" bun:",unique,nullzero,notnull"` // activitypub URI of this status + URL string `validate:"url" bun:",nullzero"` // web url for viewing this status + Content string `validate:"-" bun:",nullzero"` // content of this status; likely html-formatted but not guaranteed + AttachmentIDs []string `validate:"dive,ulid" bun:"attachments,array"` // Database IDs of any media attachments associated with this status + Attachments []*MediaAttachment `validate:"-" bun:"attached_media,rel:has-many"` // Attachments corresponding to attachmentIDs + TagIDs []string `validate:"dive,ulid" bun:"tags,array"` // Database IDs of any tags used in this status + Tags []*Tag `validate:"-" bun:"attached_tags,m2m:status_to_tags"` // Tags corresponding to tagIDs. https://bun.uptrace.dev/guide/relations.html#many-to-many-relation + MentionIDs []string `validate:"dive,ulid" bun:"mentions,array"` // Database IDs of any mentions in this status + Mentions []*Mention `validate:"-" bun:"attached_mentions,rel:has-many"` // Mentions corresponding to mentionIDs + EmojiIDs []string `validate:"dive,ulid" bun:"emojis,array"` // Database IDs of any emojis used in this status + Emojis []*Emoji `validate:"-" bun:"attached_emojis,m2m:status_to_emojis"` // Emojis corresponding to emojiIDs. https://bun.uptrace.dev/guide/relations.html#many-to-many-relation + Local bool `validate:"-" bun:",notnull,default:false"` // is this status from a local account? + AccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // which account posted this status? + Account *Account `validate:"-" bun:"rel:belongs-to"` // account corresponding to accountID + AccountURI string `validate:"required,url" bun:",nullzero,notnull"` // activitypub uri of the owner of this status + InReplyToID string `validate:"required_with=InReplyToURI InReplyToAccountID,omitempty,ulid" bun:"type:CHAR(26),nullzero"` // id of the status this status replies to + InReplyToURI string `validate:"required_with=InReplyToID InReplyToAccountID,omitempty,url" bun:",nullzero"` // activitypub uri of the status this status is a reply to + InReplyToAccountID string `validate:"required_with=InReplyToID InReplyToURI,omitempty,ulid" bun:"type:CHAR(26),nullzero"` // id of the account that this status replies to + InReplyTo *Status `validate:"-" bun:"-"` // status corresponding to inReplyToID + InReplyToAccount *Account `validate:"-" bun:"rel:belongs-to"` // account corresponding to inReplyToAccountID + BoostOfID string `validate:"required_with=BoostOfAccountID,omitempty,ulid" bun:"type:CHAR(26),nullzero"` // id of the status this status is a boost of + BoostOfAccountID string `validate:"required_with=BoostOfID,omitempty,ulid" bun:"type:CHAR(26),nullzero"` // id of the account that owns the boosted status + BoostOf *Status `validate:"-" bun:"-"` // status that corresponds to boostOfID + BoostOfAccount *Account `validate:"-" bun:"rel:belongs-to"` // account that corresponds to boostOfAccountID + ContentWarning string `validate:"-" bun:",nullzero"` // cw string for this status + Visibility Visibility `validate:"-" bun:",nullzero,notnull"` // visibility entry for this status + Sensitive bool `validate:"-" bun:",notnull,default:false"` // mark the status as sensitive? + Language string `validate:"-" bun:",nullzero"` // what language is this status written in? + CreatedWithApplicationID string `validate:"required_if=Local true,omitempty,ulid" bun:"type:CHAR(26),nullzero"` // Which application was used to create this status? + CreatedWithApplication *Application `validate:"-" bun:"rel:belongs-to"` // application corresponding to createdWithApplicationID + VisibilityAdvanced VisibilityAdvanced `validate:"required" bun:",nullzero,notnull" ` // advanced visibility for this status + ActivityStreamsType string `validate:"required" bun:",nullzero,notnull"` // What is the activitystreams type of this status? See: https://www.w3.org/TR/activitystreams-vocabulary/#object-types. Will probably almost always be Note but who knows!. + Text string `validate:"-" bun:",nullzero"` // Original text of the status without formatting + Pinned bool `validate:"-" bun:",notnull,default:false" ` // Has this status been pinned by its owner? } // StatusToTag is an intermediate struct to facilitate the many2many relationship between a status and one or more tags. type StatusToTag struct { - StatusID string `bun:"type:CHAR(26),unique:statustag,nullzero"` - Status *Status `bun:"rel:belongs-to"` - TagID string `bun:"type:CHAR(26),unique:statustag,nullzero"` - Tag *Tag `bun:"rel:belongs-to"` + StatusID string `validate:"ulid,required" bun:"type:CHAR(26),unique:statustag,nullzero,notnull"` + Status *Status `validate:"-" bun:"rel:belongs-to"` + TagID string `validate:"ulid,required" bun:"type:CHAR(26),unique:statustag,nullzero,notnull"` + Tag *Tag `validate:"-" bun:"rel:belongs-to"` } // StatusToEmoji is an intermediate struct to facilitate the many2many relationship between a status and one or more emojis. type StatusToEmoji struct { - StatusID string `bun:"type:CHAR(26),unique:statusemoji,nullzero"` - Status *Status `bun:"rel:belongs-to"` - EmojiID string `bun:"type:CHAR(26),unique:statusemoji,nullzero"` - Emoji *Emoji `bun:"rel:belongs-to"` + StatusID string `validate:"ulid,required" bun:"type:CHAR(26),unique:statusemoji,nullzero,notnull"` + Status *Status `validate:"-" bun:"rel:belongs-to"` + EmojiID string `validate:"ulid,required" bun:"type:CHAR(26),unique:statusemoji,nullzero,notnull"` + Emoji *Emoji `validate:"-" bun:"rel:belongs-to"` } // Visibility represents the visibility granularity of a status. @@ -137,12 +109,8 @@ const ( // // If DIRECT is selected, boostable will be FALSE, and all other flags will be TRUE. type VisibilityAdvanced struct { - // This status will be federated beyond the local timeline(s) - Federated bool `bun:"default:true"` - // This status can be boosted/reblogged - Boostable bool `bun:"default:true"` - // This status can be replied to - Replyable bool `bun:"default:true"` - // This status can be liked/faved - Likeable bool `bun:"default:true"` + Federated bool `validate:"-" bun:",notnull,default:true"` // This status will be federated beyond the local timeline(s) + Boostable bool `validate:"-" bun:",notnull,default:true"` // This status can be boosted/reblogged + Replyable bool `validate:"-" bun:",notnull,default:true"` // This status can be replied to + Likeable bool `validate:"-" bun:",notnull,default:true"` // This status can be liked/faved } diff --git a/internal/gtsmodel/statusbookmark.go b/internal/gtsmodel/statusbookmark.go index 26dafa420..3dcf4cb92 100644 --- a/internal/gtsmodel/statusbookmark.go +++ b/internal/gtsmodel/statusbookmark.go @@ -20,18 +20,15 @@ package gtsmodel import "time" -// StatusBookmark refers to one account having a 'bookmark' of the status of another account +// StatusBookmark refers to one account having a 'bookmark' of the status of another account. type StatusBookmark struct { - // id of this bookmark in the database - ID string `bun:"type:CHAR(26),pk,notnull,unique"` - // when was this bookmark created - CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // id of the account that created ('did') the bookmarking - AccountID string `bun:"type:CHAR(26),notnull"` - Account *Account `bun:"rel:belongs-to"` - // id the account owning the bookmarked status - TargetAccountID string `bun:"type:CHAR(26),notnull"` - TargetAccount *Account `bun:"rel:belongs-to"` - // database id of the status that has been bookmarked - StatusID string `bun:"type:CHAR(26),notnull"` + ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated + AccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // id of the account that created ('did') the bookmark + Account *Account `validate:"-" bun:"rel:belongs-to"` // account that created the bookmark + TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // id the account owning the bookmarked status + TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // account owning the bookmarked status + StatusID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // database id of the status that has been bookmarked + Status *Status `validate:"-" bun:"rel:belongs-to"` // the bookmarked status } diff --git a/internal/gtsmodel/statusfave.go b/internal/gtsmodel/statusfave.go index 3b816af56..93bcda0e6 100644 --- a/internal/gtsmodel/statusfave.go +++ b/internal/gtsmodel/statusfave.go @@ -22,19 +22,14 @@ import "time" // StatusFave refers to a 'fave' or 'like' in the database, from one account, targeting the status of another account type StatusFave struct { - // id of this fave in the database - ID string `bun:"type:CHAR(26),pk,notnull,unique"` - // when was this fave created - CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // id of the account that created ('did') the fave - AccountID string `bun:"type:CHAR(26),notnull"` - Account *Account `bun:"rel:belongs-to"` - // id the account owning the faved status - TargetAccountID string `bun:"type:CHAR(26),notnull"` - TargetAccount *Account `bun:"rel:belongs-to"` - // database id of the status that has been 'faved' - StatusID string `bun:"type:CHAR(26),notnull"` - Status *Status `bun:"rel:belongs-to"` - // ActivityPub URI of this fave - URI string `bun:",notnull"` + ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated + AccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // id of the account that created ('did') the fave + Account *Account `validate:"-" bun:"rel:belongs-to"` // account that created the fave + TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // id the account owning the faved status + TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // account owning the faved status + StatusID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // database id of the status that has been 'faved' + Status *Status `validate:"-" bun:"rel:belongs-to"` // the faved status + URI string `validate:"required,url" bun:",nullzero,notnull"` // ActivityPub URI of this fave } diff --git a/internal/gtsmodel/statusmute.go b/internal/gtsmodel/statusmute.go index 56a792ab4..2c03b8085 100644 --- a/internal/gtsmodel/statusmute.go +++ b/internal/gtsmodel/statusmute.go @@ -20,19 +20,15 @@ package gtsmodel import "time" -// StatusMute refers to one account having muted the status of another account or its own +// StatusMute refers to one account having muted the status of another account or its own. type StatusMute struct { - // id of this mute in the database - ID string `bun:"type:CHAR(26),pk,notnull,unique"` - // when was this mute created - CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // id of the account that created ('did') the mute - AccountID string `bun:"type:CHAR(26),notnull"` - Account *Account `bun:"rel:belongs-to"` - // id the account owning the muted status (can be the same as accountID) - TargetAccountID string `bun:"type:CHAR(26),notnull"` - TargetAccount *Account `bun:"rel:belongs-to"` - // database id of the status that has been muted - StatusID string `bun:"type:CHAR(26),notnull"` - Status *Status `bun:"rel:belongs-to"` + ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated + AccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // id of the account that created ('did') the mute + Account *Account `validate:"-" bun:"rel:belongs-to"` // pointer to the account specified by accountID + TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // id the account owning the muted status (can be the same as accountID) + TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // pointer to the account specified by targetAccountID + StatusID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // database id of the status that has been muted + Status *Status `validate:"-" bun:"rel:belongs-to"` // pointer to the muted status specified by statusID } diff --git a/internal/gtsmodel/stream.go b/internal/gtsmodel/stream.go deleted file mode 100644 index 4a1571de5..000000000 --- a/internal/gtsmodel/stream.go +++ /dev/null @@ -1,38 +0,0 @@ -package gtsmodel - -import "sync" - -// StreamsForAccount is a wrapper for the multiple streams that one account can have running at the same time. -// TODO: put a limit on this -type StreamsForAccount struct { - // The currently held streams for this account - Streams []*Stream - // Mutex to lock/unlock when modifying the slice of streams. - sync.Mutex -} - -// Stream represents one open stream for a client. -type Stream struct { - // ID of this stream, generated during creation. - ID string - // Type of this stream: user/public/etc - Type string - // Channel of messages for the client to read from - Messages chan *Message - // Channel to close when the client drops away - Hangup chan interface{} - // Only put messages in the stream when Connected - Connected bool - // Mutex to lock/unlock when inserting messages, hanging up, changing the connected state etc. - sync.Mutex -} - -// Message represents one streamed message. -type Message struct { - // All the stream types this message should be delivered to. - Stream []string `json:"stream"` - // The event type of the message (update/delete/notification etc) - Event string `json:"event"` - // The actual payload of the message. In case of an update or notification, this will be a JSON string. - Payload string `json:"payload"` -} diff --git a/internal/gtsmodel/tag.go b/internal/gtsmodel/tag.go index d4be0b66c..295447c4f 100644 --- a/internal/gtsmodel/tag.go +++ b/internal/gtsmodel/tag.go @@ -20,24 +20,15 @@ package gtsmodel import "time" -// Tag represents a hashtag for gathering public statuses together +// Tag represents a hashtag for gathering public statuses together. type Tag struct { - // id of this tag in the database - ID string `bun:",unique,type:CHAR(26),pk,notnull"` - // Href of this tag, eg https://example.org/tags/somehashtag - URL string `bun:",nullzero"` - // name of this tag -- the tag without the hash part - Name string `bun:",unique,notnull"` - // Which account ID is the first one we saw using this tag? - FirstSeenFromAccountID string `bun:"type:CHAR(26),nullzero"` - // when was this tag created - CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // when was this tag last updated - UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // can our instance users use this tag? - Useable bool `bun:",notnull,default:true"` - // can our instance users look up this tag? - Listable bool `bun:",notnull,default:true"` - // when was this tag last used? - LastStatusAt time.Time `bun:",nullzero"` + ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated + URL string `validate:"required,url" bun:",nullzero,notnull"` // Href/web address of this tag, eg https://example.org/tags/somehashtag + Name string `validate:"required" bun:",unique,nullzero,notnull"` // name of this tag -- the tag without the hash part + FirstSeenFromAccountID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // Which account ID is the first one we saw using this tag? + Useable bool `validate:"-" bun:",notnull,default:true"` // can our instance users use this tag? + Listable bool `validate:"-" bun:",notnull,default:true"` // can our instance users look up this tag? + LastStatusAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was this tag last used? } diff --git a/internal/gtsmodel/token.go b/internal/gtsmodel/token.go new file mode 100644 index 000000000..5fa96e915 --- /dev/null +++ b/internal/gtsmodel/token.go @@ -0,0 +1,43 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package gtsmodel + +import "time" + +// Token is a translation of the gotosocial token with the ExpiresIn fields replaced with ExpiresAt. +type Token struct { + ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated + ClientID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // ID of the client who owns this token + UserID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // ID of the user who owns this token + RedirectURI string `validate:"required,uri" bun:",nullzero,notnull"` // Oauth redirect URI for this token + Scope string `validate:"required" bun:",nullzero,notnull"` // Oauth scope + Code string `validate:"-" bun:",pk,nullzero,notnull,default:''"` // Code, if present + CodeChallenge string `validate:"-" bun:",nullzero"` // Code challenge, if code present + CodeChallengeMethod string `validate:"-" bun:",nullzero"` // Code challenge method, if code present + CodeCreateAt time.Time `validate:"required_with=Code" bun:"type:timestamp,nullzero"` // Code created time, if code present + CodeExpiresAt time.Time `validate:"-" bun:"type:timestamp,nullzero"` // Code expires at -- null means the code never expires + Access string `validate:"-" bun:",pk,nullzero,notnull,default:''"` // User level access token, if present + AccessCreateAt time.Time `validate:"required_with=Access" bun:"type:timestamp,nullzero"` // User level access token created time, if access present + AccessExpiresAt time.Time `validate:"-" bun:"type:timestamp,nullzero"` // User level access token expires at -- null means the token never expires + Refresh string `validate:"-" bun:",pk,nullzero,notnull,default:''"` // Refresh token, if present + RefreshCreateAt time.Time `validate:"required_with=Refresh" bun:"type:timestamp,nullzero"` // Refresh created at, if refresh present + RefreshExpiresAt time.Time `validate:"-" bun:"type:timestamp,nullzero"` // Refresh expires at -- null means the refresh token never expires +} diff --git a/internal/gtsmodel/user.go b/internal/gtsmodel/user.go index c36d75c8c..28156cfdd 100644 --- a/internal/gtsmodel/user.go +++ b/internal/gtsmodel/user.go @@ -26,97 +26,34 @@ import ( // User represents an actual human user of gotosocial. Note, this is a LOCAL gotosocial user, not a remote account. // To cross reference this local user with their account (which can be local or remote), use the AccountID field. type User struct { - /* - BASIC INFO - */ - - // id of this user in the local database; the end-user will never need to know this, it's strictly internal - ID string `bun:"type:CHAR(26),pk,notnull,unique"` - // confirmed email address for this user, this should be unique -- only one email address registered per instance, multiple users per email are not supported - Email string `bun:"default:null,unique,nullzero"` - // The id of the local gtsmodel.Account entry for this user, if it exists (unconfirmed users don't have an account yet) - AccountID string `bun:"type:CHAR(26),unique,nullzero"` - Account *Account `bun:"rel:belongs-to"` - // The encrypted password of this user, generated using https://pkg.go.dev/golang.org/x/crypto/bcrypt#GenerateFromPassword. A salt is included so we're safe against 🌈 tables - EncryptedPassword string `bun:",notnull"` - - /* - USER METADATA - */ - - // When was this user created? - CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // From what IP was this user created? - SignUpIP net.IP `bun:",nullzero"` - // When was this user updated (eg., password changed, email address changed)? - UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` - // When did this user sign in for their current session? - CurrentSignInAt time.Time `bun:",nullzero"` - // What's the most recent IP of this user - CurrentSignInIP net.IP `bun:",nullzero"` - // When did this user last sign in? - LastSignInAt time.Time `bun:",nullzero"` - // What's the previous IP of this user? - LastSignInIP net.IP `bun:",nullzero"` - // How many times has this user signed in? - SignInCount int - // id of the user who invited this user (who let this guy in?) - InviteID string `bun:"type:CHAR(26),nullzero"` - // What languages does this user want to see? - ChosenLanguages []string - // What languages does this user not want to see? - FilteredLanguages []string - // In what timezone/locale is this user located? - Locale string `bun:",nullzero"` - // Which application id created this user? See gtsmodel.Application - CreatedByApplicationID string `bun:"type:CHAR(26),nullzero"` - CreatedByApplication *Application `bun:"rel:belongs-to"` - // When did we last contact this user - LastEmailedAt time.Time `bun:",nullzero"` - - /* - USER CONFIRMATION - */ - - // What confirmation token did we send this user/what are we expecting back? - ConfirmationToken string `bun:",nullzero"` - // When did the user confirm their email address - ConfirmedAt time.Time `bun:",nullzero"` - // When did we send email confirmation to this user? - ConfirmationSentAt time.Time `bun:",nullzero"` - // Email address that hasn't yet been confirmed - UnconfirmedEmail string `bun:",nullzero"` - - /* - ACL FLAGS - */ - - // Is this user a moderator? - Moderator bool - // Is this user an admin? - Admin bool - // Is this user disabled from posting? - Disabled bool - // Has this user been approved by a moderator? - Approved bool - - /* - USER SECURITY - */ - - // The generated token that the user can use to reset their password - ResetPasswordToken string `bun:",nullzero"` - // When did we email the user their reset-password email? - ResetPasswordSentAt time.Time `bun:",nullzero"` - - EncryptedOTPSecret string `bun:",nullzero"` - EncryptedOTPSecretIv string `bun:",nullzero"` - EncryptedOTPSecretSalt string `bun:",nullzero"` - OTPRequiredForLogin bool - OTPBackupCodes []string - ConsumedTimestamp int - RememberToken string `bun:",nullzero"` - SignInToken string `bun:",nullzero"` - SignInTokenSentAt time.Time `bun:",nullzero"` - WebauthnID string `bun:",nullzero"` + ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated + Email string `validate:"required_with=ConfirmedAt" bun:",nullzero,unique"` // confirmed email address for this user, this should be unique -- only one email address registered per instance, multiple users per email are not supported + AccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull,unique"` // The id of the local gtsmodel.Account entry for this user. + Account *Account `validate:"-" bun:"rel:belongs-to"` // Pointer to the account of this user that corresponds to AccountID. + EncryptedPassword string `validate:"required" bun:",nullzero,notnull"` // The encrypted password of this user, generated using https://pkg.go.dev/golang.org/x/crypto/bcrypt#GenerateFromPassword. A salt is included so we're safe against 🌈 tables. + SignUpIP net.IP `validate:"-" bun:",nullzero"` // From what IP was this user created? + CurrentSignInAt time.Time `validate:"-" bun:"type:timestamp,nullzero"` // When did the user sign in with their current session. + CurrentSignInIP net.IP `validate:"-" bun:",nullzero"` // What's the most recent IP of this user + LastSignInAt time.Time `validate:"-" bun:"type:timestamp,nullzero"` // When did this user last sign in? + LastSignInIP net.IP `validate:"-" bun:",nullzero"` // What's the previous IP of this user? + SignInCount int `validate:"min=0" bun:",nullzero,notnull,default:0"` // How many times has this user signed in? + InviteID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // id of the user who invited this user (who let this joker in?) + ChosenLanguages []string `validate:"-" bun:",nullzero"` // What languages does this user want to see? + FilteredLanguages []string `validate:"-" bun:",nullzero"` // What languages does this user not want to see? + Locale string `validate:"-" bun:",nullzero"` // In what timezone/locale is this user located? + CreatedByApplicationID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // Which application id created this user? See gtsmodel.Application + CreatedByApplication *Application `validate:"-" bun:"rel:belongs-to"` // Pointer to the application corresponding to createdbyapplicationID. + LastEmailedAt time.Time `validate:"-" bun:"type:timestamp,nullzero"` // When was this user last contacted by email. + ConfirmationToken string `validate:"required_with=ConfirmationSentAt" bun:",nullzero"` // What confirmation token did we send this user/what are we expecting back? + ConfirmationSentAt time.Time `validate:"required_with=ConfirmationToken" bun:"type:timestamp,nullzero"` // When did we send email confirmation to this user? + ConfirmedAt time.Time `validate:"required_with=Email" bun:"type:timestamp,nullzero"` // When did the user confirm their email address + UnconfirmedEmail string `validate:"required_without=Email" bun:",nullzero"` // Email address that hasn't yet been confirmed + Moderator bool `validate:"-" bun:",notnull,default:false"` // Is this user a moderator? + Admin bool `validate:"-" bun:",notnull,default:false"` // Is this user an admin? + Disabled bool `validate:"-" bun:",notnull,default:false"` // Is this user disabled from posting? + Approved bool `validate:"-" bun:",notnull,default:false"` // Has this user been approved by a moderator? + ResetPasswordToken string `validate:"required_with=ResetPasswordSentAt" bun:",nullzero"` // The generated token that the user can use to reset their password + ResetPasswordSentAt time.Time `validate:"required_with=ResetPasswordToken" bun:"type:timestamp,nullzero"` // When did we email the user their reset-password email? } |