diff options
51 files changed, 423 insertions, 3164 deletions
| @@ -28,7 +28,6 @@ require (  	github.com/gin-gonic/gin v1.9.1  	github.com/go-fed/httpsig v1.1.0  	github.com/go-playground/form/v4 v4.2.1 -	github.com/go-playground/validator/v10 v10.14.1  	github.com/google/uuid v1.3.0  	github.com/gorilla/feeds v1.1.1  	github.com/gorilla/websocket v1.5.0 @@ -108,6 +107,7 @@ require (  	github.com/go-logr/stdr v1.2.2 // indirect  	github.com/go-playground/locales v0.14.1 // indirect  	github.com/go-playground/universal-translator v0.18.1 // indirect +	github.com/go-playground/validator/v10 v10.14.1 // indirect  	github.com/go-xmlfmt/xmlfmt v0.0.0-20211206191508-7fd73a941850 // indirect  	github.com/goccy/go-json v0.10.2 // indirect  	github.com/godbus/dbus/v5 v5.0.4 // indirect diff --git a/internal/gtsmodel/account.go b/internal/gtsmodel/account.go index bce9065c1..7b27f076a 100644 --- a/internal/gtsmodel/account.go +++ b/internal/gtsmodel/account.go @@ -32,55 +32,55 @@ import (  // Account represents either a local or a remote fediverse account, gotosocial or otherwise (mastodon, pleroma, etc).  type Account 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:timestamptz,nullzero,notnull,default:current_timestamp"`                                        // when was item created. -	UpdatedAt               time.Time        `validate:"-" bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"`                                        // when was item was last updated. -	FetchedAt               time.Time        `validate:"required_with=Domain" bun:"type:timestamptz,nullzero"`                                                       // when was item (remote) last fetched. -	Username                string           `validate:"required" bun:",nullzero,notnull,unique:usernamedomain"`                                                     // 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:usernamedomain"`                                                       // Domain of the account, will be null if this is a local account, otherwise something like ``example.org``. 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:""`                                                                                                   // DisplayName for this account. Can be empty, then just the Username will be used for display purposes. -	EmojiIDs                []string         `validate:"dive,ulid" bun:"emojis,array"`                                                                               // Database IDs of any emojis used in this account's bio, display name, etc -	Emojis                  []*Emoji         `validate:"-" bun:"attached_emojis,m2m:account_to_emojis"`                                                              // Emojis corresponding to emojiIDs. https://bun.uptrace.dev/guide/relations.html#many-to-many-relation -	Fields                  []*Field         `validate:"-"`                                                                                                          // A slice of of fields that this account has added to their profile. -	FieldsRaw               []*Field         `validate:"-"`                                                                                                          // The raw (unparsed) content of fields that this account has added to their profile, without conversion to HTML, only available when requester = target -	Note                    string           `validate:"-" bun:""`                                                                                                   // A note that this account has on their profile (ie., the account's bio/description of themselves) -	NoteRaw                 string           `validate:"-" bun:""`                                                                                                   // The raw contents of .Note without conversion to HTML, only available when requester = target -	Memorial                *bool            `validate:"-" bun:",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 (TODO: migrate to be AlsoKnownAsID) -	MovedToAccountID        string           `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"`                                                                // This account has moved this account id in the database -	Bot                     *bool            `validate:"-" bun:",default:false"`                                                                                     // Does this account identify itself as a bot? -	Reason                  string           `validate:"-" bun:""`                                                                                                   // What reason was given for signing up when this account was created? -	Locked                  *bool            `validate:"-" bun:",default:true"`                                                                                      // Does this account need an approval for new followers? -	Discoverable            *bool            `validate:"-" bun:",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:",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? -	StatusContentType       string           `validate:"required_without=Domain,omitempty,oneof=text/plain text/markdown" bun:",nullzero"`                           // What is the default format for statuses posted by this account (only for local accounts). -	CustomCSS               string           `validate:"-" bun:",nullzero"`                                                                                          // Custom CSS that should be displayed for this Account's profile and statuses. -	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 -	InboxURI                string           `validate:"required_without=Domain,omitempty,url" bun:",nullzero,unique"`                                               // Address of this account's ActivityPub inbox, for sending activity to -	SharedInboxURI          *string          `validate:"-" bun:""`                                                                                                   // Address of this account's ActivityPub sharedInbox. Gotcha warning: this is a string pointer because it has three possible states: 1. We don't know yet if the account has a shared inbox -- null. 2. We know it doesn't have a shared inbox -- empty string. 3. We know it does have a shared inbox -- url string. -	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" bun:""`                                                                             // Privatekey for validating activitypub requests, will only be defined for local accounts -	PublicKey               *rsa.PublicKey   `validate:"required" bun:",notnull"`                                                                                    // 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:timestamptz,nullzero"`                                                                          // When was this account set to have all its media shown as sensitive? -	SilencedAt              time.Time        `validate:"-" bun:"type:timestamptz,nullzero"`                                                                          // When was this account silenced (eg., statuses only visible to followers, not public)? -	SuspendedAt             time.Time        `validate:"-" bun:"type:timestamptz,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:",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 -	EnableRSS               *bool            `validate:"-" bun:",default:false"`                                                                                     // enable RSS feed subscription for this account's public posts at [URL]/feed +	ID                      string           `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt               time.Time        `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created. +	UpdatedAt               time.Time        `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item was last updated. +	FetchedAt               time.Time        `bun:"type:timestamptz,nullzero"`                                   // when was item (remote) last fetched. +	Username                string           `bun:",nullzero,notnull,unique:usernamedomain"`                     // 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           `bun:",nullzero,unique:usernamedomain"`                             // Domain of the account, will be null if this is a local account, otherwise something like ``example.org``. Should be unique with username. +	AvatarMediaAttachmentID string           `bun:"type:CHAR(26),nullzero"`                                      // Database ID of the media attachment, if present +	AvatarMediaAttachment   *MediaAttachment `bun:"rel:belongs-to"`                                              // MediaAttachment corresponding to avatarMediaAttachmentID +	AvatarRemoteURL         string           `bun:",nullzero"`                                                   // For a non-local account, where can the header be fetched? +	HeaderMediaAttachmentID string           `bun:"type:CHAR(26),nullzero"`                                      // Database ID of the media attachment, if present +	HeaderMediaAttachment   *MediaAttachment `bun:"rel:belongs-to"`                                              // MediaAttachment corresponding to headerMediaAttachmentID +	HeaderRemoteURL         string           `bun:",nullzero"`                                                   // For a non-local account, where can the header be fetched? +	DisplayName             string           `bun:""`                                                            // DisplayName for this account. Can be empty, then just the Username will be used for display purposes. +	EmojiIDs                []string         `bun:"emojis,array"`                                                // Database IDs of any emojis used in this account's bio, display name, etc +	Emojis                  []*Emoji         `bun:"attached_emojis,m2m:account_to_emojis"`                       // Emojis corresponding to emojiIDs. https://bun.uptrace.dev/guide/relations.html#many-to-many-relation +	Fields                  []*Field         // A slice of of fields that this account has added to their profile. +	FieldsRaw               []*Field         // The raw (unparsed) content of fields that this account has added to their profile, without conversion to HTML, only available when requester = target +	Note                    string           `bun:""`                               // A note that this account has on their profile (ie., the account's bio/description of themselves) +	NoteRaw                 string           `bun:""`                               // The raw contents of .Note without conversion to HTML, only available when requester = target +	Memorial                *bool            `bun:",default:false"`                 // Is this a memorial account, ie., has the user passed away? +	AlsoKnownAs             string           `bun:"type:CHAR(26),nullzero"`         // This account is associated with x account id (TODO: migrate to be AlsoKnownAsID) +	MovedToAccountID        string           `bun:"type:CHAR(26),nullzero"`         // This account has moved this account id in the database +	Bot                     *bool            `bun:",default:false"`                 // Does this account identify itself as a bot? +	Reason                  string           `bun:""`                               // What reason was given for signing up when this account was created? +	Locked                  *bool            `bun:",default:true"`                  // Does this account need an approval for new followers? +	Discoverable            *bool            `bun:",default:false"`                 // Should this account be shown in the instance's profile directory? +	Privacy                 Visibility       `bun:",nullzero"`                      // Default post privacy for this account +	Sensitive               *bool            `bun:",default:false"`                 // Set posts from this account to sensitive by default? +	Language                string           `bun:",nullzero,notnull,default:'en'"` // What language does this account post in? +	StatusContentType       string           `bun:",nullzero"`                      // What is the default format for statuses posted by this account (only for local accounts). +	CustomCSS               string           `bun:",nullzero"`                      // Custom CSS that should be displayed for this Account's profile and statuses. +	URI                     string           `bun:",nullzero,notnull,unique"`       // ActivityPub URI for this account. +	URL                     string           `bun:",nullzero,unique"`               // Web URL for this account's profile +	InboxURI                string           `bun:",nullzero,unique"`               // Address of this account's ActivityPub inbox, for sending activity to +	SharedInboxURI          *string          `bun:""`                               // Address of this account's ActivityPub sharedInbox. Gotcha warning: this is a string pointer because it has three possible states: 1. We don't know yet if the account has a shared inbox -- null. 2. We know it doesn't have a shared inbox -- empty string. 3. We know it does have a shared inbox -- url string. +	OutboxURI               string           `bun:",nullzero,unique"`               // Address of this account's activitypub outbox +	FollowingURI            string           `bun:",nullzero,unique"`               // URI for getting the following list of this account +	FollowersURI            string           `bun:",nullzero,unique"`               // URI for getting the followers list of this account +	FeaturedCollectionURI   string           `bun:",nullzero,unique"`               // URL for getting the featured collection list of this account +	ActorType               string           `bun:",nullzero,notnull"`              // What type of activitypub actor is this account? +	PrivateKey              *rsa.PrivateKey  `bun:""`                               // Privatekey for validating activitypub requests, will only be defined for local accounts +	PublicKey               *rsa.PublicKey   `bun:",notnull"`                       // Publickey for encoding activitypub requests, will be defined for both local and remote accounts +	PublicKeyURI            string           `bun:",nullzero,notnull,unique"`       // Web-reachable location of this account's public key +	SensitizedAt            time.Time        `bun:"type:timestamptz,nullzero"`      // When was this account set to have all its media shown as sensitive? +	SilencedAt              time.Time        `bun:"type:timestamptz,nullzero"`      // When was this account silenced (eg., statuses only visible to followers, not public)? +	SuspendedAt             time.Time        `bun:"type:timestamptz,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            `bun:",default:false"`                 // Hide this account's collections +	SuspensionOrigin        string           `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 +	EnableRSS               *bool            `bun:",default:false"`                 // enable RSS feed subscription for this account's public posts at [URL]/feed  }  // IsLocal returns whether account is a local user account. @@ -131,19 +131,19 @@ func (a *Account) EmojisPopulated() bool {  // AccountToEmoji is an intermediate struct to facilitate the many2many relationship between an account and one or more emojis.  type AccountToEmoji struct { -	AccountID string   `validate:"ulid,required" bun:"type:CHAR(26),unique:accountemoji,nullzero,notnull"` -	Account   *Account `validate:"-" bun:"rel:belongs-to"` -	EmojiID   string   `validate:"ulid,required" bun:"type:CHAR(26),unique:accountemoji,nullzero,notnull"` -	Emoji     *Emoji   `validate:"-" bun:"rel:belongs-to"` +	AccountID string   `bun:"type:CHAR(26),unique:accountemoji,nullzero,notnull"` +	Account   *Account `bun:"rel:belongs-to"` +	EmojiID   string   `bun:"type:CHAR(26),unique:accountemoji,nullzero,notnull"` +	Emoji     *Emoji   `bun:"rel:belongs-to"`  }  // 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    `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). +	Name       string    // Name of this field. +	Value      string    // Value of this field. +	VerifiedAt time.Time `bun:",nullzero"` // This field was verified at (optional).  }  // Relationship describes a requester's relationship with another account. diff --git a/internal/gtsmodel/accountnote.go b/internal/gtsmodel/accountnote.go index 239ed6ce9..74b730eae 100644 --- a/internal/gtsmodel/accountnote.go +++ b/internal/gtsmodel/accountnote.go @@ -21,12 +21,12 @@ import "time"  // AccountNote stores a private note from a local account related to any account.  type AccountNote 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:timestamptz,nullzero,notnull,default:current_timestamp"`                                       // when was item created -	UpdatedAt       time.Time `validate:"-" bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"`                                       // when was item last updated -	AccountID       string    `validate:"required,ulid" bun:"type:CHAR(26),unique:account_notes_account_id_target_account_id_uniq,notnull,nullzero"` // ID of the local account that created the note -	Account         *Account  `validate:"-" bun:"rel:belongs-to"`                                                                                    // Account corresponding to accountID -	TargetAccountID string    `validate:"required,ulid" bun:"type:CHAR(26),unique:account_notes_account_id_target_account_id_uniq,notnull,nullzero"` // Who is the target of this note? -	TargetAccount   *Account  `validate:"-" bun:"rel:belongs-to"`                                                                                    // Account corresponding to targetAccountID -	Comment         string    `validate:"-" bun:""`                                                                                                  // The text of the note. +	ID              string    `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                                              // id of this item in the database +	CreatedAt       time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"`                           // when was item created +	UpdatedAt       time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"`                           // when was item last updated +	AccountID       string    `bun:"type:CHAR(26),unique:account_notes_account_id_target_account_id_uniq,notnull,nullzero"` // ID of the local account that created the note +	Account         *Account  `bun:"rel:belongs-to"`                                                                        // Account corresponding to accountID +	TargetAccountID string    `bun:"type:CHAR(26),unique:account_notes_account_id_target_account_id_uniq,notnull,nullzero"` // Who is the target of this note? +	TargetAccount   *Account  `bun:"rel:belongs-to"`                                                                        // Account corresponding to targetAccountID +	Comment         string    `bun:""`                                                                                      // The text of the note.  } diff --git a/internal/gtsmodel/admin.go b/internal/gtsmodel/admin.go index 22a38f32c..f1f30db2d 100644 --- a/internal/gtsmodel/admin.go +++ b/internal/gtsmodel/admin.go @@ -24,17 +24,17 @@ import (  // AdminAccountAction models an action taken by an instance administrator on an account.  type AdminAccountAction 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:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created -	UpdatedAt       time.Time       `validate:"-" bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated -	AccountID       string          `validate:"required,ulid" bun:"type:CHAR(26),notnull,nullzero"`                  // Who performed this admin action. -	Account         *Account        `validate:"-" bun:"rel:has-one"`                                                 // Account corresponding to accountID -	TargetAccountID string          `validate:"required,ulid" bun:"type:CHAR(26),notnull,nullzero"`                  // Who is the target of this action -	TargetAccount   *Account        `validate:"-" bun:"rel:has-one"`                                                 // Account corresponding to targetAccountID -	Text            string          `validate:"-" bun:""`                                                            // text explaining why this action was taken -	Type            AdminActionType `validate:"oneof=disable silence suspend" bun:",nullzero,notnull"`               // type of action that was taken -	SendEmail       bool            `validate:"-" bun:""`                                                            // should an email be sent to the account owner to explain what happened -	ReportID        string          `validate:",omitempty,ulid" bun:"type:CHAR(26),nullzero"`                        // id of a report connected to this action, if it exists +	ID              string          `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt       time.Time       `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt       time.Time       `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	AccountID       string          `bun:"type:CHAR(26),notnull,nullzero"`                              // Who performed this admin action. +	Account         *Account        `bun:"rel:has-one"`                                                 // Account corresponding to accountID +	TargetAccountID string          `bun:"type:CHAR(26),notnull,nullzero"`                              // Who is the target of this action +	TargetAccount   *Account        `bun:"rel:has-one"`                                                 // Account corresponding to targetAccountID +	Text            string          `bun:""`                                                            // text explaining why this action was taken +	Type            AdminActionType `bun:",nullzero,notnull"`                                           // type of action that was taken +	SendEmail       bool            `bun:""`                                                            // should an email be sent to the account owner to explain what happened +	ReportID        string          `bun:"type:CHAR(26),nullzero"`                                      // id of a report connected to this action, if it exists  }  // AdminActionType describes a type of action taken on an entity by an admin diff --git a/internal/gtsmodel/application.go b/internal/gtsmodel/application.go index a9057b558..5f2d4f4b1 100644 --- a/internal/gtsmodel/application.go +++ b/internal/gtsmodel/application.go @@ -22,13 +22,13 @@ 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           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:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created -	UpdatedAt    time.Time `validate:"-" bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated -	Name         string    `validate:"required" bun:",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:",notnull"`                                             // scopes requested when this app was created +	ID           string    `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt    time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt    time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	Name         string    `bun:",notnull"`                                                    // name of the application given when it was created (eg., 'tusky') +	Website      string    `bun:",nullzero"`                                                   // website for the application given when it was created (eg., 'https://tusky.app') +	RedirectURI  string    `bun:",nullzero,notnull"`                                           // redirect uri requested by the application for oauth2 flow +	ClientID     string    `bun:"type:CHAR(26),nullzero,notnull"`                              // id of the associated oauth client entity in the db +	ClientSecret string    `bun:",nullzero,notnull"`                                           // secret of the associated oauth client entity in the db +	Scopes       string    `bun:",notnull"`                                                    // scopes requested when this app was created  } diff --git a/internal/gtsmodel/block.go b/internal/gtsmodel/block.go index 98f68f451..1fcdb364a 100644 --- a/internal/gtsmodel/block.go +++ b/internal/gtsmodel/block.go @@ -21,12 +21,12 @@ import "time"  // Block refers to the blocking of one account by another.  type Block 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:timestamptz,nullzero,notnull,default:current_timestamp"`      // when was item created -	UpdatedAt       time.Time `validate:"-" bun:"type:timestamptz,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,nullzero"` // 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,nullzero"` // Who is the target of this block ? -	TargetAccount   *Account  `validate:"-" bun:"rel:belongs-to"`                                                   // Account corresponding to targetAccountID +	ID              string    `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt       time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt       time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	URI             string    `bun:",notnull,nullzero,unique"`                                    // ActivityPub uri of this block. +	AccountID       string    `bun:"type:CHAR(26),unique:blocksrctarget,notnull,nullzero"`        // Who does this block originate from? +	Account         *Account  `bun:"rel:belongs-to"`                                              // Account corresponding to accountID +	TargetAccountID string    `bun:"type:CHAR(26),unique:blocksrctarget,notnull,nullzero"`        // Who is the target of this block ? +	TargetAccount   *Account  `bun:"rel:belongs-to"`                                              // Account corresponding to targetAccountID  } diff --git a/internal/gtsmodel/client.go b/internal/gtsmodel/client.go index a712257e5..35a85fdbe 100644 --- a/internal/gtsmodel/client.go +++ b/internal/gtsmodel/client.go @@ -21,10 +21,10 @@ 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:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created -	UpdatedAt time.Time `validate:"-" bun:"type:timestamptz,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 +	ID        string    `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	Secret    string    `bun:",nullzero,notnull"`                                           // secret generated when client was created +	Domain    string    `bun:",nullzero,notnull"`                                           // domain requested for client +	UserID    string    `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 0d038d18c..dfe642ef5 100644 --- a/internal/gtsmodel/domainblock.go +++ b/internal/gtsmodel/domainblock.go @@ -21,14 +21,14 @@ import "time"  // DomainBlock represents a federation block against a particular domain  type DomainBlock 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:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created -	UpdatedAt          time.Time `validate:"-" bun:"type:timestamptz,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:""`                                                            // Private comment on this block, viewable to admins -	PublicComment      string    `validate:"-" bun:""`                                                            // Public comment on this block, viewable (optionally) by everyone -	Obfuscate          *bool     `validate:"-" bun:",nullzero,notnull,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? +	ID                 string    `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt          time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt          time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	Domain             string    `bun:",nullzero,notnull"`                                           // domain to block. Eg. 'whatever.com' +	CreatedByAccountID string    `bun:"type:CHAR(26),nullzero,notnull"`                              // Account ID of the creator of this block +	CreatedByAccount   *Account  `bun:"rel:belongs-to"`                                              // Account corresponding to createdByAccountID +	PrivateComment     string    `bun:""`                                                            // Private comment on this block, viewable to admins +	PublicComment      string    `bun:""`                                                            // Public comment on this block, viewable (optionally) by everyone +	Obfuscate          *bool     `bun:",nullzero,notnull,default:false"`                             // whether the domain name should appear obfuscated when displaying it publicly +	SubscriptionID     string    `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 7258f64d7..c81eec365 100644 --- a/internal/gtsmodel/emaildomainblock.go +++ b/internal/gtsmodel/emaildomainblock.go @@ -21,10 +21,10 @@ import "time"  // EmailDomainBlock represents a domain that the server should automatically reject sign-up requests from.  type EmailDomainBlock 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:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created -	UpdatedAt          time.Time `validate:"-" bun:"type:timestamptz,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 +	ID                 string    `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt          time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt          time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	Domain             string    `bun:",nullzero,notnull"`                                           // Email domain to block. Eg. 'gmail.com' or 'hotmail.com' +	CreatedByAccountID string    `bun:"type:CHAR(26),nullzero,notnull"`                              // Account ID of the creator of this block +	CreatedByAccount   *Account  `bun:"rel:belongs-to"`                                              // Account corresponding to createdByAccountID  } diff --git a/internal/gtsmodel/emoji.go b/internal/gtsmodel/emoji.go index 0fcc3247b..596a64110 100644 --- a/internal/gtsmodel/emoji.go +++ b/internal/gtsmodel/emoji.go @@ -21,26 +21,26 @@ import "time"  // Emoji represents a custom emoji that's been uploaded through the admin UI or downloaded from a remote instance.  type Emoji 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:timestamptz,nullzero,notnull,default:current_timestamp"`                         // when was item created -	UpdatedAt              time.Time      `validate:"-" bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"`                         // when was item last updated -	Shortcode              string         `validate:"required" bun:",nullzero,notnull,unique:domainshortcode"`                                     // String shortcode for this emoji -- the part that's between colons. This should be a-zA-Z_  eg., 'blob_hug' 'purple_heart' 'Gay_Otter' Must be unique with domain. -	Domain                 string         `validate:"omitempty,fqdn" bun:",nullzero,unique:domainshortcode"`                                       // 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:timestamptz,nullzero,notnull,default:current_timestamp"`                         // When was the emoji image last updated? -	Disabled               *bool          `validate:"-" bun:",nullzero,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:",nullzero,notnull,default:true"`                                                      // Is this emoji visible in the admin emoji picker? -	Category               *EmojiCategory `validate:"-" bun:"rel:belongs-to"`                                                                      // In which emoji category is this emoji visible? -	CategoryID             string         `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"`                                                 // ID of the category this emoji belongs to. -	Cached                 *bool          `validate:"-" bun:",nullzero,notnull,default:false"` +	ID                     string         `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt              time.Time      `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt              time.Time      `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	Shortcode              string         `bun:",nullzero,notnull,unique:domainshortcode"`                    // String shortcode for this emoji -- the part that's between colons. This should be a-zA-Z_  eg., 'blob_hug' 'purple_heart' 'Gay_Otter' Must be unique with domain. +	Domain                 string         `bun:",nullzero,unique:domainshortcode"`                            // Origin domain of this emoji, eg 'example.org', 'queer.party'. empty string for local emojis. +	ImageRemoteURL         string         `bun:",nullzero"`                                                   // Where can this emoji be retrieved remotely? Null for local emojis. +	ImageStaticRemoteURL   string         `bun:",nullzero"`                                                   // Where can a static / non-animated version of this emoji be retrieved remotely? Null for local emojis. +	ImageURL               string         `bun:",nullzero"`                                                   // Where can this emoji be retrieved from the local server? Null for remote emojis. +	ImageStaticURL         string         `bun:",nullzero"`                                                   // Where can a static version of this emoji be retrieved from the local server? Null for remote emojis. +	ImagePath              string         `bun:",nullzero,notnull"`                                           // Path of the emoji image in the server storage system. +	ImageStaticPath        string         `bun:",nullzero,notnull"`                                           // Path of a static version of the emoji image in the server storage system +	ImageContentType       string         `bun:",nullzero,notnull"`                                           // MIME content type of the emoji image +	ImageStaticContentType string         `bun:",nullzero,notnull"`                                           // MIME content type of the static version of the emoji image. +	ImageFileSize          int            `bun:",nullzero,notnull"`                                           // Size of the emoji image file in bytes, for serving purposes. +	ImageStaticFileSize    int            `bun:",nullzero,notnull"`                                           // Size of the static version of the emoji image file in bytes, for serving purposes. +	ImageUpdatedAt         time.Time      `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // When was the emoji image last updated? +	Disabled               *bool          `bun:",nullzero,notnull,default:false"`                             // Has a moderation action disabled this emoji from being shown? +	URI                    string         `bun:",nullzero,notnull,unique"`                                    // ActivityPub uri of this emoji. Something like 'https://example.org/emojis/1234' +	VisibleInPicker        *bool          `bun:",nullzero,notnull,default:true"`                              // Is this emoji visible in the admin emoji picker? +	Category               *EmojiCategory `bun:"rel:belongs-to"`                                              // In which emoji category is this emoji visible? +	CategoryID             string         `bun:"type:CHAR(26),nullzero"`                                      // ID of the category this emoji belongs to. +	Cached                 *bool          `bun:",nullzero,notnull,default:false"`  } diff --git a/internal/gtsmodel/emojicategory.go b/internal/gtsmodel/emojicategory.go index ad17a8600..80a448f3c 100644 --- a/internal/gtsmodel/emojicategory.go +++ b/internal/gtsmodel/emojicategory.go @@ -21,8 +21,8 @@ import "time"  // EmojiCategory represents a grouping of custom emojis.  type EmojiCategory 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:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created -	UpdatedAt time.Time `validate:"-" bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated -	Name      string    `validate:"required" bun:",nullzero,notnull,unique"`                             // name of this category +	ID        string    `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	Name      string    `bun:",nullzero,notnull,unique"`                                    // name of this category  } diff --git a/internal/gtsmodel/follow.go b/internal/gtsmodel/follow.go index 871d01e20..f359a7bc4 100644 --- a/internal/gtsmodel/follow.go +++ b/internal/gtsmodel/follow.go @@ -21,14 +21,14 @@ import "time"  // Follow represents one account following another, and the metadata around that follow.  type Follow 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:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created -	UpdatedAt       time.Time `validate:"-" bun:"type:timestamptz,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,nullzero"` // 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,nullzero"` // Who is the target of this follow ? -	TargetAccount   *Account  `validate:"-" bun:"rel:belongs-to"`                                              // Account corresponding to targetAccountID -	ShowReblogs     *bool     `validate:"-" bun:",nullzero,notnull,default:true"`                              // Does this follow also want to see reblogs and not just posts? -	Notify          *bool     `validate:"-" bun:",nullzero,notnull,default:false"`                             // does the following account want to be notified when the followed account posts? +	ID              string    `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt       time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt       time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	URI             string    `bun:",notnull,nullzero,unique"`                                    // ActivityPub uri of this follow. +	AccountID       string    `bun:"type:CHAR(26),unique:srctarget,notnull,nullzero"`             // Who does this follow originate from? +	Account         *Account  `bun:"rel:belongs-to"`                                              // Account corresponding to accountID +	TargetAccountID string    `bun:"type:CHAR(26),unique:srctarget,notnull,nullzero"`             // Who is the target of this follow ? +	TargetAccount   *Account  `bun:"rel:belongs-to"`                                              // Account corresponding to targetAccountID +	ShowReblogs     *bool     `bun:",nullzero,notnull,default:true"`                              // Does this follow also want to see reblogs and not just posts? +	Notify          *bool     `bun:",nullzero,notnull,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 3fc161af7..32eb13950 100644 --- a/internal/gtsmodel/followrequest.go +++ b/internal/gtsmodel/followrequest.go @@ -21,14 +21,14 @@ import "time"  // FollowRequest represents one account requesting to follow another, and the metadata around that request.  type FollowRequest 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:timestamptz,nullzero,notnull,default:current_timestamp"`   // when was item created -	UpdatedAt       time.Time `validate:"-" bun:"type:timestamptz,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,nullzero"` // 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,nullzero"` // Who is the target of this follow request? -	TargetAccount   *Account  `validate:"-" bun:"rel:belongs-to"`                                                // Account corresponding to targetAccountID -	ShowReblogs     *bool     `validate:"-" bun:",nullzero,notnull,default:true"`                                // Does this follow also want to see reblogs and not just posts? -	Notify          *bool     `validate:"-" bun:",nullzero,notnull,default:false"`                               // does the following account want to be notified when the followed account posts? +	ID              string    `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt       time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt       time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	URI             string    `bun:",notnull,nullzero,unique"`                                    // ActivityPub uri of this follow (request). +	AccountID       string    `bun:"type:CHAR(26),unique:frsrctarget,notnull,nullzero"`           // Who does this follow request originate from? +	Account         *Account  `bun:"rel:belongs-to"`                                              // Account corresponding to accountID +	TargetAccountID string    `bun:"type:CHAR(26),unique:frsrctarget,notnull,nullzero"`           // Who is the target of this follow request? +	TargetAccount   *Account  `bun:"rel:belongs-to"`                                              // Account corresponding to targetAccountID +	ShowReblogs     *bool     `bun:",nullzero,notnull,default:true"`                              // Does this follow also want to see reblogs and not just posts? +	Notify          *bool     `bun:",nullzero,notnull,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 3172726fd..388f0f4ed 100644 --- a/internal/gtsmodel/instance.go +++ b/internal/gtsmodel/instance.go @@ -21,22 +21,22 @@ import "time"  // Instance represents a federated instance, either local or remote.  type Instance 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:timestamptz,nullzero,notnull,default:current_timestamp"`              // when was item created -	UpdatedAt              time.Time    `validate:"-" bun:"type:timestamptz,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:""`                                                                         // 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:timestamptz,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:""`                                                                         // Short description of this instance -	Description            string       `validate:"-" bun:""`                                                                         // Longer description of this instance -	Terms                  string       `validate:"-" bun:""`                                                                         // Terms and conditions of this instance -	ContactEmail           string       `validate:"omitempty,email" bun:""`                                                           // 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 +	ID                     string       `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt              time.Time    `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt              time.Time    `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	Domain                 string       `bun:",nullzero,notnull,unique"`                                    // Instance domain eg example.org +	Title                  string       `bun:""`                                                            // Title of this instance as it would like to be displayed. +	URI                    string       `bun:",nullzero,notnull,unique"`                                    // base URI of this instance eg https://example.org +	SuspendedAt            time.Time    `bun:"type:timestamptz,nullzero"`                                   // When was this instance suspended, if at all? +	DomainBlockID          string       `bun:"type:CHAR(26),nullzero"`                                      // ID of any existing domain block for this instance in the database +	DomainBlock            *DomainBlock `bun:"rel:belongs-to"`                                              // Domain block corresponding to domainBlockID +	ShortDescription       string       `bun:""`                                                            // Short description of this instance +	Description            string       `bun:""`                                                            // Longer description of this instance +	Terms                  string       `bun:""`                                                            // Terms and conditions of this instance +	ContactEmail           string       `bun:""`                                                            // Contact email address for this instance +	ContactAccountUsername string       `bun:",nullzero"`                                                   // Username of the contact account for this instance +	ContactAccountID       string       `bun:"type:CHAR(26),nullzero"`                                      // Contact account ID in the database for this instance +	ContactAccount         *Account     `bun:"rel:belongs-to"`                                              // account corresponding to contactAccountID +	Reputation             int64        `bun:",notnull,default:0"`                                          // Reputation score of this instance +	Version                string       `bun:",nullzero"`                                                   // Version of the software used on this instance  } diff --git a/internal/gtsmodel/list.go b/internal/gtsmodel/list.go index 98188b113..ea53df9b3 100644 --- a/internal/gtsmodel/list.go +++ b/internal/gtsmodel/list.go @@ -21,24 +21,24 @@ import "time"  // List refers to a list of follows for which the owning account wants to view a timeline of posts.  type List 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:timestamptz,nullzero,notnull,default:current_timestamp"`        // when was item created -	UpdatedAt     time.Time     `validate:"-" bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"`        // when was item last updated -	Title         string        `validate:"required" bun:",nullzero,notnull,unique:listaccounttitle"`                   // Title of this list. -	AccountID     string        `validate:"required,ulid" bun:"type:CHAR(26),notnull,nullzero,unique:listaccounttitle"` // Account that created/owns the list -	Account       *Account      `validate:"-" bun:"-"`                                                                  // Account corresponding to accountID -	ListEntries   []*ListEntry  `validate:"-" bun:"-"`                                                                  // Entries contained by this list. -	RepliesPolicy RepliesPolicy `validate:"-" bun:",nullzero,notnull,default:'followed'"`                               // RepliesPolicy for this list. +	ID            string        `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt     time.Time     `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt     time.Time     `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	Title         string        `bun:",nullzero,notnull,unique:listaccounttitle"`                   // Title of this list. +	AccountID     string        `bun:"type:CHAR(26),notnull,nullzero,unique:listaccounttitle"`      // Account that created/owns the list +	Account       *Account      `bun:"-"`                                                           // Account corresponding to accountID +	ListEntries   []*ListEntry  `bun:"-"`                                                           // Entries contained by this list. +	RepliesPolicy RepliesPolicy `bun:",nullzero,notnull,default:'followed'"`                        // RepliesPolicy for this list.  }  // ListEntry refers to a single follow entry in a list.  type ListEntry 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:timestamptz,nullzero,notnull,default:current_timestamp"`           // when was item created -	UpdatedAt time.Time `validate:"-" bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"`           // when was item last updated -	ListID    string    `validate:"required,ulid" bun:"type:CHAR(26),notnull,nullzero,unique:listentrylistfollow"` // ID of the list that this entry belongs to. -	FollowID  string    `validate:"required,ulid" bun:"type:CHAR(26),notnull,nullzero,unique:listentrylistfollow"` // Follow that the account owning this entry wants to see posts of in the timeline. -	Follow    *Follow   `validate:"-" bun:"-"`                                                                     // Follow corresponding to followID. +	ID        string    `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	ListID    string    `bun:"type:CHAR(26),notnull,nullzero,unique:listentrylistfollow"`   // ID of the list that this entry belongs to. +	FollowID  string    `bun:"type:CHAR(26),notnull,nullzero,unique:listentrylistfollow"`   // Follow that the account owning this entry wants to see posts of in the timeline. +	Follow    *Follow   `bun:"-"`                                                           // Follow corresponding to followID.  }  // RepliesPolicy denotes which replies should be shown in the list. diff --git a/internal/gtsmodel/marker.go b/internal/gtsmodel/marker.go index 3aeb376ff..93fbebfe0 100644 --- a/internal/gtsmodel/marker.go +++ b/internal/gtsmodel/marker.go @@ -21,11 +21,11 @@ import "time"  // Marker stores a local account's read position on a given timeline.  type Marker struct { -	AccountID  string     `validate:"required,ulid" bun:"type:CHAR(26),pk,unique:markers_account_id_timeline_uniq,notnull,nullzero"` // ID of the local account that owns the marker -	Name       MarkerName `validate:"oneof=home notifications" bun:",nullzero,notnull,pk,unique:markers_account_id_timeline_uniq"`   // Name of the marked timeline -	UpdatedAt  time.Time  `validate:"required" bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"`                    // When marker was last updated -	Version    int        `validate:"required,min=0" bun:",nullzero,notnull,default:0"`                                              // For optimistic concurrency control -	LastReadID string     `validate:"required,ulid" bun:"type:CHAR(26),notnull,nullzero"`                                            // Last ID read on this timeline (status ID for home, notification ID for notifications) +	AccountID  string     `bun:"type:CHAR(26),pk,unique:markers_account_id_timeline_uniq,notnull,nullzero"` // ID of the local account that owns the marker +	Name       MarkerName `bun:",nullzero,notnull,pk,unique:markers_account_id_timeline_uniq"`              // Name of the marked timeline +	UpdatedAt  time.Time  `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"`               // When marker was last updated +	Version    int        `bun:",nullzero,notnull,default:0"`                                               // For optimistic concurrency control +	LastReadID string     `bun:"type:CHAR(26),notnull,nullzero"`                                            // Last ID read on this timeline (status ID for home, notification ID for notifications)  }  // MarkerName is the name of one of the timelines we can store markers for. diff --git a/internal/gtsmodel/mediaattachment.go b/internal/gtsmodel/mediaattachment.go index b8e8b57f7..e418de7d2 100644 --- a/internal/gtsmodel/mediaattachment.go +++ b/internal/gtsmodel/mediaattachment.go @@ -24,42 +24,42 @@ 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                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:timestamptz,nullzero,notnull,default:current_timestamp"`                // when was item created -	UpdatedAt         time.Time        `validate:"-" bun:"type:timestamptz,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 Gifv Audio Video Unknown" bun:",nullzero,notnull"`                       // Type of file (image/gifv/audio/video) -	FileMeta          FileMeta         `validate:"required" bun:",embed:,nullzero,notnull"`                                            // Metadata about the file -	AccountID         string           `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"`                                 // To which account does this attachment belong -	Description       string           `validate:"-" bun:""`                                                                           // 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:",embed:file_,notnull,nullzero"`                                       // metadata for the whole file -	Thumbnail         Thumbnail        `validate:"required" bun:",embed:thumbnail_,notnull,nullzero"`                                  // small image thumbnail derived from a larger image, video, or audio file. -	Avatar            *bool            `validate:"-" bun:",nullzero,notnull,default:false"`                                            // Is this attachment being used as an avatar? -	Header            *bool            `validate:"-" bun:",nullzero,notnull,default:false"`                                            // Is this attachment being used as a header? -	Cached            *bool            `validate:"-" bun:",nullzero,notnull,default:false"`                                            // Is this attachment currently cached by our instance? +	ID                string           `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt         time.Time        `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt         time.Time        `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	StatusID          string           `bun:"type:CHAR(26),nullzero"`                                      // ID of the status to which this is attached +	URL               string           `bun:",nullzero"`                                                   // Where can the attachment be retrieved on *this* server +	RemoteURL         string           `bun:",nullzero"`                                                   // Where can the attachment be retrieved on a remote server (empty for local media) +	Type              FileType         `bun:",nullzero,notnull"`                                           // Type of file (image/gifv/audio/video) +	FileMeta          FileMeta         `bun:",embed:,nullzero,notnull"`                                    // Metadata about the file +	AccountID         string           `bun:"type:CHAR(26),nullzero,notnull"`                              // To which account does this attachment belong +	Description       string           `bun:""`                                                            // Description of the attachment (for screenreaders) +	ScheduledStatusID string           `bun:"type:CHAR(26),nullzero"`                                      // To which scheduled status does this attachment belong +	Blurhash          string           `bun:",nullzero"`                                                   // What is the generated blurhash of this attachment +	Processing        ProcessingStatus `bun:",notnull,default:2"`                                          // What is the processing status of this attachment +	File              File             `bun:",embed:file_,notnull,nullzero"`                               // metadata for the whole file +	Thumbnail         Thumbnail        `bun:",embed:thumbnail_,notnull,nullzero"`                          // small image thumbnail derived from a larger image, video, or audio file. +	Avatar            *bool            `bun:",nullzero,notnull,default:false"`                             // Is this attachment being used as an avatar? +	Header            *bool            `bun:",nullzero,notnull,default:false"`                             // Is this attachment being used as a header? +	Cached            *bool            `bun:",nullzero,notnull,default:false"`                             // Is this attachment currently cached by our instance?  }  // File refers to the metadata for the whole file  type File struct { -	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:",notnull"`                                             // File size in bytes -	UpdatedAt   time.Time `validate:"-" bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // When was the file last updated. +	Path        string    `bun:",nullzero,notnull"`                                           // Path of the file in storage. +	ContentType string    `bun:",nullzero,notnull"`                                           // MIME content type of the file. +	FileSize    int       `bun:",notnull"`                                                    // File size in bytes +	UpdatedAt   time.Time `bun:"type:timestamptz,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 { -	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:",notnull"`                                             // File size in bytes -	UpdatedAt   time.Time `validate:"-" bun:"type:timestamptz,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) +	Path        string    `bun:",nullzero,notnull"`                                           // Path of the file in storage. +	ContentType string    `bun:",nullzero,notnull"`                                           // MIME content type of the file. +	FileSize    int       `bun:",notnull"`                                                    // File size in bytes +	UpdatedAt   time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // When was the file last updated. +	URL         string    `bun:",nullzero"`                                                   // What is the URL of the thumbnail on the local server +	RemoteURL   string    `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. @@ -87,33 +87,33 @@ const (  // FileMeta describes metadata about the actual contents of the file.  type FileMeta struct { -	Original Original `validate:"required" bun:"embed:original_"` +	Original Original `bun:"embed:original_"`  	Small    Small    `bun:"embed:small_"`  	Focus    Focus    `bun:"embed:focus_"`  }  // Small can be used for a thumbnail of any media type  type Small struct { -	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 float32 `validate:"required_with=Width Height Size"`   // aspect ratio (width / height) +	Width  int     // width in pixels +	Height int     // height in pixels +	Size   int     // size in pixels (width * height) +	Aspect float32 // aspect ratio (width / height)  }  // Original can be used for original metadata for any media type  type Original struct { -	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    float32  `validate:"required_with=Width Height Size"`   // aspect ratio (width / height) -	Duration  *float32 `validate:"-"`                                 // video-specific: duration of the video in seconds -	Framerate *float32 `validate:"-"`                                 // video-specific: fps -	Bitrate   *uint64  `validate:"-"`                                 // video-specific: bitrate +	Width     int      // width in pixels +	Height    int      // height in pixels +	Size      int      // size in pixels (width * height) +	Aspect    float32  // aspect ratio (width / height) +	Duration  *float32 // video-specific: duration of the video in seconds +	Framerate *float32 // video-specific: fps +	Bitrate   *uint64  // video-specific: bitrate  }  // 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 `validate:"omitempty,max=1,min=-1"` -	Y float32 `validate:"omitempty,max=1,min=-1"` +	X float32 +	Y float32  } diff --git a/internal/gtsmodel/mention.go b/internal/gtsmodel/mention.go index 9ad9204eb..fb7f3b51a 100644 --- a/internal/gtsmodel/mention.go +++ b/internal/gtsmodel/mention.go @@ -24,17 +24,17 @@ import (  // Mention refers to the 'tagging' or 'mention' of a user within a status.  type Mention 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:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created -	UpdatedAt        time.Time `validate:"-" bun:"type:timestamptz,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:",nullzero,notnull,default:false"`                             // Prevent this mention from generating a notification? +	ID               string    `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt        time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt        time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	StatusID         string    `bun:"type:CHAR(26),nullzero,notnull"`                              // ID of the status this mention originates from +	Status           *Status   `bun:"rel:belongs-to"`                                              // status referred to by statusID +	OriginAccountID  string    `bun:"type:CHAR(26),nullzero,notnull"`                              // ID of the mention creator account +	OriginAccountURI string    `bun:",nullzero,notnull"`                                           // ActivityPub URI of the originator/creator of the mention +	OriginAccount    *Account  `bun:"rel:belongs-to"`                                              // account referred to by originAccountID +	TargetAccountID  string    `bun:"type:CHAR(26),nullzero,notnull"`                              // Mention target/receiver account ID +	TargetAccount    *Account  `bun:"rel:belongs-to"`                                              // account referred to by targetAccountID +	Silent           *bool     `bun:",nullzero,notnull,default:false"`                             // Prevent this mention from generating a notification?  	/*  		NON-DATABASE CONVENIENCE FIELDS @@ -48,15 +48,15 @@ type Mention struct {  	// @whatever_username@example.org  	//  	// This will not be put in the database, it's just for convenience. -	NameString string `validate:"-" bun:"-"` +	NameString string `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 `validate:"-" bun:"-"` +	TargetAccountURI string `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 `validate:"-" bun:"-"` +	TargetAccountURL string `bun:"-"`  	// A pointer to the gtsmodel account of the mentioned account.  } diff --git a/internal/gtsmodel/notification.go b/internal/gtsmodel/notification.go index 7e8db7713..5e2eff167 100644 --- a/internal/gtsmodel/notification.go +++ b/internal/gtsmodel/notification.go @@ -21,17 +21,17 @@ 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               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:timestamptz,nullzero,notnull,default:current_timestamp"`                                                                                                                             // when was item created -	UpdatedAt        time.Time        `validate:"-" bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"`                                                                                                                             // when was item last updated -	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"`                                                                                                                                                       // ID of the account targeted by the notification (ie., who will receive the notification?) -	TargetAccount    *Account         `validate:"-" bun:"-"`                                                                                                                                                                                       // Account corresponding to TargetAccountID. Can be nil, always check first + select using ID if necessary. -	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:"-"`                                                                                                                                                                                       // Account corresponding to OriginAccountID. Can be nil, always check first + select using ID if necessary. -	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:"-"`                                                                                                                                                                                       // Status corresponding to StatusID. Can be nil, always check first + select using ID if necessary. -	Read             *bool            `validate:"-" bun:",nullzero,notnull,default:false"`                                                                                                                                                         // Notification has been seen/read +	ID               string           `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt        time.Time        `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt        time.Time        `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	NotificationType NotificationType `bun:",nullzero,notnull"`                                           // Type of this notification +	TargetAccountID  string           `bun:"type:CHAR(26),nullzero,notnull"`                              // ID of the account targeted by the notification (ie., who will receive the notification?) +	TargetAccount    *Account         `bun:"-"`                                                           // Account corresponding to TargetAccountID. Can be nil, always check first + select using ID if necessary. +	OriginAccountID  string           `bun:"type:CHAR(26),nullzero,notnull"`                              // ID of the account that performed the action that created the notification. +	OriginAccount    *Account         `bun:"-"`                                                           // Account corresponding to OriginAccountID. Can be nil, always check first + select using ID if necessary. +	StatusID         string           `bun:"type:CHAR(26),nullzero"`                                      // If the notification pertains to a status, what is the database ID of that status? +	Status           *Status          `bun:"-"`                                                           // Status corresponding to StatusID. Can be nil, always check first + select using ID if necessary. +	Read             *bool            `bun:",nullzero,notnull,default:false"`                             // Notification has been seen/read  }  // NotificationType describes the reason/type of this notification. diff --git a/internal/gtsmodel/report.go b/internal/gtsmodel/report.go index eb45c820c..e5b942563 100644 --- a/internal/gtsmodel/report.go +++ b/internal/gtsmodel/report.go @@ -26,20 +26,20 @@ import "time"  // or another instance, OR a report that was created remotely (on another instance)  // about a user on this instance, and received via the federated (s2s) API.  type Report 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:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created -	UpdatedAt              time.Time `validate:"-" bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated -	URI                    string    `validate:"required,url" bun:",unique,nullzero,notnull"`                         // activitypub URI of this report -	AccountID              string    `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"`                  // which account created this report -	Account                *Account  `validate:"-" bun:"-"`                                                           // account corresponding to AccountID -	TargetAccountID        string    `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"`                  // which account is targeted by this report -	TargetAccount          *Account  `validate:"-" bun:"-"`                                                           // account corresponding to TargetAccountID -	Comment                string    `validate:"-" bun:",nullzero"`                                                   // comment / explanation for this report, by the reporter -	StatusIDs              []string  `validate:"dive,ulid" bun:"statuses,array"`                                      // database IDs of any statuses referenced by this report -	Statuses               []*Status `validate:"-" bun:"-"`                                                           // statuses corresponding to StatusIDs -	Forwarded              *bool     `validate:"-" bun:",nullzero,notnull,default:false"`                             // flag to indicate report should be forwarded to remote instance -	ActionTaken            string    `validate:"-" bun:",nullzero"`                                                   // string description of what action was taken in response to this report -	ActionTakenAt          time.Time `validate:"-" bun:"type:timestamptz,nullzero"`                                   // time at which action was taken, if any -	ActionTakenByAccountID string    `validate:",omitempty,ulid" bun:"type:CHAR(26),nullzero"`                        // database ID of account which took action, if any -	ActionTakenByAccount   *Account  `validate:"-" bun:"-"`                                                           // account corresponding to ActionTakenByID, if any +	ID                     string    `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt              time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt              time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	URI                    string    `bun:",unique,nullzero,notnull"`                                    // activitypub URI of this report +	AccountID              string    `bun:"type:CHAR(26),nullzero,notnull"`                              // which account created this report +	Account                *Account  `bun:"-"`                                                           // account corresponding to AccountID +	TargetAccountID        string    `bun:"type:CHAR(26),nullzero,notnull"`                              // which account is targeted by this report +	TargetAccount          *Account  `bun:"-"`                                                           // account corresponding to TargetAccountID +	Comment                string    `bun:",nullzero"`                                                   // comment / explanation for this report, by the reporter +	StatusIDs              []string  `bun:"statuses,array"`                                              // database IDs of any statuses referenced by this report +	Statuses               []*Status `bun:"-"`                                                           // statuses corresponding to StatusIDs +	Forwarded              *bool     `bun:",nullzero,notnull,default:false"`                             // flag to indicate report should be forwarded to remote instance +	ActionTaken            string    `bun:",nullzero"`                                                   // string description of what action was taken in response to this report +	ActionTakenAt          time.Time `bun:"type:timestamptz,nullzero"`                                   // time at which action was taken, if any +	ActionTakenByAccountID string    `bun:"type:CHAR(26),nullzero"`                                      // database ID of account which took action, if any +	ActionTakenByAccount   *Account  `bun:"-"`                                                           // account corresponding to ActionTakenByID, if any  } diff --git a/internal/gtsmodel/routersession.go b/internal/gtsmodel/routersession.go index 050c0715b..d51d93bca 100644 --- a/internal/gtsmodel/routersession.go +++ b/internal/gtsmodel/routersession.go @@ -21,9 +21,9 @@ import "time"  // RouterSession is used to store and retrieve settings for a router session.  type RouterSession 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:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created -	UpdatedAt time.Time `validate:"-" bun:"type:timestamptz,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"` +	ID        string    `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	Auth      []byte    `bun:"type:bytea,notnull,nullzero"` +	Crypt     []byte    `bun:"type:bytea,notnull,nullzero"`  } diff --git a/internal/gtsmodel/status.go b/internal/gtsmodel/status.go index 393bb1ac7..3e8880798 100644 --- a/internal/gtsmodel/status.go +++ b/internal/gtsmodel/status.go @@ -25,47 +25,47 @@ import (  // Status represents a user-created 'post' or 'status' in the database, either remote or local  type Status 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:timestamptz,nullzero,notnull,default:current_timestamp"`                       // when was item created -	UpdatedAt                time.Time          `validate:"-" bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"`                       // when was item last updated -	FetchedAt                time.Time          `validate:"required_with=!Local" bun:"type:timestamptz,nullzero"`                                      // when was item (remote) last fetched. -	PinnedAt                 time.Time          `validate:"-" bun:"type:timestamptz,nullzero"`                                                         // Status was pinned by owning account at this time. -	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:""`                                                                                  // 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:",nullzero,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:"oneof=public unlocked followers_only mutuals_only direct" bun:",nullzero,notnull"`          // visibility entry for this status -	Sensitive                *bool              `validate:"-" bun:",nullzero,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 -	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:""`                                                                                  // Original text of the status without formatting -	Federated                *bool              `validate:"-" bun:",notnull"`                                                                          // This status will be federated beyond the local timeline(s) -	Boostable                *bool              `validate:"-" bun:",notnull"`                                                                          // This status can be boosted/reblogged -	Replyable                *bool              `validate:"-" bun:",notnull"`                                                                          // This status can be replied to -	Likeable                 *bool              `validate:"-" bun:",notnull"`                                                                          // This status can be liked/faved +	ID                       string             `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt                time.Time          `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt                time.Time          `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	FetchedAt                time.Time          `bun:"type:timestamptz,nullzero"`                                   // when was item (remote) last fetched. +	PinnedAt                 time.Time          `bun:"type:timestamptz,nullzero"`                                   // Status was pinned by owning account at this time. +	URI                      string             `bun:",unique,nullzero,notnull"`                                    // activitypub URI of this status +	URL                      string             `bun:",nullzero"`                                                   // web url for viewing this status +	Content                  string             `bun:""`                                                            // content of this status; likely html-formatted but not guaranteed +	AttachmentIDs            []string           `bun:"attachments,array"`                                           // Database IDs of any media attachments associated with this status +	Attachments              []*MediaAttachment `bun:"attached_media,rel:has-many"`                                 // Attachments corresponding to attachmentIDs +	TagIDs                   []string           `bun:"tags,array"`                                                  // Database IDs of any tags used in this status +	Tags                     []*Tag             `bun:"attached_tags,m2m:status_to_tags"`                            // Tags corresponding to tagIDs. https://bun.uptrace.dev/guide/relations.html#many-to-many-relation +	MentionIDs               []string           `bun:"mentions,array"`                                              // Database IDs of any mentions in this status +	Mentions                 []*Mention         `bun:"attached_mentions,rel:has-many"`                              // Mentions corresponding to mentionIDs +	EmojiIDs                 []string           `bun:"emojis,array"`                                                // Database IDs of any emojis used in this status +	Emojis                   []*Emoji           `bun:"attached_emojis,m2m:status_to_emojis"`                        // Emojis corresponding to emojiIDs. https://bun.uptrace.dev/guide/relations.html#many-to-many-relation +	Local                    *bool              `bun:",nullzero,notnull,default:false"`                             // is this status from a local account? +	AccountID                string             `bun:"type:CHAR(26),nullzero,notnull"`                              // which account posted this status? +	Account                  *Account           `bun:"rel:belongs-to"`                                              // account corresponding to accountID +	AccountURI               string             `bun:",nullzero,notnull"`                                           // activitypub uri of the owner of this status +	InReplyToID              string             `bun:"type:CHAR(26),nullzero"`                                      // id of the status this status replies to +	InReplyToURI             string             `bun:",nullzero"`                                                   // activitypub uri of the status this status is a reply to +	InReplyToAccountID       string             `bun:"type:CHAR(26),nullzero"`                                      // id of the account that this status replies to +	InReplyTo                *Status            `bun:"-"`                                                           // status corresponding to inReplyToID +	InReplyToAccount         *Account           `bun:"rel:belongs-to"`                                              // account corresponding to inReplyToAccountID +	BoostOfID                string             `bun:"type:CHAR(26),nullzero"`                                      // id of the status this status is a boost of +	BoostOfAccountID         string             `bun:"type:CHAR(26),nullzero"`                                      // id of the account that owns the boosted status +	BoostOf                  *Status            `bun:"-"`                                                           // status that corresponds to boostOfID +	BoostOfAccount           *Account           `bun:"rel:belongs-to"`                                              // account that corresponds to boostOfAccountID +	ContentWarning           string             `bun:",nullzero"`                                                   // cw string for this status +	Visibility               Visibility         `bun:",nullzero,notnull"`                                           // visibility entry for this status +	Sensitive                *bool              `bun:",nullzero,notnull,default:false"`                             // mark the status as sensitive? +	Language                 string             `bun:",nullzero"`                                                   // what language is this status written in? +	CreatedWithApplicationID string             `bun:"type:CHAR(26),nullzero"`                                      // Which application was used to create this status? +	CreatedWithApplication   *Application       `bun:"rel:belongs-to"`                                              // application corresponding to createdWithApplicationID +	ActivityStreamsType      string             `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             `bun:""`                                                            // Original text of the status without formatting +	Federated                *bool              `bun:",notnull"`                                                    // This status will be federated beyond the local timeline(s) +	Boostable                *bool              `bun:",notnull"`                                                    // This status can be boosted/reblogged +	Replyable                *bool              `bun:",notnull"`                                                    // This status can be replied to +	Likeable                 *bool              `bun:",notnull"`                                                    // This status can be liked/faved  }  // GetID implements timeline.Timelineable{}. @@ -252,18 +252,18 @@ func (s *Status) MentionsAccount(id string) bool {  // StatusToTag is an intermediate struct to facilitate the many2many relationship between a status and one or more tags.  type StatusToTag struct { -	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"` +	StatusID string  `bun:"type:CHAR(26),unique:statustag,nullzero,notnull"` +	Status   *Status `bun:"rel:belongs-to"` +	TagID    string  `bun:"type:CHAR(26),unique:statustag,nullzero,notnull"` +	Tag      *Tag    `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  `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"` +	StatusID string  `bun:"type:CHAR(26),unique:statusemoji,nullzero,notnull"` +	Status   *Status `bun:"rel:belongs-to"` +	EmojiID  string  `bun:"type:CHAR(26),unique:statusemoji,nullzero,notnull"` +	Emoji    *Emoji  `bun:"rel:belongs-to"`  }  // Visibility represents the visibility granularity of a status. diff --git a/internal/gtsmodel/statusbookmark.go b/internal/gtsmodel/statusbookmark.go index 6141b6e34..c7590a5c3 100644 --- a/internal/gtsmodel/statusbookmark.go +++ b/internal/gtsmodel/statusbookmark.go @@ -21,13 +21,13 @@ import "time"  // StatusBookmark refers to one account having a 'bookmark' of the status of another account.  type StatusBookmark 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:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created -	UpdatedAt       time.Time `validate:"-" bun:"type:timestamptz,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 +	ID              string    `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt       time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt       time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	AccountID       string    `bun:"type:CHAR(26),nullzero,notnull"`                              // id of the account that created ('did') the bookmark +	Account         *Account  `bun:"rel:belongs-to"`                                              // account that created the bookmark +	TargetAccountID string    `bun:"type:CHAR(26),nullzero,notnull"`                              // id the account owning the bookmarked status +	TargetAccount   *Account  `bun:"rel:belongs-to"`                                              // account owning the bookmarked status +	StatusID        string    `bun:"type:CHAR(26),nullzero,notnull"`                              // database id of the status that has been bookmarked +	Status          *Status   `bun:"rel:belongs-to"`                                              // the bookmarked status  } diff --git a/internal/gtsmodel/statusfave.go b/internal/gtsmodel/statusfave.go index 86096ef5e..f81226f8b 100644 --- a/internal/gtsmodel/statusfave.go +++ b/internal/gtsmodel/statusfave.go @@ -21,14 +21,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              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:timestamptz,nullzero,notnull,default:current_timestamp"`               // when was item created -	UpdatedAt       time.Time `validate:"-" bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"`               // when was item last updated -	AccountID       string    `validate:"required,ulid" bun:"type:CHAR(26),unique:statusfaveaccountstatus,nullzero,notnull"` // id of the account that created ('did') the fave -	Account         *Account  `validate:"-" bun:"-"`                                                                         // 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:"-"`                                                                         // account owning the faved status -	StatusID        string    `validate:"required,ulid" bun:"type:CHAR(26),unique:statusfaveaccountstatus,nullzero,notnull"` // database id of the status that has been 'faved' -	Status          *Status   `validate:"-" bun:"-"`                                                                         // the faved status -	URI             string    `validate:"required,url" bun:",nullzero,notnull,unique"`                                       // ActivityPub URI of this fave +	ID              string    `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                      // id of this item in the database +	CreatedAt       time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"`   // when was item created +	UpdatedAt       time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"`   // when was item last updated +	AccountID       string    `bun:"type:CHAR(26),unique:statusfaveaccountstatus,nullzero,notnull"` // id of the account that created ('did') the fave +	Account         *Account  `bun:"-"`                                                             // account that created the fave +	TargetAccountID string    `bun:"type:CHAR(26),nullzero,notnull"`                                // id the account owning the faved status +	TargetAccount   *Account  `bun:"-"`                                                             // account owning the faved status +	StatusID        string    `bun:"type:CHAR(26),unique:statusfaveaccountstatus,nullzero,notnull"` // database id of the status that has been 'faved' +	Status          *Status   `bun:"-"`                                                             // the faved status +	URI             string    `bun:",nullzero,notnull,unique"`                                      // ActivityPub URI of this fave  } diff --git a/internal/gtsmodel/statusmute.go b/internal/gtsmodel/statusmute.go index 27af921e4..b8aca1c7a 100644 --- a/internal/gtsmodel/statusmute.go +++ b/internal/gtsmodel/statusmute.go @@ -21,13 +21,13 @@ import "time"  // StatusMute refers to one account having muted the status of another account or its own.  type StatusMute 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:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created -	UpdatedAt       time.Time `validate:"-" bun:"type:timestamptz,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 +	ID              string    `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt       time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt       time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	AccountID       string    `bun:"type:CHAR(26),nullzero,notnull"`                              // id of the account that created ('did') the mute +	Account         *Account  `bun:"rel:belongs-to"`                                              // pointer to the account specified by accountID +	TargetAccountID string    `bun:"type:CHAR(26),nullzero,notnull"`                              // id the account owning the muted status (can be the same as accountID) +	TargetAccount   *Account  `bun:"rel:belongs-to"`                                              // pointer to the account specified by targetAccountID +	StatusID        string    `bun:"type:CHAR(26),nullzero,notnull"`                              // database id of the status that has been muted +	Status          *Status   `bun:"rel:belongs-to"`                                              // pointer to the muted status specified by statusID  } diff --git a/internal/gtsmodel/tag.go b/internal/gtsmodel/tag.go index a43c4a5ec..514389f23 100644 --- a/internal/gtsmodel/tag.go +++ b/internal/gtsmodel/tag.go @@ -21,10 +21,10 @@ import "time"  // Tag represents a hashtag for gathering public statuses together.  type Tag 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:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created -	UpdatedAt time.Time `validate:"-" bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated -	Name      string    `validate:"required" bun:",unique,nullzero,notnull"`                             // (lowercase) name of the tag without the hash prefix -	Useable   *bool     `validate:"-" bun:",nullzero,notnull,default:true"`                              // Tag is useable on this instance. -	Listable  *bool     `validate:"-" bun:",nullzero,notnull,default:true"`                              // Tagged statuses can be listed on this instance. +	ID        string    `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	Name      string    `bun:",unique,nullzero,notnull"`                                    // (lowercase) name of the tag without the hash prefix +	Useable   *bool     `bun:",nullzero,notnull,default:true"`                              // Tag is useable on this instance. +	Listable  *bool     `bun:",nullzero,notnull,default:true"`                              // Tagged statuses can be listed on this instance.  } diff --git a/internal/gtsmodel/token.go b/internal/gtsmodel/token.go index 06db7e394..fd640abde 100644 --- a/internal/gtsmodel/token.go +++ b/internal/gtsmodel/token.go @@ -21,22 +21,22 @@ 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:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created -	UpdatedAt           time.Time `validate:"-" bun:"type:timestamptz,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"`                          // 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:",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:timestamptz,nullzero"`                  // Code created time, if code present -	CodeExpiresAt       time.Time `validate:"-" bun:"type:timestamptz,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:timestamptz,nullzero"`                // User level access token created time, if access present -	AccessExpiresAt     time.Time `validate:"-" bun:"type:timestamptz,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:timestamptz,nullzero"`               // Refresh created at, if refresh present -	RefreshExpiresAt    time.Time `validate:"-" bun:"type:timestamptz,nullzero"`                                   // Refresh expires at -- null means the refresh token never expires +	ID                  string    `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt           time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt           time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	ClientID            string    `bun:"type:CHAR(26),nullzero,notnull"`                              // ID of the client who owns this token +	UserID              string    `bun:"type:CHAR(26),nullzero"`                                      // ID of the user who owns this token +	RedirectURI         string    `bun:",nullzero,notnull"`                                           // Oauth redirect URI for this token +	Scope               string    `bun:",notnull"`                                                    // Oauth scope +	Code                string    `bun:",pk,nullzero,notnull,default:''"`                             // Code, if present +	CodeChallenge       string    `bun:",nullzero"`                                                   // Code challenge, if code present +	CodeChallengeMethod string    `bun:",nullzero"`                                                   // Code challenge method, if code present +	CodeCreateAt        time.Time `bun:"type:timestamptz,nullzero"`                                   // Code created time, if code present +	CodeExpiresAt       time.Time `bun:"type:timestamptz,nullzero"`                                   // Code expires at -- null means the code never expires +	Access              string    `bun:",pk,nullzero,notnull,default:''"`                             // User level access token, if present +	AccessCreateAt      time.Time `bun:"type:timestamptz,nullzero"`                                   // User level access token created time, if access present +	AccessExpiresAt     time.Time `bun:"type:timestamptz,nullzero"`                                   // User level access token expires at -- null means the token never expires +	Refresh             string    `bun:",pk,nullzero,notnull,default:''"`                             // Refresh token, if present +	RefreshCreateAt     time.Time `bun:"type:timestamptz,nullzero"`                                   // Refresh created at, if refresh present +	RefreshExpiresAt    time.Time `bun:"type:timestamptz,nullzero"`                                   // Refresh expires at -- null means the refresh token never expires  } diff --git a/internal/gtsmodel/tombstone.go b/internal/gtsmodel/tombstone.go index f7e1c2504..7c6af6de3 100644 --- a/internal/gtsmodel/tombstone.go +++ b/internal/gtsmodel/tombstone.go @@ -29,9 +29,9 @@ import (  // It's useful in cases where a remote account has been deleted, and we don't want to keep trying to process  // subsequent activities from that account, or deletes which target it.  type Tombstone 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:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created -	UpdatedAt time.Time `validate:"-" bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated -	Domain    string    `validate:"omitempty,fqdn" bun:",nullzero,notnull"`                              // Domain of the Object/Actor. -	URI       string    `validate:"required,url" bun:",nullzero,notnull,unique"`                         // ActivityPub URI for this Object/Actor. +	ID        string    `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	Domain    string    `bun:",nullzero,notnull"`                                           // Domain of the Object/Actor. +	URI       string    `bun:",nullzero,notnull,unique"`                                    // ActivityPub URI for this Object/Actor.  } diff --git a/internal/gtsmodel/user.go b/internal/gtsmodel/user.go index 2f2029636..16c4d4ee2 100644 --- a/internal/gtsmodel/user.go +++ b/internal/gtsmodel/user.go @@ -25,35 +25,35 @@ 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 { -	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:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created -	UpdatedAt              time.Time    `validate:"-" bun:"type:timestamptz,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:timestamptz,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:timestamptz,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:",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:timestamptz,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:timestamptz,nullzero"`     // When did we send email confirmation to this user? -	ConfirmedAt            time.Time    `validate:"required_with=Email" bun:"type:timestamptz,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:",nullzero,notnull,default:false"`                             // Is this user a moderator? -	Admin                  *bool        `validate:"-" bun:",nullzero,notnull,default:false"`                             // Is this user an admin? -	Disabled               *bool        `validate:"-" bun:",nullzero,notnull,default:false"`                             // Is this user disabled from posting? -	Approved               *bool        `validate:"-" bun:",nullzero,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:timestamptz,nullzero"`    // When did we email the user their reset-password email? -	ExternalID             string       `validate:"-" bun:",nullzero,unique"`                                            // If the login for the user is managed externally (e.g OIDC), we need to keep a stable reference to the external object (e.g OIDC sub claim) +	ID                     string       `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt              time.Time    `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt              time.Time    `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	Email                  string       `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       `bun:"type:CHAR(26),nullzero,notnull,unique"`                       // The id of the local gtsmodel.Account entry for this user. +	Account                *Account     `bun:"rel:belongs-to"`                                              // Pointer to the account of this user that corresponds to AccountID. +	EncryptedPassword      string       `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       `bun:",nullzero"`                                                   // From what IP was this user created? +	CurrentSignInAt        time.Time    `bun:"type:timestamptz,nullzero"`                                   // When did the user sign in with their current session. +	CurrentSignInIP        net.IP       `bun:",nullzero"`                                                   // What's the most recent IP of this user +	LastSignInAt           time.Time    `bun:"type:timestamptz,nullzero"`                                   // When did this user last sign in? +	LastSignInIP           net.IP       `bun:",nullzero"`                                                   // What's the previous IP of this user? +	SignInCount            int          `bun:",notnull,default:0"`                                          // How many times has this user signed in? +	InviteID               string       `bun:"type:CHAR(26),nullzero"`                                      // id of the user who invited this user (who let this joker in?) +	ChosenLanguages        []string     `bun:",nullzero"`                                                   // What languages does this user want to see? +	FilteredLanguages      []string     `bun:",nullzero"`                                                   // What languages does this user not want to see? +	Locale                 string       `bun:",nullzero"`                                                   // In what timezone/locale is this user located? +	CreatedByApplicationID string       `bun:"type:CHAR(26),nullzero"`                                      // Which application id created this user? See gtsmodel.Application +	CreatedByApplication   *Application `bun:"rel:belongs-to"`                                              // Pointer to the application corresponding to createdbyapplicationID. +	LastEmailedAt          time.Time    `bun:"type:timestamptz,nullzero"`                                   // When was this user last contacted by email. +	ConfirmationToken      string       `bun:",nullzero"`                                                   // What confirmation token did we send this user/what are we expecting back? +	ConfirmationSentAt     time.Time    `bun:"type:timestamptz,nullzero"`                                   // When did we send email confirmation to this user? +	ConfirmedAt            time.Time    `bun:"type:timestamptz,nullzero"`                                   // When did the user confirm their email address +	UnconfirmedEmail       string       `bun:",nullzero"`                                                   // Email address that hasn't yet been confirmed +	Moderator              *bool        `bun:",nullzero,notnull,default:false"`                             // Is this user a moderator? +	Admin                  *bool        `bun:",nullzero,notnull,default:false"`                             // Is this user an admin? +	Disabled               *bool        `bun:",nullzero,notnull,default:false"`                             // Is this user disabled from posting? +	Approved               *bool        `bun:",nullzero,notnull,default:false"`                             // Has this user been approved by a moderator? +	ResetPasswordToken     string       `bun:",nullzero"`                                                   // The generated token that the user can use to reset their password +	ResetPasswordSentAt    time.Time    `bun:"type:timestamptz,nullzero"`                                   // When did we email the user their reset-password email? +	ExternalID             string       `bun:",nullzero,unique"`                                            // If the login for the user is managed externally (e.g OIDC), we need to keep a stable reference to the external object (e.g OIDC sub claim)  } diff --git a/internal/validate/account_test.go b/internal/validate/account_test.go deleted file mode 100644 index 57f0f4900..000000000 --- a/internal/validate/account_test.go +++ /dev/null @@ -1,343 +0,0 @@ -// GoToSocial -// Copyright (C) GoToSocial Authors admin@gotosocial.org -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// 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 validate_test - -import ( -	"crypto/rand" -	"crypto/rsa" -	"testing" -	"time" - -	"github.com/stretchr/testify/suite" -	"github.com/superseriousbusiness/gotosocial/internal/ap" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" -	"github.com/superseriousbusiness/gotosocial/internal/validate" -	"github.com/superseriousbusiness/gotosocial/testrig" -) - -func happyAccount() *gtsmodel.Account { -	priv, err := rsa.GenerateKey(rand.Reader, 2048) -	if err != nil { -		panic(err) -	} -	pub := &priv.PublicKey - -	return >smodel.Account{ -		ID:                      "01F8MH1H7YV1Z7D2C8K2730QBF", -		CreatedAt:               time.Now().Add(-48 * time.Hour), -		UpdatedAt:               time.Now().Add(-48 * time.Hour), -		Username:                "the_mighty_zork", -		Domain:                  "", -		AvatarMediaAttachmentID: "01F8MH58A357CV5K7R7TJMSH6S", -		AvatarMediaAttachment:   nil, -		AvatarRemoteURL:         "", -		HeaderMediaAttachmentID: "01PFPMWK2FF0D9WMHEJHR07C3Q", -		HeaderMediaAttachment:   nil, -		HeaderRemoteURL:         "", -		DisplayName:             "original zork (he/they)", -		Fields:                  []*gtsmodel.Field{}, -		Note:                    "hey yo this is my profile!", -		Memorial:                testrig.FalseBool(), -		AlsoKnownAs:             "", -		MovedToAccountID:        "", -		Bot:                     testrig.FalseBool(), -		Reason:                  "I wanna be on this damned webbed site so bad! Please! Wow", -		Locked:                  testrig.FalseBool(), -		Discoverable:            testrig.TrueBool(), -		Privacy:                 gtsmodel.VisibilityPublic, -		Sensitive:               testrig.FalseBool(), -		Language:                "en", -		StatusContentType:       "text/plain", -		URI:                     "http://localhost:8080/users/the_mighty_zork", -		URL:                     "http://localhost:8080/@the_mighty_zork", -		FetchedAt:               time.Time{}, -		InboxURI:                "http://localhost:8080/users/the_mighty_zork/inbox", -		OutboxURI:               "http://localhost:8080/users/the_mighty_zork/outbox", -		FollowersURI:            "http://localhost:8080/users/the_mighty_zork/followers", -		FollowingURI:            "http://localhost:8080/users/the_mighty_zork/following", -		FeaturedCollectionURI:   "http://localhost:8080/users/the_mighty_zork/collections/featured", -		ActorType:               ap.ActorPerson, -		PrivateKey:              priv, -		PublicKey:               pub, -		PublicKeyURI:            "http://localhost:8080/users/the_mighty_zork#main-key", -		SensitizedAt:            time.Time{}, -		SilencedAt:              time.Time{}, -		SuspendedAt:             time.Time{}, -		HideCollections:         testrig.FalseBool(), -		SuspensionOrigin:        "", -	} -} - -type AccountValidateTestSuite struct { -	suite.Suite -} - -func (suite *AccountValidateTestSuite) TestValidateAccountHappyPath() { -	// no problem here -	a := happyAccount() -	err := validate.Struct(*a) -	suite.NoError(err) -} - -// ID must be set and be valid ULID -func (suite *AccountValidateTestSuite) TestValidateAccountBadID() { -	a := happyAccount() - -	a.ID = "" -	err := validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.ID' Error:Field validation for 'ID' failed on the 'required' tag") - -	a.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB" -	err = validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.ID' Error:Field validation for 'ID' failed on the 'ulid' tag") -} - -// CreatedAt can be set or not -- it will be set in the database anyway -func (suite *AccountValidateTestSuite) TestValidateAccountNoCreatedAt() { -	a := happyAccount() - -	a.CreatedAt = time.Time{} -	err := validate.Struct(*a) -	suite.NoError(err) -} - -// FetchedAt must be defined if remote account -func (suite *AccountValidateTestSuite) TestValidateAccountNoWebfingeredAt() { -	a := happyAccount() - -	a.Domain = "example.org" -	a.FetchedAt = time.Time{} -	err := validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.FetchedAt' Error:Field validation for 'FetchedAt' failed on the 'required_with' tag") -} - -// Username must be set -func (suite *AccountValidateTestSuite) TestValidateAccountUsername() { -	a := happyAccount() - -	a.Username = "" -	err := validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.Username' Error:Field validation for 'Username' failed on the 'required' tag") -} - -// Domain must be either empty (for local accounts) or proper fqdn (for remote accounts) -func (suite *AccountValidateTestSuite) TestValidateAccountDomain() { -	a := happyAccount() -	a.FetchedAt = time.Now() - -	a.Domain = "" -	err := validate.Struct(*a) -	suite.NoError(err) - -	a.Domain = "localhost:8080" -	err = validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.Domain' Error:Field validation for 'Domain' failed on the 'fqdn' tag") - -	a.Domain = "ahhhhh" -	err = validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.Domain' Error:Field validation for 'Domain' failed on the 'fqdn' tag") - -	a.Domain = "https://www.example.org" -	err = validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.Domain' Error:Field validation for 'Domain' failed on the 'fqdn' tag") - -	a.Domain = "example.org:8080" -	err = validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.Domain' Error:Field validation for 'Domain' failed on the 'fqdn' tag") - -	a.Domain = "example.org" -	err = validate.Struct(*a) -	suite.NoError(err) -} - -// Attachment IDs must either be not set, or must be valid ULID -func (suite *AccountValidateTestSuite) TestValidateAttachmentIDs() { -	a := happyAccount() - -	a.AvatarMediaAttachmentID = "" -	a.HeaderMediaAttachmentID = "" -	err := validate.Struct(*a) -	suite.NoError(err) - -	a.AvatarMediaAttachmentID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB" -	a.HeaderMediaAttachmentID = "aaaa" -	err = validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.AvatarMediaAttachmentID' Error:Field validation for 'AvatarMediaAttachmentID' failed on the 'ulid' tag\nKey: 'Account.HeaderMediaAttachmentID' Error:Field validation for 'HeaderMediaAttachmentID' failed on the 'ulid' tag") -} - -// Attachment remote URLs must either not be set, or be valid URLs -func (suite *AccountValidateTestSuite) TestValidateAttachmentRemoteURLs() { -	a := happyAccount() - -	a.AvatarRemoteURL = "" -	a.HeaderRemoteURL = "" -	err := validate.Struct(*a) -	suite.NoError(err) - -	a.AvatarRemoteURL = "-------------" -	a.HeaderRemoteURL = "https://valid-url.com" -	err = validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.AvatarRemoteURL' Error:Field validation for 'AvatarRemoteURL' failed on the 'url' tag") - -	a.AvatarRemoteURL = "https://valid-url.com" -	a.HeaderRemoteURL = "" -	err = validate.Struct(*a) -	suite.NoError(err) -} - -// Default privacy must be set if account is local -func (suite *AccountValidateTestSuite) TestValidatePrivacy() { -	a := happyAccount() -	a.FetchedAt = time.Now() - -	a.Privacy = "" -	err := validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.Privacy' Error:Field validation for 'Privacy' failed on the 'required_without' tag") - -	a.Privacy = "not valid" -	err = validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.Privacy' Error:Field validation for 'Privacy' failed on the 'oneof' tag") - -	a.Privacy = gtsmodel.VisibilityFollowersOnly -	err = validate.Struct(*a) -	suite.NoError(err) - -	a.Privacy = "" -	a.Domain = "example.org" -	err = validate.Struct(*a) -	suite.NoError(err) - -	a.Privacy = "invalid" -	err = validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.Privacy' Error:Field validation for 'Privacy' failed on the 'oneof' tag") -} - -// If set, language must be a valid language -func (suite *AccountValidateTestSuite) TestValidateLanguage() { -	a := happyAccount() - -	a.Language = "" -	err := validate.Struct(*a) -	suite.NoError(err) - -	a.Language = "not valid" -	err = validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.Language' Error:Field validation for 'Language' failed on the 'bcp47_language_tag' tag") - -	a.Language = "en-uk" -	err = validate.Struct(*a) -	suite.NoError(err) -} - -// Account URI must be set and must be valid -func (suite *AccountValidateTestSuite) TestValidateAccountURI() { -	a := happyAccount() - -	a.URI = "invalid-uri" -	err := validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.URI' Error:Field validation for 'URI' failed on the 'url' tag") - -	a.URI = "" -	err = validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.URI' Error:Field validation for 'URI' failed on the 'required' tag") -} - -// ActivityPub URIs must be set on account if it's local -func (suite *AccountValidateTestSuite) TestValidateAccountURIs() { -	a := happyAccount() -	a.FetchedAt = time.Now() - -	a.InboxURI = "invalid-uri" -	a.OutboxURI = "invalid-uri" -	a.FollowersURI = "invalid-uri" -	a.FollowingURI = "invalid-uri" -	a.FeaturedCollectionURI = "invalid-uri" -	a.PublicKeyURI = "invalid-uri" -	err := validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.InboxURI' Error:Field validation for 'InboxURI' failed on the 'url' tag\nKey: 'Account.OutboxURI' Error:Field validation for 'OutboxURI' failed on the 'url' tag\nKey: 'Account.FollowingURI' Error:Field validation for 'FollowingURI' failed on the 'url' tag\nKey: 'Account.FollowersURI' Error:Field validation for 'FollowersURI' failed on the 'url' tag\nKey: 'Account.FeaturedCollectionURI' Error:Field validation for 'FeaturedCollectionURI' failed on the 'url' tag\nKey: 'Account.PublicKeyURI' Error:Field validation for 'PublicKeyURI' failed on the 'url' tag") - -	a.InboxURI = "" -	a.OutboxURI = "" -	a.FollowersURI = "" -	a.FollowingURI = "" -	a.FeaturedCollectionURI = "" -	a.PublicKeyURI = "" -	err = validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.InboxURI' Error:Field validation for 'InboxURI' failed on the 'required_without' tag\nKey: 'Account.OutboxURI' Error:Field validation for 'OutboxURI' failed on the 'required_without' tag\nKey: 'Account.FollowingURI' Error:Field validation for 'FollowingURI' failed on the 'required_without' tag\nKey: 'Account.FollowersURI' Error:Field validation for 'FollowersURI' failed on the 'required_without' tag\nKey: 'Account.FeaturedCollectionURI' Error:Field validation for 'FeaturedCollectionURI' failed on the 'required_without' tag\nKey: 'Account.PublicKeyURI' Error:Field validation for 'PublicKeyURI' failed on the 'required' tag") - -	a.Domain = "example.org" -	err = validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.PublicKeyURI' Error:Field validation for 'PublicKeyURI' failed on the 'required' tag") - -	a.InboxURI = "invalid-uri" -	a.OutboxURI = "invalid-uri" -	a.FollowersURI = "invalid-uri" -	a.FollowingURI = "invalid-uri" -	a.FeaturedCollectionURI = "invalid-uri" -	a.PublicKeyURI = "invalid-uri" -	err = validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.InboxURI' Error:Field validation for 'InboxURI' failed on the 'url' tag\nKey: 'Account.OutboxURI' Error:Field validation for 'OutboxURI' failed on the 'url' tag\nKey: 'Account.FollowingURI' Error:Field validation for 'FollowingURI' failed on the 'url' tag\nKey: 'Account.FollowersURI' Error:Field validation for 'FollowersURI' failed on the 'url' tag\nKey: 'Account.FeaturedCollectionURI' Error:Field validation for 'FeaturedCollectionURI' failed on the 'url' tag\nKey: 'Account.PublicKeyURI' Error:Field validation for 'PublicKeyURI' failed on the 'url' tag") -} - -// Actor type must be set and valid -func (suite *AccountValidateTestSuite) TestValidateActorType() { -	a := happyAccount() - -	a.ActorType = "" -	err := validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.ActorType' Error:Field validation for 'ActorType' failed on the 'oneof' tag") - -	a.ActorType = "not valid" -	err = validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.ActorType' Error:Field validation for 'ActorType' failed on the 'oneof' tag") - -	a.ActorType = ap.ActivityArrive -	err = validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.ActorType' Error:Field validation for 'ActorType' failed on the 'oneof' tag") - -	a.ActorType = ap.ActorOrganization -	err = validate.Struct(*a) -	suite.NoError(err) -} - -// Private key must be set on local accounts -func (suite *AccountValidateTestSuite) TestValidatePrivateKey() { -	a := happyAccount() -	a.FetchedAt = time.Now() - -	a.PrivateKey = nil -	err := validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.PrivateKey' Error:Field validation for 'PrivateKey' failed on the 'required_without' tag") - -	a.Domain = "example.org" -	err = validate.Struct(*a) -	suite.NoError(err) -} - -// Public key must be set -func (suite *AccountValidateTestSuite) TestValidatePublicKey() { -	a := happyAccount() - -	a.PublicKey = nil -	err := validate.Struct(*a) -	suite.EqualError(err, "Key: 'Account.PublicKey' Error:Field validation for 'PublicKey' failed on the 'required' tag") -} - -func TestAccountValidateTestSuite(t *testing.T) { -	suite.Run(t, new(AccountValidateTestSuite)) -} diff --git a/internal/validate/application_test.go b/internal/validate/application_test.go deleted file mode 100644 index 86c53a615..000000000 --- a/internal/validate/application_test.go +++ /dev/null @@ -1,132 +0,0 @@ -// GoToSocial -// Copyright (C) GoToSocial Authors admin@gotosocial.org -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// 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 validate_test - -import ( -	"testing" -	"time" - -	"github.com/stretchr/testify/suite" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" -	"github.com/superseriousbusiness/gotosocial/internal/validate" -) - -func happyApplication() *gtsmodel.Application { -	return >smodel.Application{ -		ID:           "01FE91RJR88PSEEE30EV35QR8N", -		CreatedAt:    time.Now(), -		UpdatedAt:    time.Now(), -		Name:         "Tusky", -		Website:      "https://tusky.app", -		RedirectURI:  "oauth2redirect://com.keylesspalace.tusky/", -		ClientID:     "01FEEDMF6C0QD589MRK7919Z0R", -		ClientSecret: "bd740cf1-024a-4e4d-8c39-866538f52fe6", -		Scopes:       "read write follow", -	} -} - -type ApplicationValidateTestSuite struct { -	suite.Suite -} - -func (suite *ApplicationValidateTestSuite) TestValidateApplicationHappyPath() { -	// no problem here -	a := happyApplication() -	err := validate.Struct(a) -	suite.NoError(err) -} - -func (suite *ApplicationValidateTestSuite) TestValidateApplicationBadID() { -	a := happyApplication() - -	a.ID = "" -	err := validate.Struct(a) -	suite.EqualError(err, "Key: 'Application.ID' Error:Field validation for 'ID' failed on the 'required' tag") - -	a.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB" -	err = validate.Struct(a) -	suite.EqualError(err, "Key: 'Application.ID' Error:Field validation for 'ID' failed on the 'ulid' tag") -} - -func (suite *ApplicationValidateTestSuite) TestValidateApplicationNoCreatedAt() { -	a := happyApplication() - -	a.CreatedAt = time.Time{} -	err := validate.Struct(a) -	suite.NoError(err) -} - -func (suite *ApplicationValidateTestSuite) TestValidateApplicationName() { -	a := happyApplication() - -	a.Name = "" -	err := validate.Struct(a) -	suite.EqualError(err, "Key: 'Application.Name' Error:Field validation for 'Name' failed on the 'required' tag") -} - -func (suite *ApplicationValidateTestSuite) TestValidateApplicationWebsite() { -	a := happyApplication() - -	a.Website = "invalid-website" -	err := validate.Struct(a) -	suite.EqualError(err, "Key: 'Application.Website' Error:Field validation for 'Website' failed on the 'url' tag") - -	a.Website = "" -	err = validate.Struct(a) -	suite.NoError(err) -} - -func (suite *ApplicationValidateTestSuite) TestValidateApplicationRedirectURI() { -	a := happyApplication() - -	a.RedirectURI = "invalid-uri" -	err := validate.Struct(a) -	suite.EqualError(err, "Key: 'Application.RedirectURI' Error:Field validation for 'RedirectURI' failed on the 'uri' tag") - -	a.RedirectURI = "" -	err = validate.Struct(a) -	suite.EqualError(err, "Key: 'Application.RedirectURI' Error:Field validation for 'RedirectURI' failed on the 'required' tag") - -	a.RedirectURI = "urn:ietf:wg:oauth:2.0:oob" -	err = validate.Struct(a) -	suite.NoError(err) -} - -func (suite *ApplicationValidateTestSuite) TestValidateApplicationClientSecret() { -	a := happyApplication() - -	a.ClientSecret = "invalid-uuid" -	err := validate.Struct(a) -	suite.EqualError(err, "Key: 'Application.ClientSecret' Error:Field validation for 'ClientSecret' failed on the 'uuid' tag") - -	a.ClientSecret = "" -	err = validate.Struct(a) -	suite.EqualError(err, "Key: 'Application.ClientSecret' Error:Field validation for 'ClientSecret' failed on the 'required' tag") -} - -func (suite *ApplicationValidateTestSuite) TestValidateApplicationScopes() { -	a := happyApplication() - -	a.Scopes = "" -	err := validate.Struct(a) -	suite.EqualError(err, "Key: 'Application.Scopes' Error:Field validation for 'Scopes' failed on the 'required' tag") -} - -func TestApplicationValidateTestSuite(t *testing.T) { -	suite.Run(t, new(ApplicationValidateTestSuite)) -} diff --git a/internal/validate/block_test.go b/internal/validate/block_test.go deleted file mode 100644 index 96e206140..000000000 --- a/internal/validate/block_test.go +++ /dev/null @@ -1,115 +0,0 @@ -// GoToSocial -// Copyright (C) GoToSocial Authors admin@gotosocial.org -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// 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 validate_test - -import ( -	"testing" -	"time" - -	"github.com/stretchr/testify/suite" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" -	"github.com/superseriousbusiness/gotosocial/internal/validate" -) - -func happyBlock() *gtsmodel.Block { -	return >smodel.Block{ -		ID:              "01FE91RJR88PSEEE30EV35QR8N", -		CreatedAt:       time.Now(), -		UpdatedAt:       time.Now(), -		URI:             "https://example.org/accounts/someone/blocks/01FE91RJR88PSEEE30EV35QR8N", -		AccountID:       "01FEED79PRMVWPRMFHFQM8MJQN", -		Account:         nil, -		TargetAccountID: "01FEEDMF6C0QD589MRK7919Z0R", -		TargetAccount:   nil, -	} -} - -type BlockValidateTestSuite struct { -	suite.Suite -} - -func (suite *BlockValidateTestSuite) TestValidateBlockHappyPath() { -	// no problem here -	b := happyBlock() -	err := validate.Struct(b) -	suite.NoError(err) -} - -func (suite *BlockValidateTestSuite) TestValidateBlockBadID() { -	b := happyBlock() - -	b.ID = "" -	err := validate.Struct(b) -	suite.EqualError(err, "Key: 'Block.ID' Error:Field validation for 'ID' failed on the 'required' tag") - -	b.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB" -	err = validate.Struct(b) -	suite.EqualError(err, "Key: 'Block.ID' Error:Field validation for 'ID' failed on the 'ulid' tag") -} - -func (suite *BlockValidateTestSuite) TestValidateBlockNoCreatedAt() { -	b := happyBlock() - -	b.CreatedAt = time.Time{} -	err := validate.Struct(b) -	suite.NoError(err) -} - -func (suite *BlockValidateTestSuite) TestValidateBlockCreatedByAccountID() { -	b := happyBlock() - -	b.AccountID = "" -	err := validate.Struct(b) -	suite.EqualError(err, "Key: 'Block.AccountID' Error:Field validation for 'AccountID' failed on the 'required' tag") - -	b.AccountID = "this-is-not-a-valid-ulid" -	err = validate.Struct(b) -	suite.EqualError(err, "Key: 'Block.AccountID' Error:Field validation for 'AccountID' failed on the 'ulid' tag") -} - -func (suite *BlockValidateTestSuite) TestValidateBlockTargetAccountID() { -	b := happyBlock() - -	b.TargetAccountID = "invalid-ulid" -	err := validate.Struct(b) -	suite.EqualError(err, "Key: 'Block.TargetAccountID' Error:Field validation for 'TargetAccountID' failed on the 'ulid' tag") - -	b.TargetAccountID = "01FEEDHX4G7EGHF5GD9E82Y51Q" -	err = validate.Struct(b) -	suite.NoError(err) - -	b.TargetAccountID = "" -	err = validate.Struct(b) -	suite.EqualError(err, "Key: 'Block.TargetAccountID' Error:Field validation for 'TargetAccountID' failed on the 'required' tag") -} - -func (suite *BlockValidateTestSuite) TestValidateBlockURI() { -	b := happyBlock() - -	b.URI = "invalid-uri" -	err := validate.Struct(b) -	suite.EqualError(err, "Key: 'Block.URI' Error:Field validation for 'URI' failed on the 'url' tag") - -	b.URI = "" -	err = validate.Struct(b) -	suite.EqualError(err, "Key: 'Block.URI' Error:Field validation for 'URI' failed on the 'required' tag") -} - -func TestBlockValidateTestSuite(t *testing.T) { -	suite.Run(t, new(BlockValidateTestSuite)) -} diff --git a/internal/validate/client_test.go b/internal/validate/client_test.go deleted file mode 100644 index ee8f0e66e..000000000 --- a/internal/validate/client_test.go +++ /dev/null @@ -1,101 +0,0 @@ -// GoToSocial -// Copyright (C) GoToSocial Authors admin@gotosocial.org -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// 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 validate_test - -import ( -	"testing" -	"time" - -	"github.com/stretchr/testify/suite" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" -	"github.com/superseriousbusiness/gotosocial/internal/validate" -) - -func happyClient() *gtsmodel.Client { -	return >smodel.Client{ -		ID:        "01FE91RJR88PSEEE30EV35QR8N", -		CreatedAt: time.Now(), -		UpdatedAt: time.Now(), -		Secret:    "bd740cf1-024a-4e4d-8c39-866538f52fe6", -		Domain:    "oauth2redirect://com.keylesspalace.tusky/", -		UserID:    "01FEEDMF6C0QD589MRK7919Z0R", -	} -} - -type ClientValidateTestSuite struct { -	suite.Suite -} - -func (suite *ClientValidateTestSuite) TestValidateClientHappyPath() { -	// no problem here -	c := happyClient() -	err := validate.Struct(c) -	suite.NoError(err) -} - -func (suite *ClientValidateTestSuite) TestValidateClientBadID() { -	c := happyClient() - -	c.ID = "" -	err := validate.Struct(c) -	suite.EqualError(err, "Key: 'Client.ID' Error:Field validation for 'ID' failed on the 'required' tag") - -	c.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB" -	err = validate.Struct(c) -	suite.EqualError(err, "Key: 'Client.ID' Error:Field validation for 'ID' failed on the 'ulid' tag") -} - -func (suite *ClientValidateTestSuite) TestValidateClientNoCreatedAt() { -	c := happyClient() - -	c.CreatedAt = time.Time{} -	err := validate.Struct(c) -	suite.NoError(err) -} - -func (suite *ClientValidateTestSuite) TestValidateClientDomain() { -	c := happyClient() - -	c.Domain = "invalid-uri" -	err := validate.Struct(c) -	suite.EqualError(err, "Key: 'Client.Domain' Error:Field validation for 'Domain' failed on the 'uri' tag") - -	c.Domain = "" -	err = validate.Struct(c) -	suite.EqualError(err, "Key: 'Client.Domain' Error:Field validation for 'Domain' failed on the 'required' tag") - -	c.Domain = "urn:ietf:wg:oauth:2.0:oob" -	err = validate.Struct(c) -	suite.NoError(err) -} - -func (suite *ClientValidateTestSuite) TestValidateSecret() { -	c := happyClient() - -	c.Secret = "invalid-uuid" -	err := validate.Struct(c) -	suite.EqualError(err, "Key: 'Client.Secret' Error:Field validation for 'Secret' failed on the 'uuid' tag") - -	c.Secret = "" -	err = validate.Struct(c) -	suite.EqualError(err, "Key: 'Client.Secret' Error:Field validation for 'Secret' failed on the 'required' tag") -} - -func TestClientValidateTestSuite(t *testing.T) { -	suite.Run(t, new(ClientValidateTestSuite)) -} diff --git a/internal/validate/domainblock_test.go b/internal/validate/domainblock_test.go deleted file mode 100644 index f6504d1f3..000000000 --- a/internal/validate/domainblock_test.go +++ /dev/null @@ -1,122 +0,0 @@ -// GoToSocial -// Copyright (C) GoToSocial Authors admin@gotosocial.org -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// 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 validate_test - -import ( -	"testing" -	"time" - -	"github.com/stretchr/testify/suite" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" -	"github.com/superseriousbusiness/gotosocial/internal/validate" -	"github.com/superseriousbusiness/gotosocial/testrig" -) - -func happyDomainBlock() *gtsmodel.DomainBlock { -	return >smodel.DomainBlock{ -		ID:                 "01FE91RJR88PSEEE30EV35QR8N", -		CreatedAt:          time.Now(), -		UpdatedAt:          time.Now(), -		Domain:             "baddudes.suck", -		CreatedByAccountID: "01FEED79PRMVWPRMFHFQM8MJQN", -		PrivateComment:     "we don't like em", -		PublicComment:      "poo poo dudes", -		Obfuscate:          testrig.FalseBool(), -		SubscriptionID:     "", -	} -} - -type DomainBlockValidateTestSuite struct { -	suite.Suite -} - -func (suite *DomainBlockValidateTestSuite) TestValidateDomainBlockHappyPath() { -	// no problem here -	d := happyDomainBlock() -	err := validate.Struct(d) -	suite.NoError(err) -} - -func (suite *DomainBlockValidateTestSuite) TestValidateDomainBlockBadID() { -	d := happyDomainBlock() - -	d.ID = "" -	err := validate.Struct(d) -	suite.EqualError(err, "Key: 'DomainBlock.ID' Error:Field validation for 'ID' failed on the 'required' tag") - -	d.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB" -	err = validate.Struct(d) -	suite.EqualError(err, "Key: 'DomainBlock.ID' Error:Field validation for 'ID' failed on the 'ulid' tag") -} - -func (suite *DomainBlockValidateTestSuite) TestValidateDomainBlockNoCreatedAt() { -	d := happyDomainBlock() - -	d.CreatedAt = time.Time{} -	err := validate.Struct(d) -	suite.NoError(err) -} - -func (suite *DomainBlockValidateTestSuite) TestValidateDomainBlockBadDomain() { -	d := happyDomainBlock() - -	d.Domain = "" -	err := validate.Struct(d) -	suite.EqualError(err, "Key: 'DomainBlock.Domain' Error:Field validation for 'Domain' failed on the 'required' tag") - -	d.Domain = "this-is-not-a-valid-domain" -	err = validate.Struct(d) -	suite.EqualError(err, "Key: 'DomainBlock.Domain' Error:Field validation for 'Domain' failed on the 'fqdn' tag") -} - -func (suite *DomainBlockValidateTestSuite) TestValidateDomainBlockCreatedByAccountID() { -	d := happyDomainBlock() - -	d.CreatedByAccountID = "" -	err := validate.Struct(d) -	suite.EqualError(err, "Key: 'DomainBlock.CreatedByAccountID' Error:Field validation for 'CreatedByAccountID' failed on the 'required' tag") - -	d.CreatedByAccountID = "this-is-not-a-valid-ulid" -	err = validate.Struct(d) -	suite.EqualError(err, "Key: 'DomainBlock.CreatedByAccountID' Error:Field validation for 'CreatedByAccountID' failed on the 'ulid' tag") -} - -func (suite *DomainBlockValidateTestSuite) TestValidateDomainBlockComments() { -	d := happyDomainBlock() - -	d.PrivateComment = "" -	d.PublicComment = "" -	err := validate.Struct(d) -	suite.NoError(err) -} - -func (suite *DomainBlockValidateTestSuite) TestValidateDomainSubscriptionID() { -	d := happyDomainBlock() - -	d.SubscriptionID = "invalid-ulid" -	err := validate.Struct(d) -	suite.EqualError(err, "Key: 'DomainBlock.SubscriptionID' Error:Field validation for 'SubscriptionID' failed on the 'ulid' tag") - -	d.SubscriptionID = "01FEEDHX4G7EGHF5GD9E82Y51Q" -	err = validate.Struct(d) -	suite.NoError(err) -} - -func TestDomainBlockValidateTestSuite(t *testing.T) { -	suite.Run(t, new(DomainBlockValidateTestSuite)) -} diff --git a/internal/validate/emaildomainblock_test.go b/internal/validate/emaildomainblock_test.go deleted file mode 100644 index 2aac0d72c..000000000 --- a/internal/validate/emaildomainblock_test.go +++ /dev/null @@ -1,96 +0,0 @@ -// GoToSocial -// Copyright (C) GoToSocial Authors admin@gotosocial.org -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// 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 validate_test - -import ( -	"testing" -	"time" - -	"github.com/stretchr/testify/suite" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" -	"github.com/superseriousbusiness/gotosocial/internal/validate" -) - -func happyEmailDomainBlock() *gtsmodel.EmailDomainBlock { -	return >smodel.EmailDomainBlock{ -		ID:                 "01FE91RJR88PSEEE30EV35QR8N", -		CreatedAt:          time.Now(), -		UpdatedAt:          time.Now(), -		Domain:             "baddudes.suck", -		CreatedByAccountID: "01FEED79PRMVWPRMFHFQM8MJQN", -	} -} - -type EmailDomainBlockValidateTestSuite struct { -	suite.Suite -} - -func (suite *EmailDomainBlockValidateTestSuite) TestValidateEmailDomainBlockHappyPath() { -	// no problem here -	e := happyEmailDomainBlock() -	err := validate.Struct(e) -	suite.NoError(err) -} - -func (suite *EmailDomainBlockValidateTestSuite) TestValidateEmailDomainBlockBadID() { -	e := happyEmailDomainBlock() - -	e.ID = "" -	err := validate.Struct(e) -	suite.EqualError(err, "Key: 'EmailDomainBlock.ID' Error:Field validation for 'ID' failed on the 'required' tag") - -	e.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB" -	err = validate.Struct(e) -	suite.EqualError(err, "Key: 'EmailDomainBlock.ID' Error:Field validation for 'ID' failed on the 'ulid' tag") -} - -func (suite *EmailDomainBlockValidateTestSuite) TestValidateEmailDomainBlockNoCreatedAt() { -	e := happyEmailDomainBlock() - -	e.CreatedAt = time.Time{} -	err := validate.Struct(e) -	suite.NoError(err) -} - -func (suite *EmailDomainBlockValidateTestSuite) TestValidateEmailDomainBlockBadDomain() { -	e := happyEmailDomainBlock() - -	e.Domain = "" -	err := validate.Struct(e) -	suite.EqualError(err, "Key: 'EmailDomainBlock.Domain' Error:Field validation for 'Domain' failed on the 'required' tag") - -	e.Domain = "this-is-not-a-valid-domain" -	err = validate.Struct(e) -	suite.EqualError(err, "Key: 'EmailDomainBlock.Domain' Error:Field validation for 'Domain' failed on the 'fqdn' tag") -} - -func (suite *EmailDomainBlockValidateTestSuite) TestValidateEmailDomainBlockCreatedByAccountID() { -	e := happyEmailDomainBlock() - -	e.CreatedByAccountID = "" -	err := validate.Struct(e) -	suite.EqualError(err, "Key: 'EmailDomainBlock.CreatedByAccountID' Error:Field validation for 'CreatedByAccountID' failed on the 'required' tag") - -	e.CreatedByAccountID = "this-is-not-a-valid-ulid" -	err = validate.Struct(e) -	suite.EqualError(err, "Key: 'EmailDomainBlock.CreatedByAccountID' Error:Field validation for 'CreatedByAccountID' failed on the 'ulid' tag") -} - -func TestEmailDomainBlockValidateTestSuite(t *testing.T) { -	suite.Run(t, new(EmailDomainBlockValidateTestSuite)) -} diff --git a/internal/validate/emoji_test.go b/internal/validate/emoji_test.go deleted file mode 100644 index 9192cb1fc..000000000 --- a/internal/validate/emoji_test.go +++ /dev/null @@ -1,195 +0,0 @@ -// GoToSocial -// Copyright (C) GoToSocial Authors admin@gotosocial.org -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// 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 validate_test - -import ( -	"os" -	"testing" -	"time" - -	"github.com/stretchr/testify/suite" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" -	"github.com/superseriousbusiness/gotosocial/internal/validate" -	"github.com/superseriousbusiness/gotosocial/testrig" -) - -func happyEmoji() *gtsmodel.Emoji { -	// the file validator actually runs os.Stat on given paths, so we need to just create small -	// temp files for both the main attachment file and the thumbnail - -	imageFile, err := os.CreateTemp("", "gts_test_emoji") -	if err != nil { -		panic(err) -	} -	if _, err := imageFile.WriteString("main"); err != nil { -		panic(err) -	} -	imagePath := imageFile.Name() -	if err := imageFile.Close(); err != nil { -		panic(err) -	} - -	staticFile, err := os.CreateTemp("", "gts_test_emoji_static") -	if err != nil { -		panic(err) -	} -	if _, err := staticFile.WriteString("thumbnail"); err != nil { -		panic(err) -	} -	imageStaticPath := staticFile.Name() -	if err := staticFile.Close(); err != nil { -		panic(err) -	} - -	return >smodel.Emoji{ -		ID:                     "01F8MH6NEM8D7527KZAECTCR76", -		CreatedAt:              time.Now().Add(-71 * time.Hour), -		UpdatedAt:              time.Now().Add(-71 * time.Hour), -		Shortcode:              "blob_test", -		Domain:                 "example.org", -		ImageRemoteURL:         "https://example.org/emojis/blob_test.gif", -		ImageStaticRemoteURL:   "https://example.org/emojis/blob_test.png", -		ImageURL:               "", -		ImageStaticURL:         "", -		ImagePath:              imagePath, -		ImageStaticPath:        imageStaticPath, -		ImageContentType:       "image/gif", -		ImageStaticContentType: "image/png", -		ImageFileSize:          1024, -		ImageStaticFileSize:    256, -		ImageUpdatedAt:         time.Now(), -		Disabled:               testrig.FalseBool(), -		URI:                    "https://example.org/emojis/blob_test", -		VisibleInPicker:        testrig.TrueBool(), -		CategoryID:             "01FEE47ZH70PWDSEAVBRFNX325", -	} -} - -type EmojiValidateTestSuite struct { -	suite.Suite -} - -func (suite *EmojiValidateTestSuite) TestValidateEmojiHappyPath() { -	// no problem here -	m := happyEmoji() -	err := validate.Struct(*m) -	suite.NoError(err) -} - -func (suite *EmojiValidateTestSuite) TestValidateEmojiBadFilePaths() { -	e := happyEmoji() - -	e.ImagePath = "/tmp/nonexistent/file/for/gotosocial/test" -	err := validate.Struct(e) -	suite.EqualError(err, "Key: 'Emoji.ImagePath' Error:Field validation for 'ImagePath' failed on the 'file' tag") - -	e.ImagePath = "" -	err = validate.Struct(e) -	suite.EqualError(err, "Key: 'Emoji.ImagePath' Error:Field validation for 'ImagePath' failed on the 'required' tag") - -	e.ImagePath = "???????????thisnot a valid path####" -	err = validate.Struct(e) -	suite.EqualError(err, "Key: 'Emoji.ImagePath' Error:Field validation for 'ImagePath' failed on the 'file' tag") - -	e.ImageStaticPath = "/tmp/nonexistent/file/for/gotosocial/test" -	err = validate.Struct(e) -	suite.EqualError(err, "Key: 'Emoji.ImagePath' Error:Field validation for 'ImagePath' failed on the 'file' tag\nKey: 'Emoji.ImageStaticPath' Error:Field validation for 'ImageStaticPath' failed on the 'file' tag") - -	e.ImageStaticPath = "" -	err = validate.Struct(e) -	suite.EqualError(err, "Key: 'Emoji.ImagePath' Error:Field validation for 'ImagePath' failed on the 'file' tag\nKey: 'Emoji.ImageStaticPath' Error:Field validation for 'ImageStaticPath' failed on the 'required' tag") - -	e.ImageStaticPath = "???????????thisnot a valid path####" -	err = validate.Struct(e) -	suite.EqualError(err, "Key: 'Emoji.ImagePath' Error:Field validation for 'ImagePath' failed on the 'file' tag\nKey: 'Emoji.ImageStaticPath' Error:Field validation for 'ImageStaticPath' failed on the 'file' tag") -} - -func (suite *EmojiValidateTestSuite) TestValidateEmojiURI() { -	e := happyEmoji() - -	e.URI = "aaaaaaaaaa" -	err := validate.Struct(e) -	suite.EqualError(err, "Key: 'Emoji.URI' Error:Field validation for 'URI' failed on the 'url' tag") - -	e.URI = "" -	err = validate.Struct(e) -	suite.EqualError(err, "Key: 'Emoji.URI' Error:Field validation for 'URI' failed on the 'url' tag") -} - -func (suite *EmojiValidateTestSuite) TestValidateEmojiURLCombos() { -	e := happyEmoji() - -	e.ImageRemoteURL = "" -	err := validate.Struct(e) -	suite.EqualError(err, "Key: 'Emoji.ImageRemoteURL' Error:Field validation for 'ImageRemoteURL' failed on the 'required_without' tag\nKey: 'Emoji.ImageURL' Error:Field validation for 'ImageURL' failed on the 'required_without' tag") - -	e.ImageURL = "https://whatever.org" -	err = validate.Struct(e) -	suite.NoError(err) - -	e.ImageStaticRemoteURL = "" -	err = validate.Struct(e) -	suite.EqualError(err, "Key: 'Emoji.ImageStaticRemoteURL' Error:Field validation for 'ImageStaticRemoteURL' failed on the 'required_without' tag\nKey: 'Emoji.ImageStaticURL' Error:Field validation for 'ImageStaticURL' failed on the 'required_without' tag") - -	e.ImageStaticURL = "https://whatever.org" -	err = validate.Struct(e) -	suite.NoError(err) - -	e.ImageURL = "" -	e.ImageStaticURL = "" -	e.ImageRemoteURL = "" -	e.ImageStaticRemoteURL = "" -	err = validate.Struct(e) -	suite.EqualError(err, "Key: 'Emoji.ImageRemoteURL' Error:Field validation for 'ImageRemoteURL' failed on the 'required_without' tag\nKey: 'Emoji.ImageStaticRemoteURL' Error:Field validation for 'ImageStaticRemoteURL' failed on the 'required_without' tag\nKey: 'Emoji.ImageURL' Error:Field validation for 'ImageURL' failed on the 'required_without' tag\nKey: 'Emoji.ImageStaticURL' Error:Field validation for 'ImageStaticURL' failed on the 'required_without' tag") -} - -func (suite *EmojiValidateTestSuite) TestValidateFileSize() { -	e := happyEmoji() - -	e.ImageFileSize = 0 -	err := validate.Struct(e) -	suite.EqualError(err, "Key: 'Emoji.ImageFileSize' Error:Field validation for 'ImageFileSize' failed on the 'required' tag") - -	e.ImageStaticFileSize = 0 -	err = validate.Struct(e) -	suite.EqualError(err, "Key: 'Emoji.ImageFileSize' Error:Field validation for 'ImageFileSize' failed on the 'required' tag\nKey: 'Emoji.ImageStaticFileSize' Error:Field validation for 'ImageStaticFileSize' failed on the 'required' tag") - -	e.ImageFileSize = -1 -	err = validate.Struct(e) -	suite.EqualError(err, "Key: 'Emoji.ImageFileSize' Error:Field validation for 'ImageFileSize' failed on the 'min' tag\nKey: 'Emoji.ImageStaticFileSize' Error:Field validation for 'ImageStaticFileSize' failed on the 'required' tag") - -	e.ImageStaticFileSize = -1 -	err = validate.Struct(e) -	suite.EqualError(err, "Key: 'Emoji.ImageFileSize' Error:Field validation for 'ImageFileSize' failed on the 'min' tag\nKey: 'Emoji.ImageStaticFileSize' Error:Field validation for 'ImageStaticFileSize' failed on the 'min' tag") -} - -func (suite *EmojiValidateTestSuite) TestValidateDomain() { -	e := happyEmoji() - -	e.Domain = "" -	err := validate.Struct(e) -	suite.EqualError(err, "Key: 'Emoji.ImageURL' Error:Field validation for 'ImageURL' failed on the 'required_without' tag\nKey: 'Emoji.ImageStaticURL' Error:Field validation for 'ImageStaticURL' failed on the 'required_without' tag") - -	e.Domain = "aaaaaaaaa" -	err = validate.Struct(e) -	suite.EqualError(err, "Key: 'Emoji.Domain' Error:Field validation for 'Domain' failed on the 'fqdn' tag") -} - -func TestEmojiValidateTestSuite(t *testing.T) { -	suite.Run(t, new(EmojiValidateTestSuite)) -} diff --git a/internal/validate/follow_test.go b/internal/validate/follow_test.go deleted file mode 100644 index 2128be4aa..000000000 --- a/internal/validate/follow_test.go +++ /dev/null @@ -1,87 +0,0 @@ -// GoToSocial -// Copyright (C) GoToSocial Authors admin@gotosocial.org -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// 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 validate_test - -import ( -	"testing" -	"time" - -	"github.com/stretchr/testify/suite" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" -	"github.com/superseriousbusiness/gotosocial/internal/validate" -) - -func happyFollow() *gtsmodel.Follow { -	return >smodel.Follow{ -		ID:              "01FE91RJR88PSEEE30EV35QR8N", -		CreatedAt:       time.Now(), -		UpdatedAt:       time.Now(), -		AccountID:       "01FE96MAE58MXCE5C4SSMEMCEK", -		Account:         nil, -		TargetAccountID: "01FE96MXRHWZHKC0WH5FT82H1A", -		TargetAccount:   nil, -		URI:             "https://example.org/users/user1/activity/follow/01FE91RJR88PSEEE30EV35QR8N", -	} -} - -type FollowValidateTestSuite struct { -	suite.Suite -} - -func (suite *FollowValidateTestSuite) TestValidateFollowHappyPath() { -	// no problem here -	f := happyFollow() -	err := validate.Struct(f) -	suite.NoError(err) -} - -func (suite *FollowValidateTestSuite) TestValidateFollowBadID() { -	f := happyFollow() - -	f.ID = "" -	err := validate.Struct(f) -	suite.EqualError(err, "Key: 'Follow.ID' Error:Field validation for 'ID' failed on the 'required' tag") - -	f.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB" -	err = validate.Struct(f) -	suite.EqualError(err, "Key: 'Follow.ID' Error:Field validation for 'ID' failed on the 'ulid' tag") -} - -func (suite *FollowValidateTestSuite) TestValidateFollowNoCreatedAt() { -	f := happyFollow() - -	f.CreatedAt = time.Time{} -	err := validate.Struct(f) -	suite.NoError(err) -} - -func (suite *FollowValidateTestSuite) TestValidateFollowNoURI() { -	f := happyFollow() - -	f.URI = "" -	err := validate.Struct(f) -	suite.EqualError(err, "Key: 'Follow.URI' Error:Field validation for 'URI' failed on the 'required' tag") - -	f.URI = "this-is-not-a-valid-url" -	err = validate.Struct(f) -	suite.EqualError(err, "Key: 'Follow.URI' Error:Field validation for 'URI' failed on the 'url' tag") -} - -func TestFollowValidateTestSuite(t *testing.T) { -	suite.Run(t, new(FollowValidateTestSuite)) -} diff --git a/internal/validate/followrequest_test.go b/internal/validate/followrequest_test.go deleted file mode 100644 index 0c3d883bb..000000000 --- a/internal/validate/followrequest_test.go +++ /dev/null @@ -1,87 +0,0 @@ -// GoToSocial -// Copyright (C) GoToSocial Authors admin@gotosocial.org -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// 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 validate_test - -import ( -	"testing" -	"time" - -	"github.com/stretchr/testify/suite" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" -	"github.com/superseriousbusiness/gotosocial/internal/validate" -) - -func happyFollowRequest() *gtsmodel.FollowRequest { -	return >smodel.FollowRequest{ -		ID:              "01FE91RJR88PSEEE30EV35QR8N", -		CreatedAt:       time.Now(), -		UpdatedAt:       time.Now(), -		AccountID:       "01FE96MAE58MXCE5C4SSMEMCEK", -		Account:         nil, -		TargetAccountID: "01FE96MXRHWZHKC0WH5FT82H1A", -		TargetAccount:   nil, -		URI:             "https://example.org/users/user1/activity/follow/01FE91RJR88PSEEE30EV35QR8N", -	} -} - -type FollowRequestValidateTestSuite struct { -	suite.Suite -} - -func (suite *FollowRequestValidateTestSuite) TestValidateFollowRequestHappyPath() { -	// no problem here -	f := happyFollowRequest() -	err := validate.Struct(f) -	suite.NoError(err) -} - -func (suite *FollowRequestValidateTestSuite) TestValidateFollowRequestBadID() { -	f := happyFollowRequest() - -	f.ID = "" -	err := validate.Struct(f) -	suite.EqualError(err, "Key: 'FollowRequest.ID' Error:Field validation for 'ID' failed on the 'required' tag") - -	f.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB" -	err = validate.Struct(f) -	suite.EqualError(err, "Key: 'FollowRequest.ID' Error:Field validation for 'ID' failed on the 'ulid' tag") -} - -func (suite *FollowRequestValidateTestSuite) TestValidateFollowRequestNoCreatedAt() { -	f := happyFollowRequest() - -	f.CreatedAt = time.Time{} -	err := validate.Struct(f) -	suite.NoError(err) -} - -func (suite *FollowRequestValidateTestSuite) TestValidateFollowRequestNoURI() { -	f := happyFollowRequest() - -	f.URI = "" -	err := validate.Struct(f) -	suite.EqualError(err, "Key: 'FollowRequest.URI' Error:Field validation for 'URI' failed on the 'required' tag") - -	f.URI = "this-is-not-a-valid-url" -	err = validate.Struct(f) -	suite.EqualError(err, "Key: 'FollowRequest.URI' Error:Field validation for 'URI' failed on the 'url' tag") -} - -func TestFollowRequestValidateTestSuite(t *testing.T) { -	suite.Run(t, new(FollowRequestValidateTestSuite)) -} diff --git a/internal/validate/instance_test.go b/internal/validate/instance_test.go deleted file mode 100644 index 38c68a616..000000000 --- a/internal/validate/instance_test.go +++ /dev/null @@ -1,145 +0,0 @@ -// GoToSocial -// Copyright (C) GoToSocial Authors admin@gotosocial.org -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// 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 validate_test - -import ( -	"testing" -	"time" - -	"github.com/stretchr/testify/suite" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" -	"github.com/superseriousbusiness/gotosocial/internal/validate" -) - -func happyInstance() *gtsmodel.Instance { -	return >smodel.Instance{ -		ID:                     "01FE91RJR88PSEEE30EV35QR8N", -		CreatedAt:              time.Now(), -		UpdatedAt:              time.Now(), -		Domain:                 "example.org", -		Title:                  "Example Instance", -		URI:                    "https://example.org", -		SuspendedAt:            time.Time{}, -		DomainBlockID:          "", -		DomainBlock:            nil, -		ShortDescription:       "This is a description for the example/testing instance.", -		Description:            "This is a way longer description for the example/testing instance!", -		Terms:                  "Don't be a knobhead.", -		ContactEmail:           "admin@example.org", -		ContactAccountUsername: "admin", -		ContactAccountID:       "01FEE20H5QWHJDEXAEE9G96PR0", -		ContactAccount:         nil, -		Reputation:             420, -		Version:                "gotosocial 0.1.0", -	} -} - -type InstanceValidateTestSuite struct { -	suite.Suite -} - -func (suite *InstanceValidateTestSuite) TestValidateInstanceHappyPath() { -	// no problem here -	m := happyInstance() -	err := validate.Struct(*m) -	suite.NoError(err) -} - -func (suite *InstanceValidateTestSuite) TestValidateInstanceBadID() { -	m := happyInstance() - -	m.ID = "" -	err := validate.Struct(*m) -	suite.EqualError(err, "Key: 'Instance.ID' Error:Field validation for 'ID' failed on the 'required' tag") - -	m.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB" -	err = validate.Struct(*m) -	suite.EqualError(err, "Key: 'Instance.ID' Error:Field validation for 'ID' failed on the 'ulid' tag") -} - -func (suite *InstanceValidateTestSuite) TestValidateInstanceAccountURI() { -	i := happyInstance() - -	i.URI = "" -	err := validate.Struct(i) -	suite.EqualError(err, "Key: 'Instance.URI' Error:Field validation for 'URI' failed on the 'required' tag") - -	i.URI = "---------------------------" -	err = validate.Struct(i) -	suite.EqualError(err, "Key: 'Instance.URI' Error:Field validation for 'URI' failed on the 'url' tag") -} - -func (suite *InstanceValidateTestSuite) TestValidateInstanceDodgyAccountID() { -	i := happyInstance() - -	i.ContactAccountID = "9HZJ76B6VXSKF" -	err := validate.Struct(i) -	suite.EqualError(err, "Key: 'Instance.ContactAccountID' Error:Field validation for 'ContactAccountID' failed on the 'ulid' tag") - -	i.ContactAccountID = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!!!!!!!!!!!!" -	err = validate.Struct(i) -	suite.EqualError(err, "Key: 'Instance.ContactAccountID' Error:Field validation for 'ContactAccountID' failed on the 'ulid' tag") - -	i.ContactAccountID = "" -	err = validate.Struct(i) -	suite.EqualError(err, "Key: 'Instance.ContactAccountID' Error:Field validation for 'ContactAccountID' failed on the 'required_with' tag") - -	i.ContactAccountUsername = "" -	err = validate.Struct(i) -	suite.NoError(err) -} - -func (suite *InstanceValidateTestSuite) TestValidateInstanceDomain() { -	i := happyInstance() - -	i.Domain = "poopoo" -	err := validate.Struct(i) -	suite.EqualError(err, "Key: 'Instance.Domain' Error:Field validation for 'Domain' failed on the 'fqdn' tag") - -	i.Domain = "" -	err = validate.Struct(i) -	suite.EqualError(err, "Key: 'Instance.Domain' Error:Field validation for 'Domain' failed on the 'required' tag") - -	i.Domain = "https://aaaaaaaaaaaaah.org" -	err = validate.Struct(i) -	suite.EqualError(err, "Key: 'Instance.Domain' Error:Field validation for 'Domain' failed on the 'fqdn' tag") -} - -func (suite *InstanceValidateTestSuite) TestValidateInstanceContactEmail() { -	i := happyInstance() - -	i.ContactEmail = "poopoo" -	err := validate.Struct(i) -	suite.EqualError(err, "Key: 'Instance.ContactEmail' Error:Field validation for 'ContactEmail' failed on the 'email' tag") - -	i.ContactEmail = "" -	err = validate.Struct(i) -	suite.NoError(err) -} - -func (suite *InstanceValidateTestSuite) TestValidateInstanceNoCreatedAt() { -	i := happyInstance() - -	i.CreatedAt = time.Time{} -	err := validate.Struct(i) -	suite.NoError(err) -} - -func TestInstanceValidateTestSuite(t *testing.T) { -	suite.Run(t, new(InstanceValidateTestSuite)) -} diff --git a/internal/validate/mediaattachment_test.go b/internal/validate/mediaattachment_test.go deleted file mode 100644 index 1021319f2..000000000 --- a/internal/validate/mediaattachment_test.go +++ /dev/null @@ -1,230 +0,0 @@ -// GoToSocial -// Copyright (C) GoToSocial Authors admin@gotosocial.org -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// 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 validate_test - -import ( -	"os" -	"testing" -	"time" - -	"github.com/stretchr/testify/suite" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" -	"github.com/superseriousbusiness/gotosocial/internal/validate" -	"github.com/superseriousbusiness/gotosocial/testrig" -) - -func happyMediaAttachment() *gtsmodel.MediaAttachment { -	// the file validator actually runs os.Stat on given paths, so we need to just create small -	// temp files for both the main attachment file and the thumbnail - -	mainFile, err := os.CreateTemp("", "gts_test_mainfile") -	if err != nil { -		panic(err) -	} -	if _, err := mainFile.WriteString("main"); err != nil { -		panic(err) -	} -	mainPath := mainFile.Name() -	if err := mainFile.Close(); err != nil { -		panic(err) -	} - -	thumbnailFile, err := os.CreateTemp("", "gts_test_thumbnail") -	if err != nil { -		panic(err) -	} -	if _, err := thumbnailFile.WriteString("thumbnail"); err != nil { -		panic(err) -	} -	thumbnailPath := thumbnailFile.Name() -	if err := thumbnailFile.Close(); err != nil { -		panic(err) -	} - -	return >smodel.MediaAttachment{ -		ID:        "01F8MH6NEM8D7527KZAECTCR76", -		CreatedAt: time.Now().Add(-71 * time.Hour), -		UpdatedAt: time.Now().Add(-71 * time.Hour), -		StatusID:  "01F8MH75CBF9JFX4ZAD54N0W0R", -		URL:       "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.jpg", -		RemoteURL: "", -		Type:      gtsmodel.FileTypeImage, -		FileMeta: gtsmodel.FileMeta{ -			Original: gtsmodel.Original{ -				Width:  1200, -				Height: 630, -				Size:   756000, -				Aspect: 1.9047619047619047, -			}, -			Small: gtsmodel.Small{ -				Width:  256, -				Height: 134, -				Size:   34304, -				Aspect: 1.9104477611940298, -			}, -		}, -		AccountID:         "01F8MH17FWEB39HZJ76B6VXSKF", -		Description:       "Black and white image of some 50's style text saying: Welcome On Board", -		ScheduledStatusID: "", -		Blurhash:          "LNJRdVM{00Rj%Mayt7j[4nWBofRj", -		Processing:        2, -		File: gtsmodel.File{ -			Path:        mainPath, -			ContentType: "image/jpeg", -			FileSize:    62529, -			UpdatedAt:   time.Now().Add(-71 * time.Hour), -		}, -		Thumbnail: gtsmodel.Thumbnail{ -			Path:        thumbnailPath, -			ContentType: "image/jpeg", -			FileSize:    6872, -			UpdatedAt:   time.Now().Add(-71 * time.Hour), -			URL:         "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/small/01F8MH6NEM8D7527KZAECTCR76.jpg", -			RemoteURL:   "", -		}, -		Avatar: testrig.FalseBool(), -		Header: testrig.FalseBool(), -	} -} - -type MediaAttachmentValidateTestSuite struct { -	suite.Suite -} - -func (suite *MediaAttachmentValidateTestSuite) TestValidateMediaAttachmentHappyPath() { -	// no problem here -	m := happyMediaAttachment() -	err := validate.Struct(m) -	suite.NoError(err) -} - -func (suite *MediaAttachmentValidateTestSuite) TestValidateMediaAttachmentBadFilePaths() { -	m := happyMediaAttachment() - -	m.File.Path = "/tmp/nonexistent/file/for/gotosocial/test" -	err := validate.Struct(m) -	suite.EqualError(err, "Key: 'MediaAttachment.File.Path' Error:Field validation for 'Path' failed on the 'file' tag") - -	m.File.Path = "" -	err = validate.Struct(m) -	suite.EqualError(err, "Key: 'MediaAttachment.File.Path' Error:Field validation for 'Path' failed on the 'required' tag") - -	m.File.Path = "???????????thisnot a valid path####" -	err = validate.Struct(m) -	suite.EqualError(err, "Key: 'MediaAttachment.File.Path' Error:Field validation for 'Path' failed on the 'file' tag") - -	m.Thumbnail.Path = "/tmp/nonexistent/file/for/gotosocial/test" -	err = validate.Struct(m) -	suite.EqualError(err, "Key: 'MediaAttachment.File.Path' Error:Field validation for 'Path' failed on the 'file' tag\nKey: 'MediaAttachment.Thumbnail.Path' Error:Field validation for 'Path' failed on the 'file' tag") - -	m.Thumbnail.Path = "" -	err = validate.Struct(m) -	suite.EqualError(err, "Key: 'MediaAttachment.File.Path' Error:Field validation for 'Path' failed on the 'file' tag\nKey: 'MediaAttachment.Thumbnail.Path' Error:Field validation for 'Path' failed on the 'required' tag") - -	m.Thumbnail.Path = "???????????thisnot a valid path####" -	err = validate.Struct(m) -	suite.EqualError(err, "Key: 'MediaAttachment.File.Path' Error:Field validation for 'Path' failed on the 'file' tag\nKey: 'MediaAttachment.Thumbnail.Path' Error:Field validation for 'Path' failed on the 'file' tag") -} - -func (suite *MediaAttachmentValidateTestSuite) TestValidateMediaAttachmentBadType() { -	m := happyMediaAttachment() - -	m.Type = "" -	err := validate.Struct(m) -	suite.EqualError(err, "Key: 'MediaAttachment.Type' Error:Field validation for 'Type' failed on the 'oneof' tag") - -	m.Type = "Not Supported" -	err = validate.Struct(m) -	suite.EqualError(err, "Key: 'MediaAttachment.Type' Error:Field validation for 'Type' failed on the 'oneof' tag") -} - -func (suite *MediaAttachmentValidateTestSuite) TestValidateMediaAttachmentBadFileMeta() { -	m := happyMediaAttachment() - -	m.FileMeta.Original.Aspect = 0 -	err := validate.Struct(m) -	suite.EqualError(err, "Key: 'MediaAttachment.FileMeta.Original.Aspect' Error:Field validation for 'Aspect' failed on the 'required_with' tag") - -	m.FileMeta.Original.Height = 0 -	err = validate.Struct(m) -	suite.EqualError(err, "Key: 'MediaAttachment.FileMeta.Original.Height' Error:Field validation for 'Height' failed on the 'required_with' tag\nKey: 'MediaAttachment.FileMeta.Original.Aspect' Error:Field validation for 'Aspect' failed on the 'required_with' tag") - -	m.FileMeta.Original = gtsmodel.Original{} -	err = validate.Struct(m) -	suite.NoError(err) - -	m.FileMeta.Focus.X = 3.6 -	err = validate.Struct(m) -	suite.EqualError(err, "Key: 'MediaAttachment.FileMeta.Focus.X' Error:Field validation for 'X' failed on the 'max' tag") - -	m.FileMeta.Focus.Y = -50 -	err = validate.Struct(m) -	suite.EqualError(err, "Key: 'MediaAttachment.FileMeta.Focus.X' Error:Field validation for 'X' failed on the 'max' tag\nKey: 'MediaAttachment.FileMeta.Focus.Y' Error:Field validation for 'Y' failed on the 'min' tag") -} - -func (suite *MediaAttachmentValidateTestSuite) TestValidateMediaAttachmentBadURLCombos() { -	m := happyMediaAttachment() - -	m.URL = "aaaaaaaaaa" -	err := validate.Struct(m) -	suite.EqualError(err, "Key: 'MediaAttachment.URL' Error:Field validation for 'URL' failed on the 'url' tag") - -	m.URL = "" -	err = validate.Struct(m) -	suite.EqualError(err, "Key: 'MediaAttachment.URL' Error:Field validation for 'URL' failed on the 'required_without' tag\nKey: 'MediaAttachment.RemoteURL' Error:Field validation for 'RemoteURL' failed on the 'required_without' tag") - -	m.RemoteURL = "oooooooooo" -	err = validate.Struct(m) -	suite.EqualError(err, "Key: 'MediaAttachment.RemoteURL' Error:Field validation for 'RemoteURL' failed on the 'url' tag") - -	m.RemoteURL = "https://a-valid-url.gay" -	err = validate.Struct(m) -	suite.NoError(err) -} - -func (suite *MediaAttachmentValidateTestSuite) TestValidateMediaAttachmentBlurhash() { -	m := happyMediaAttachment() - -	m.Blurhash = "" -	err := validate.Struct(m) -	suite.EqualError(err, "Key: 'MediaAttachment.Blurhash' Error:Field validation for 'Blurhash' failed on the 'required_if' tag") - -	m.Type = gtsmodel.FileTypeAudio -	err = validate.Struct(m) -	suite.NoError(err) - -	m.Blurhash = "some_blurhash" -	err = validate.Struct(m) -	suite.NoError(err) -} - -func (suite *MediaAttachmentValidateTestSuite) TestValidateMediaAttachmentProcessing() { -	m := happyMediaAttachment() - -	m.Processing = 420 -	err := validate.Struct(m) -	suite.EqualError(err, "Key: 'MediaAttachment.Processing' Error:Field validation for 'Processing' failed on the 'oneof' tag") - -	m.Processing = -5 -	err = validate.Struct(m) -	suite.EqualError(err, "Key: 'MediaAttachment.Processing' Error:Field validation for 'Processing' failed on the 'oneof' tag") -} - -func TestMediaAttachmentValidateTestSuite(t *testing.T) { -	suite.Run(t, new(MediaAttachmentValidateTestSuite)) -} diff --git a/internal/validate/mention_test.go b/internal/validate/mention_test.go deleted file mode 100644 index 52513bd8c..000000000 --- a/internal/validate/mention_test.go +++ /dev/null @@ -1,101 +0,0 @@ -// GoToSocial -// Copyright (C) GoToSocial Authors admin@gotosocial.org -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// 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 validate_test - -import ( -	"testing" -	"time" - -	"github.com/stretchr/testify/suite" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" -	"github.com/superseriousbusiness/gotosocial/internal/validate" -) - -func happyMention() *gtsmodel.Mention { -	return >smodel.Mention{ -		ID:               "01FE91RJR88PSEEE30EV35QR8N", -		CreatedAt:        time.Now(), -		UpdatedAt:        time.Now(), -		OriginAccountID:  "01FE96MAE58MXCE5C4SSMEMCEK", -		OriginAccountURI: "https://some-instance/accounts/bleepbloop", -		OriginAccount:    nil, -		TargetAccountID:  "01FE96MXRHWZHKC0WH5FT82H1A", -		TargetAccount:    nil, -		StatusID:         "01FE96NBPNJNY26730FT6GZTFE", -		Status:           nil, -	} -} - -type MentionValidateTestSuite struct { -	suite.Suite -} - -func (suite *MentionValidateTestSuite) TestValidateMentionHappyPath() { -	// no problem here -	m := happyMention() -	err := validate.Struct(m) -	suite.NoError(err) -} - -func (suite *MentionValidateTestSuite) TestValidateMentionBadID() { -	m := happyMention() - -	m.ID = "" -	err := validate.Struct(m) -	suite.EqualError(err, "Key: 'Mention.ID' Error:Field validation for 'ID' failed on the 'required' tag") - -	m.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB" -	err = validate.Struct(m) -	suite.EqualError(err, "Key: 'Mention.ID' Error:Field validation for 'ID' failed on the 'ulid' tag") -} - -func (suite *MentionValidateTestSuite) TestValidateMentionAccountURI() { -	m := happyMention() - -	m.OriginAccountURI = "" -	err := validate.Struct(m) -	suite.EqualError(err, "Key: 'Mention.OriginAccountURI' Error:Field validation for 'OriginAccountURI' failed on the 'url' tag") - -	m.OriginAccountURI = "---------------------------" -	err = validate.Struct(m) -	suite.EqualError(err, "Key: 'Mention.OriginAccountURI' Error:Field validation for 'OriginAccountURI' failed on the 'url' tag") -} - -func (suite *MentionValidateTestSuite) TestValidateMentionDodgyStatusID() { -	m := happyMention() - -	m.StatusID = "9HZJ76B6VXSKF" -	err := validate.Struct(m) -	suite.EqualError(err, "Key: 'Mention.StatusID' Error:Field validation for 'StatusID' failed on the 'ulid' tag") - -	m.StatusID = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!!!!!!!!!!!!" -	err = validate.Struct(m) -	suite.EqualError(err, "Key: 'Mention.StatusID' Error:Field validation for 'StatusID' failed on the 'ulid' tag") -} - -func (suite *MentionValidateTestSuite) TestValidateMentionNoCreatedAt() { -	m := happyMention() - -	m.CreatedAt = time.Time{} -	err := validate.Struct(m) -	suite.NoError(err) -} - -func TestMentionValidateTestSuite(t *testing.T) { -	suite.Run(t, new(MentionValidateTestSuite)) -} diff --git a/internal/validate/notification_test.go b/internal/validate/notification_test.go deleted file mode 100644 index a76b8bf58..000000000 --- a/internal/validate/notification_test.go +++ /dev/null @@ -1,97 +0,0 @@ -// GoToSocial -// Copyright (C) GoToSocial Authors admin@gotosocial.org -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// 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 validate_test - -import ( -	"testing" -	"time" - -	"github.com/stretchr/testify/suite" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" -	"github.com/superseriousbusiness/gotosocial/internal/validate" -) - -func happyNotification() *gtsmodel.Notification { -	return >smodel.Notification{ -		ID:               "01FE91RJR88PSEEE30EV35QR8N", -		CreatedAt:        time.Now(), -		NotificationType: gtsmodel.NotificationFave, -		OriginAccountID:  "01FE96MAE58MXCE5C4SSMEMCEK", -		OriginAccount:    nil, -		TargetAccountID:  "01FE96MXRHWZHKC0WH5FT82H1A", -		TargetAccount:    nil, -		StatusID:         "01FE96NBPNJNY26730FT6GZTFE", -		Status:           nil, -	} -} - -type NotificationValidateTestSuite struct { -	suite.Suite -} - -func (suite *NotificationValidateTestSuite) TestValidateNotificationHappyPath() { -	// no problem here -	n := happyNotification() -	err := validate.Struct(n) -	suite.NoError(err) -} - -func (suite *NotificationValidateTestSuite) TestValidateNotificationBadID() { -	n := happyNotification() - -	n.ID = "" -	err := validate.Struct(n) -	suite.EqualError(err, "Key: 'Notification.ID' Error:Field validation for 'ID' failed on the 'required' tag") - -	n.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB" -	err = validate.Struct(n) -	suite.EqualError(err, "Key: 'Notification.ID' Error:Field validation for 'ID' failed on the 'ulid' tag") -} - -func (suite *NotificationValidateTestSuite) TestValidateNotificationStatusID() { -	n := happyNotification() - -	n.StatusID = "" -	err := validate.Struct(n) -	suite.EqualError(err, "Key: 'Notification.StatusID' Error:Field validation for 'StatusID' failed on the 'required_if' tag") - -	n.StatusID = "9HZJ76B6VXSKF" -	err = validate.Struct(n) -	suite.EqualError(err, "Key: 'Notification.StatusID' Error:Field validation for 'StatusID' failed on the 'ulid' tag") - -	n.StatusID = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!!!!!!!!!!!!" -	err = validate.Struct(n) -	suite.EqualError(err, "Key: 'Notification.StatusID' Error:Field validation for 'StatusID' failed on the 'ulid' tag") - -	n.StatusID = "" -	n.NotificationType = gtsmodel.NotificationFollowRequest -	err = validate.Struct(n) -	suite.NoError(err) -} - -func (suite *NotificationValidateTestSuite) TestValidateNotificationNoCreatedAt() { -	n := happyNotification() - -	n.CreatedAt = time.Time{} -	err := validate.Struct(n) -	suite.NoError(err) -} - -func TestNotificationValidateTestSuite(t *testing.T) { -	suite.Run(t, new(NotificationValidateTestSuite)) -} diff --git a/internal/validate/routersession_test.go b/internal/validate/routersession_test.go deleted file mode 100644 index f9dc49e40..000000000 --- a/internal/validate/routersession_test.go +++ /dev/null @@ -1,87 +0,0 @@ -// GoToSocial -// Copyright (C) GoToSocial Authors admin@gotosocial.org -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// 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 validate_test - -import ( -	"testing" - -	"github.com/stretchr/testify/suite" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" -	"github.com/superseriousbusiness/gotosocial/internal/validate" -) - -func happyRouterSession() *gtsmodel.RouterSession { -	return >smodel.RouterSession{ -		ID:    "01FE91RJR88PSEEE30EV35QR8N", -		Auth:  []byte("12345678901234567890123456789012"), -		Crypt: []byte("12345678901234567890123456789012"), -	} -} - -type RouterSessionValidateTestSuite struct { -	suite.Suite -} - -func (suite *RouterSessionValidateTestSuite) TestValidateRouterSessionHappyPath() { -	// no problem here -	r := happyRouterSession() -	err := validate.Struct(r) -	suite.NoError(err) -} - -func (suite *RouterSessionValidateTestSuite) TestValidateRouterSessionAuth() { -	r := happyRouterSession() - -	// remove auth struct -	r.Auth = nil -	err := validate.Struct(r) -	suite.EqualError(err, "Key: 'RouterSession.Auth' Error:Field validation for 'Auth' failed on the 'required' tag") - -	// auth bytes too long -	r.Auth = []byte("1234567890123456789012345678901234567890") -	err = validate.Struct(r) -	suite.EqualError(err, "Key: 'RouterSession.Auth' Error:Field validation for 'Auth' failed on the 'len' tag") - -	// auth bytes too short -	r.Auth = []byte("12345678901") -	err = validate.Struct(r) -	suite.EqualError(err, "Key: 'RouterSession.Auth' Error:Field validation for 'Auth' failed on the 'len' tag") -} - -func (suite *RouterSessionValidateTestSuite) TestValidateRouterSessionCrypt() { -	r := happyRouterSession() - -	// remove crypt struct -	r.Crypt = nil -	err := validate.Struct(r) -	suite.EqualError(err, "Key: 'RouterSession.Crypt' Error:Field validation for 'Crypt' failed on the 'required' tag") - -	// crypt bytes too long -	r.Crypt = []byte("1234567890123456789012345678901234567890") -	err = validate.Struct(r) -	suite.EqualError(err, "Key: 'RouterSession.Crypt' Error:Field validation for 'Crypt' failed on the 'len' tag") - -	// crypt bytes too short -	r.Crypt = []byte("12345678901") -	err = validate.Struct(r) -	suite.EqualError(err, "Key: 'RouterSession.Crypt' Error:Field validation for 'Crypt' failed on the 'len' tag") -} - -func TestRouterSessionValidateTestSuite(t *testing.T) { -	suite.Run(t, new(RouterSessionValidateTestSuite)) -} diff --git a/internal/validate/status_test.go b/internal/validate/status_test.go deleted file mode 100644 index db0cd8fda..000000000 --- a/internal/validate/status_test.go +++ /dev/null @@ -1,160 +0,0 @@ -// GoToSocial -// Copyright (C) GoToSocial Authors admin@gotosocial.org -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// 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 validate_test - -import ( -	"testing" -	"time" - -	"github.com/stretchr/testify/suite" -	"github.com/superseriousbusiness/gotosocial/internal/ap" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" -	"github.com/superseriousbusiness/gotosocial/internal/validate" -	"github.com/superseriousbusiness/gotosocial/testrig" -) - -func happyStatus() *gtsmodel.Status { -	return >smodel.Status{ -		ID:                       "01FEBBH6NYDG87NK6A6EC543ED", -		CreatedAt:                time.Now(), -		UpdatedAt:                time.Now(), -		URI:                      "https://example.org/users/test_user/statuses/01FEBBH6NYDG87NK6A6EC543ED", -		URL:                      "https://example.org/@test_user/01FEBBH6NYDG87NK6A6EC543ED", -		Content:                  "<p>Test status! #hello</p>", -		AttachmentIDs:            []string{"01FEBBKZBY9H5FEP3PHVVAAGN1", "01FEBBM7S2R4WT6WWW22KN1PWE"}, -		Attachments:              nil, -		TagIDs:                   []string{"01FEBBNBMBSN1FESMZ1TCXNWYP"}, -		Tags:                     nil, -		MentionIDs:               nil, -		Mentions:                 nil, -		EmojiIDs:                 nil, -		Emojis:                   nil, -		Local:                    testrig.TrueBool(), -		AccountID:                "01FEBBQ4KEP3824WW61MF52638", -		Account:                  nil, -		AccountURI:               "https://example.org/users/test_user", -		InReplyToID:              "", -		InReplyToURI:             "", -		InReplyToAccountID:       "", -		InReplyTo:                nil, -		InReplyToAccount:         nil, -		BoostOfID:                "", -		BoostOfAccountID:         "", -		BoostOf:                  nil, -		BoostOfAccount:           nil, -		ContentWarning:           "hello world test post", -		Visibility:               gtsmodel.VisibilityPublic, -		Sensitive:                testrig.FalseBool(), -		Language:                 "en", -		CreatedWithApplicationID: "01FEBBZHF4GFVRXSJVXD0JTZZ2", -		CreatedWithApplication:   nil, -		Federated:                testrig.TrueBool(), -		Boostable:                testrig.TrueBool(), -		Replyable:                testrig.TrueBool(), -		Likeable:                 testrig.TrueBool(), -		ActivityStreamsType:      ap.ObjectNote, -		Text:                     "Test status! #hello", -	} -} - -type StatusValidateTestSuite struct { -	suite.Suite -} - -func (suite *StatusValidateTestSuite) TestValidateStatusHappyPath() { -	// no problem here -	s := happyStatus() -	err := validate.Struct(s) -	suite.NoError(err) -} - -func (suite *StatusValidateTestSuite) TestValidateStatusBadID() { -	s := happyStatus() - -	s.ID = "" -	err := validate.Struct(s) -	suite.EqualError(err, "Key: 'Status.ID' Error:Field validation for 'ID' failed on the 'required' tag") - -	s.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB" -	err = validate.Struct(s) -	suite.EqualError(err, "Key: 'Status.ID' Error:Field validation for 'ID' failed on the 'ulid' tag") -} - -func (suite *StatusValidateTestSuite) TestValidateStatusAttachmentIDs() { -	s := happyStatus() - -	s.AttachmentIDs[0] = "" -	err := validate.Struct(s) -	suite.EqualError(err, "Key: 'Status.AttachmentIDs[0]' Error:Field validation for 'AttachmentIDs[0]' failed on the 'ulid' tag") - -	s.AttachmentIDs[0] = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB" -	err = validate.Struct(s) -	suite.EqualError(err, "Key: 'Status.AttachmentIDs[0]' Error:Field validation for 'AttachmentIDs[0]' failed on the 'ulid' tag") - -	s.AttachmentIDs[1] = "" -	err = validate.Struct(s) -	suite.EqualError(err, "Key: 'Status.AttachmentIDs[0]' Error:Field validation for 'AttachmentIDs[0]' failed on the 'ulid' tag\nKey: 'Status.AttachmentIDs[1]' Error:Field validation for 'AttachmentIDs[1]' failed on the 'ulid' tag") - -	s.AttachmentIDs = []string{} -	err = validate.Struct(s) -	suite.NoError(err) - -	s.AttachmentIDs = nil -	err = validate.Struct(s) -	suite.NoError(err) -} - -func (suite *StatusValidateTestSuite) TestStatusApplicationID() { -	s := happyStatus() - -	s.CreatedWithApplicationID = "" -	err := validate.Struct(s) -	suite.EqualError(err, "Key: 'Status.CreatedWithApplicationID' Error:Field validation for 'CreatedWithApplicationID' failed on the 'required_if' tag") - -	s.Local = testrig.FalseBool() -	err = validate.Struct(s) -	suite.NoError(err) -} - -func (suite *StatusValidateTestSuite) TestValidateStatusReplyFields() { -	s := happyStatus() - -	s.InReplyToAccountID = "01FEBCTP6DN7961PN81C3DVM4N                         " -	err := validate.Struct(s) -	suite.EqualError(err, "Key: 'Status.InReplyToID' Error:Field validation for 'InReplyToID' failed on the 'required_with' tag\nKey: 'Status.InReplyToURI' Error:Field validation for 'InReplyToURI' failed on the 'required_with' tag\nKey: 'Status.InReplyToAccountID' Error:Field validation for 'InReplyToAccountID' failed on the 'ulid' tag") - -	s.InReplyToAccountID = "01FEBCTP6DN7961PN81C3DVM4N" -	err = validate.Struct(s) -	suite.EqualError(err, "Key: 'Status.InReplyToID' Error:Field validation for 'InReplyToID' failed on the 'required_with' tag\nKey: 'Status.InReplyToURI' Error:Field validation for 'InReplyToURI' failed on the 'required_with' tag") - -	s.InReplyToURI = "https://example.org/users/mmbop/statuses/aaaaaaaa" -	err = validate.Struct(s) -	suite.EqualError(err, "Key: 'Status.InReplyToID' Error:Field validation for 'InReplyToID' failed on the 'required_with' tag") - -	s.InReplyToID = "not a valid ulid" -	err = validate.Struct(s) -	suite.EqualError(err, "Key: 'Status.InReplyToID' Error:Field validation for 'InReplyToID' failed on the 'ulid' tag") - -	s.InReplyToID = "01FEBD07E72DEY6YB9K10ZA6ST" -	err = validate.Struct(s) -	suite.NoError(err) -} - -func TestStatusValidateTestSuite(t *testing.T) { -	suite.Run(t, new(StatusValidateTestSuite)) -} diff --git a/internal/validate/statusbookmark_test.go b/internal/validate/statusbookmark_test.go deleted file mode 100644 index 3be9e56ed..000000000 --- a/internal/validate/statusbookmark_test.go +++ /dev/null @@ -1,87 +0,0 @@ -// GoToSocial -// Copyright (C) GoToSocial Authors admin@gotosocial.org -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// 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 validate_test - -import ( -	"testing" -	"time" - -	"github.com/stretchr/testify/suite" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" -	"github.com/superseriousbusiness/gotosocial/internal/validate" -) - -func happyStatusBookmark() *gtsmodel.StatusBookmark { -	return >smodel.StatusBookmark{ -		ID:              "01FE91RJR88PSEEE30EV35QR8N", -		CreatedAt:       time.Now(), -		AccountID:       "01FE96MAE58MXCE5C4SSMEMCEK", -		Account:         nil, -		TargetAccountID: "01FE96MXRHWZHKC0WH5FT82H1A", -		TargetAccount:   nil, -		StatusID:        "01FE96NBPNJNY26730FT6GZTFE", -		Status:          nil, -	} -} - -type StatusBookmarkValidateTestSuite struct { -	suite.Suite -} - -func (suite *StatusBookmarkValidateTestSuite) TestValidateStatusBookmarkHappyPath() { -	// no problem here -	s := happyStatusBookmark() -	err := validate.Struct(s) -	suite.NoError(err) -} - -func (suite *StatusBookmarkValidateTestSuite) TestValidateStatusBookmarkBadID() { -	s := happyStatusBookmark() - -	s.ID = "" -	err := validate.Struct(s) -	suite.EqualError(err, "Key: 'StatusBookmark.ID' Error:Field validation for 'ID' failed on the 'required' tag") - -	s.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB" -	err = validate.Struct(s) -	suite.EqualError(err, "Key: 'StatusBookmark.ID' Error:Field validation for 'ID' failed on the 'ulid' tag") -} - -func (suite *StatusBookmarkValidateTestSuite) TestValidateStatusBookmarkDodgyStatusID() { -	s := happyStatusBookmark() - -	s.StatusID = "9HZJ76B6VXSKF" -	err := validate.Struct(s) -	suite.EqualError(err, "Key: 'StatusBookmark.StatusID' Error:Field validation for 'StatusID' failed on the 'ulid' tag") - -	s.StatusID = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!!!!!!!!!!!!" -	err = validate.Struct(s) -	suite.EqualError(err, "Key: 'StatusBookmark.StatusID' Error:Field validation for 'StatusID' failed on the 'ulid' tag") -} - -func (suite *StatusBookmarkValidateTestSuite) TestValidateStatusBookmarkNoCreatedAt() { -	s := happyStatusBookmark() - -	s.CreatedAt = time.Time{} -	err := validate.Struct(s) -	suite.NoError(err) -} - -func TestStatusBookmarkValidateTestSuite(t *testing.T) { -	suite.Run(t, new(StatusBookmarkValidateTestSuite)) -} diff --git a/internal/validate/statusfave_test.go b/internal/validate/statusfave_test.go deleted file mode 100644 index e864e39f2..000000000 --- a/internal/validate/statusfave_test.go +++ /dev/null @@ -1,100 +0,0 @@ -// GoToSocial -// Copyright (C) GoToSocial Authors admin@gotosocial.org -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// 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 validate_test - -import ( -	"testing" -	"time" - -	"github.com/stretchr/testify/suite" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" -	"github.com/superseriousbusiness/gotosocial/internal/validate" -) - -func happyStatusFave() *gtsmodel.StatusFave { -	return >smodel.StatusFave{ -		ID:              "01FE91RJR88PSEEE30EV35QR8N", -		CreatedAt:       time.Now(), -		AccountID:       "01FE96MAE58MXCE5C4SSMEMCEK", -		Account:         nil, -		TargetAccountID: "01FE96MXRHWZHKC0WH5FT82H1A", -		TargetAccount:   nil, -		StatusID:        "01FE96NBPNJNY26730FT6GZTFE", -		Status:          nil, -		URI:             "https://example.org/users/user1/activity/faves/01FE91RJR88PSEEE30EV35QR8N", -	} -} - -type StatusFaveValidateTestSuite struct { -	suite.Suite -} - -func (suite *StatusFaveValidateTestSuite) TestValidateStatusFaveHappyPath() { -	// no problem here -	f := happyStatusFave() -	err := validate.Struct(f) -	suite.NoError(err) -} - -func (suite *StatusFaveValidateTestSuite) TestValidateStatusFaveBadID() { -	f := happyStatusFave() - -	f.ID = "" -	err := validate.Struct(f) -	suite.EqualError(err, "Key: 'StatusFave.ID' Error:Field validation for 'ID' failed on the 'required' tag") - -	f.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB" -	err = validate.Struct(f) -	suite.EqualError(err, "Key: 'StatusFave.ID' Error:Field validation for 'ID' failed on the 'ulid' tag") -} - -func (suite *StatusFaveValidateTestSuite) TestValidateStatusFaveDodgyStatusID() { -	f := happyStatusFave() - -	f.StatusID = "9HZJ76B6VXSKF" -	err := validate.Struct(f) -	suite.EqualError(err, "Key: 'StatusFave.StatusID' Error:Field validation for 'StatusID' failed on the 'ulid' tag") - -	f.StatusID = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!!!!!!!!!!!!" -	err = validate.Struct(f) -	suite.EqualError(err, "Key: 'StatusFave.StatusID' Error:Field validation for 'StatusID' failed on the 'ulid' tag") -} - -func (suite *StatusFaveValidateTestSuite) TestValidateStatusFaveNoCreatedAt() { -	f := happyStatusFave() - -	f.CreatedAt = time.Time{} -	err := validate.Struct(f) -	suite.NoError(err) -} - -func (suite *StatusFaveValidateTestSuite) TestValidateStatusFaveNoURI() { -	f := happyStatusFave() - -	f.URI = "" -	err := validate.Struct(f) -	suite.EqualError(err, "Key: 'StatusFave.URI' Error:Field validation for 'URI' failed on the 'required' tag") - -	f.URI = "this-is-not-a-valid-url" -	err = validate.Struct(f) -	suite.EqualError(err, "Key: 'StatusFave.URI' Error:Field validation for 'URI' failed on the 'url' tag") -} - -func TestStatusFaveValidateTestSuite(t *testing.T) { -	suite.Run(t, new(StatusFaveValidateTestSuite)) -} diff --git a/internal/validate/statusmute_test.go b/internal/validate/statusmute_test.go deleted file mode 100644 index 20358bb23..000000000 --- a/internal/validate/statusmute_test.go +++ /dev/null @@ -1,87 +0,0 @@ -// GoToSocial -// Copyright (C) GoToSocial Authors admin@gotosocial.org -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// 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 validate_test - -import ( -	"testing" -	"time" - -	"github.com/stretchr/testify/suite" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" -	"github.com/superseriousbusiness/gotosocial/internal/validate" -) - -func happyStatusMute() *gtsmodel.StatusMute { -	return >smodel.StatusMute{ -		ID:              "01FE91RJR88PSEEE30EV35QR8N", -		CreatedAt:       time.Now(), -		AccountID:       "01FE96MAE58MXCE5C4SSMEMCEK", -		Account:         nil, -		TargetAccountID: "01FE96MXRHWZHKC0WH5FT82H1A", -		TargetAccount:   nil, -		StatusID:        "01FE96NBPNJNY26730FT6GZTFE", -		Status:          nil, -	} -} - -type StatusMuteValidateTestSuite struct { -	suite.Suite -} - -func (suite *StatusMuteValidateTestSuite) TestValidateStatusMuteHappyPath() { -	// no problem here -	m := happyStatusMute() -	err := validate.Struct(m) -	suite.NoError(err) -} - -func (suite *StatusMuteValidateTestSuite) TestValidateStatusMuteBadID() { -	m := happyStatusMute() - -	m.ID = "" -	err := validate.Struct(m) -	suite.EqualError(err, "Key: 'StatusMute.ID' Error:Field validation for 'ID' failed on the 'required' tag") - -	m.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB" -	err = validate.Struct(m) -	suite.EqualError(err, "Key: 'StatusMute.ID' Error:Field validation for 'ID' failed on the 'ulid' tag") -} - -func (suite *StatusMuteValidateTestSuite) TestValidateStatusMuteDodgyStatusID() { -	m := happyStatusMute() - -	m.StatusID = "9HZJ76B6VXSKF" -	err := validate.Struct(m) -	suite.EqualError(err, "Key: 'StatusMute.StatusID' Error:Field validation for 'StatusID' failed on the 'ulid' tag") - -	m.StatusID = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!!!!!!!!!!!!" -	err = validate.Struct(m) -	suite.EqualError(err, "Key: 'StatusMute.StatusID' Error:Field validation for 'StatusID' failed on the 'ulid' tag") -} - -func (suite *StatusMuteValidateTestSuite) TestValidateStatusMuteNoCreatedAt() { -	m := happyStatusMute() - -	m.CreatedAt = time.Time{} -	err := validate.Struct(m) -	suite.NoError(err) -} - -func TestStatusMuteValidateTestSuite(t *testing.T) { -	suite.Run(t, new(StatusMuteValidateTestSuite)) -} diff --git a/internal/validate/structvalidation.go b/internal/validate/structvalidation.go deleted file mode 100644 index 573e79fd2..000000000 --- a/internal/validate/structvalidation.go +++ /dev/null @@ -1,67 +0,0 @@ -// GoToSocial -// Copyright (C) GoToSocial Authors admin@gotosocial.org -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// 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 validate - -import ( -	"reflect" - -	"github.com/go-playground/validator/v10" -	"github.com/superseriousbusiness/gotosocial/internal/regexes" -) - -var v *validator.Validate - -func ulidValidator(fl validator.FieldLevel) bool { -	field := fl.Field() - -	switch field.Kind() { -	case reflect.String: -		return regexes.ULID.MatchString(field.String()) -	default: -		return false -	} -} - -func init() { -	v = validator.New() -	if err := v.RegisterValidation("ulid", ulidValidator); err != nil { -		panic(err) -	} -} - -// Struct validates the passed struct, returning validator.ValidationErrors if invalid, or nil if OK. -func Struct(s interface{}) error { -	return processValidationError(v.Struct(s)) -} - -func processValidationError(err error) error { -	if err == nil { -		return nil -	} - -	if ive, ok := err.(*validator.InvalidValidationError); ok { -		panic(ive) -	} - -	valErr, ok := err.(validator.ValidationErrors) -	if !ok { -		panic("*validator.InvalidValidationError could not be coerced to validator.ValidationErrors") -	} - -	return valErr -} diff --git a/internal/validate/structvalidation_test.go b/internal/validate/structvalidation_test.go deleted file mode 100644 index f8ad514cf..000000000 --- a/internal/validate/structvalidation_test.go +++ /dev/null @@ -1,70 +0,0 @@ -// GoToSocial -// Copyright (C) GoToSocial Authors admin@gotosocial.org -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// 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 validate_test - -import ( -	"testing" - -	"github.com/stretchr/testify/suite" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" -	"github.com/superseriousbusiness/gotosocial/internal/validate" -) - -type ValidateTestSuite struct { -	suite.Suite -} - -func (suite *ValidateTestSuite) TestValidateNilPointer() { -	var nilUser *gtsmodel.User -	suite.Panics(func() { -		validate.Struct(nilUser) -	}) -} - -func (suite *ValidateTestSuite) TestValidatePointer() { -	user := >smodel.User{} -	err := validate.Struct(user) -	suite.EqualError(err, "Key: 'User.ID' Error:Field validation for 'ID' failed on the 'required' tag\nKey: 'User.AccountID' Error:Field validation for 'AccountID' failed on the 'required' tag\nKey: 'User.EncryptedPassword' Error:Field validation for 'EncryptedPassword' failed on the 'required' tag\nKey: 'User.UnconfirmedEmail' Error:Field validation for 'UnconfirmedEmail' failed on the 'required_without' tag") -} - -func (suite *ValidateTestSuite) TestValidateNil() { -	suite.Panics(func() { -		validate.Struct(nil) -	}) -} - -func (suite *ValidateTestSuite) TestValidateWeirdULID() { -	type a struct { -		ID bool `validate:"required,ulid"` -	} - -	err := validate.Struct(a{ID: true}) -	suite.Error(err) -} - -func (suite *ValidateTestSuite) TestValidateNotStruct() { -	type aaaaaaa string -	aaaaaa := aaaaaaa("aaaa") -	suite.Panics(func() { -		validate.Struct(aaaaaa) -	}) -} - -func TestValidateTestSuite(t *testing.T) { -	suite.Run(t, new(ValidateTestSuite)) -} diff --git a/internal/validate/token_test.go b/internal/validate/token_test.go deleted file mode 100644 index 2ff0e0721..000000000 --- a/internal/validate/token_test.go +++ /dev/null @@ -1,98 +0,0 @@ -// GoToSocial -// Copyright (C) GoToSocial Authors admin@gotosocial.org -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// 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 validate_test - -import ( -	"testing" -	"time" - -	"github.com/stretchr/testify/suite" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" -	"github.com/superseriousbusiness/gotosocial/internal/validate" -) - -func happyToken() *gtsmodel.Token { -	return >smodel.Token{ -		ID:          "01FE91RJR88PSEEE30EV35QR8N", -		CreatedAt:   time.Now(), -		UpdatedAt:   time.Now(), -		ClientID:    "01FEEDMF6C0QD589MRK7919Z0R", -		UserID:      "01FEK0BFJKYXB4Y51RBQ7P5P79", -		RedirectURI: "oauth2redirect://com.keylesspalace.tusky/", -		Scope:       "read write follow", -	} -} - -type TokenValidateTestSuite struct { -	suite.Suite -} - -func (suite *TokenValidateTestSuite) TestValidateTokenHappyPath() { -	// no problem here -	t := happyToken() -	err := validate.Struct(t) -	suite.NoError(err) -} - -func (suite *TokenValidateTestSuite) TestValidateTokenBadID() { -	t := happyToken() - -	t.ID = "" -	err := validate.Struct(t) -	suite.EqualError(err, "Key: 'Token.ID' Error:Field validation for 'ID' failed on the 'required' tag") - -	t.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB" -	err = validate.Struct(t) -	suite.EqualError(err, "Key: 'Token.ID' Error:Field validation for 'ID' failed on the 'ulid' tag") -} - -func (suite *TokenValidateTestSuite) TestValidateTokenNoCreatedAt() { -	t := happyToken() - -	t.CreatedAt = time.Time{} -	err := validate.Struct(t) -	suite.NoError(err) -} - -func (suite *TokenValidateTestSuite) TestValidateTokenRedirectURI() { -	t := happyToken() - -	t.RedirectURI = "invalid-uri" -	err := validate.Struct(t) -	suite.EqualError(err, "Key: 'Token.RedirectURI' Error:Field validation for 'RedirectURI' failed on the 'uri' tag") - -	t.RedirectURI = "" -	err = validate.Struct(t) -	suite.EqualError(err, "Key: 'Token.RedirectURI' Error:Field validation for 'RedirectURI' failed on the 'required' tag") - -	t.RedirectURI = "urn:ietf:wg:oauth:2.0:oob" -	err = validate.Struct(t) -	suite.NoError(err) -} - -func (suite *TokenValidateTestSuite) TestValidateTokenScope() { -	t := happyToken() - -	t.Scope = "" -	err := validate.Struct(t) -	suite.EqualError(err, "Key: 'Token.Scope' Error:Field validation for 'Scope' failed on the 'required' tag") -} - -func TestTokenValidateTestSuite(t *testing.T) { -	suite.Run(t, new(TokenValidateTestSuite)) -} diff --git a/internal/validate/user_test.go b/internal/validate/user_test.go deleted file mode 100644 index f61ff6e2f..000000000 --- a/internal/validate/user_test.go +++ /dev/null @@ -1,134 +0,0 @@ -// GoToSocial -// Copyright (C) GoToSocial Authors admin@gotosocial.org -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// 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 validate_test - -import ( -	"net" -	"testing" -	"time" - -	"github.com/stretchr/testify/suite" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" -	"github.com/superseriousbusiness/gotosocial/internal/validate" -	"github.com/superseriousbusiness/gotosocial/testrig" -) - -func happyUser() *gtsmodel.User { -	return >smodel.User{ -		ID:                     "01FE8TTK9F34BR0KG7639AJQTX", -		Email:                  "whatever@example.org", -		AccountID:              "01FE8TWA7CN8J7237K5DFS1RY5", -		Account:                nil, -		EncryptedPassword:      "$2y$10$tkRapNGW.RWkEuCMWdgArunABFvsPGRvFQY3OibfSJo0RDL3z8WfC", -		CreatedAt:              time.Now(), -		UpdatedAt:              time.Now(), -		SignUpIP:               net.ParseIP("128.64.32.16"), -		CurrentSignInAt:        time.Now(), -		CurrentSignInIP:        net.ParseIP("128.64.32.16"), -		LastSignInAt:           time.Now(), -		LastSignInIP:           net.ParseIP("128.64.32.16"), -		SignInCount:            0, -		InviteID:               "", -		ChosenLanguages:        []string{}, -		FilteredLanguages:      []string{}, -		Locale:                 "en", -		CreatedByApplicationID: "01FE8Y5EHMWCA1MHMTNHRVZ1X4", -		CreatedByApplication:   nil, -		LastEmailedAt:          time.Now(), -		ConfirmationToken:      "", -		ConfirmedAt:            time.Now(), -		ConfirmationSentAt:     time.Time{}, -		UnconfirmedEmail:       "", -		Moderator:              testrig.FalseBool(), -		Admin:                  testrig.FalseBool(), -		Disabled:               testrig.FalseBool(), -		Approved:               testrig.TrueBool(), -	} -} - -type UserValidateTestSuite struct { -	suite.Suite -} - -func (suite *UserValidateTestSuite) TestValidateUserHappyPath() { -	// no problem here -	u := happyUser() -	err := validate.Struct(u) -	suite.NoError(err) -} - -func (suite *UserValidateTestSuite) TestValidateUserNoID() { -	// user has no id set -	u := happyUser() -	u.ID = "" - -	err := validate.Struct(u) -	suite.EqualError(err, "Key: 'User.ID' Error:Field validation for 'ID' failed on the 'required' tag") -} - -func (suite *UserValidateTestSuite) TestValidateUserNoEmail() { -	// user has no email or unconfirmed email set -	u := happyUser() -	u.Email = "" - -	err := validate.Struct(u) -	suite.EqualError(err, "Key: 'User.Email' Error:Field validation for 'Email' failed on the 'required_with' tag\nKey: 'User.UnconfirmedEmail' Error:Field validation for 'UnconfirmedEmail' failed on the 'required_without' tag") -} - -func (suite *UserValidateTestSuite) TestValidateUserOnlyUnconfirmedEmail() { -	// user has only UnconfirmedEmail but ConfirmedAt is set -	u := happyUser() -	u.Email = "" -	u.UnconfirmedEmail = "whatever@example.org" - -	err := validate.Struct(u) -	suite.EqualError(err, "Key: 'User.Email' Error:Field validation for 'Email' failed on the 'required_with' tag") -} - -func (suite *UserValidateTestSuite) TestValidateUserOnlyUnconfirmedEmailOK() { -	// user has only UnconfirmedEmail and ConfirmedAt is not set -	u := happyUser() -	u.Email = "" -	u.UnconfirmedEmail = "whatever@example.org" -	u.ConfirmedAt = time.Time{} - -	err := validate.Struct(u) -	suite.NoError(err) -} - -func (suite *UserValidateTestSuite) TestValidateUserNoConfirmedAt() { -	// user has Email but no ConfirmedAt -	u := happyUser() -	u.ConfirmedAt = time.Time{} - -	err := validate.Struct(u) -	suite.EqualError(err, "Key: 'User.ConfirmedAt' Error:Field validation for 'ConfirmedAt' failed on the 'required_with' tag") -} - -func (suite *UserValidateTestSuite) TestValidateUserUnlikelySignInCount() { -	// user has Email but no ConfirmedAt -	u := happyUser() -	u.SignInCount = -69 - -	err := validate.Struct(u) -	suite.EqualError(err, "Key: 'User.SignInCount' Error:Field validation for 'SignInCount' failed on the 'min' tag") -} - -func TestUserValidateTestSuite(t *testing.T) { -	suite.Run(t, new(UserValidateTestSuite)) -} | 
