summaryrefslogtreecommitdiff
path: root/internal/gtsmodel
diff options
context:
space:
mode:
authorLibravatar tsmethurst <tobi.smethurst@klarrio.com>2021-09-01 18:29:25 +0200
committerLibravatar tsmethurst <tobi.smethurst@klarrio.com>2021-09-01 18:29:25 +0200
commit4696e1a7b389599fa981f334b343daa911b11f5d (patch)
treed1ca0c896cdacb82ad7c64ee150aa32b37d4c053 /internal/gtsmodel
parentmove oauth models into gtsmodel (diff)
downloadgotosocial-4696e1a7b389599fa981f334b343daa911b11f5d.tar.xz
moving stuff around
Diffstat (limited to 'internal/gtsmodel')
-rw-r--r--internal/gtsmodel/account.go35
-rw-r--r--internal/gtsmodel/application.go19
-rw-r--r--internal/gtsmodel/block.go34
-rw-r--r--internal/gtsmodel/block_test.go115
-rw-r--r--internal/gtsmodel/client.go32
-rw-r--r--internal/gtsmodel/domainblock.go20
-rw-r--r--internal/gtsmodel/domainblock_test.go121
-rw-r--r--internal/gtsmodel/emaildomainblock.go12
-rw-r--r--internal/gtsmodel/emaildomainblock_test.go96
-rw-r--r--internal/gtsmodel/emoji.go6
-rw-r--r--internal/gtsmodel/emoji_test.go194
-rw-r--r--internal/gtsmodel/follow.go20
-rw-r--r--internal/gtsmodel/follow_test.go87
-rw-r--r--internal/gtsmodel/followrequest.go20
-rw-r--r--internal/gtsmodel/followrequest_test.go87
-rw-r--r--internal/gtsmodel/instance.go24
-rw-r--r--internal/gtsmodel/instance_test.go145
-rw-r--r--internal/gtsmodel/mediaattachment.go24
-rw-r--r--internal/gtsmodel/mediaattachment_test.go229
-rw-r--r--internal/gtsmodel/mention.go22
-rw-r--r--internal/gtsmodel/mention_test.go101
-rw-r--r--internal/gtsmodel/notification.go5
-rw-r--r--internal/gtsmodel/notification_test.go97
-rw-r--r--internal/gtsmodel/poll.go19
-rw-r--r--internal/gtsmodel/relationship.go36
-rw-r--r--internal/gtsmodel/routersession.go10
-rw-r--r--internal/gtsmodel/routersession_test.go87
-rw-r--r--internal/gtsmodel/status.go12
-rw-r--r--internal/gtsmodel/status_test.go162
-rw-r--r--internal/gtsmodel/statusbookmark.go17
-rw-r--r--internal/gtsmodel/statusbookmark_test.go87
-rw-r--r--internal/gtsmodel/statusfave.go19
-rw-r--r--internal/gtsmodel/statusfave_test.go100
-rw-r--r--internal/gtsmodel/statusmute.go17
-rw-r--r--internal/gtsmodel/statusmute_test.go87
-rw-r--r--internal/gtsmodel/stream.go38
-rw-r--r--internal/gtsmodel/tag.go18
-rw-r--r--internal/gtsmodel/tag_test.go92
-rw-r--r--internal/gtsmodel/token.go43
-rw-r--r--internal/gtsmodel/user.go71
-rw-r--r--internal/gtsmodel/user_test.go124
-rw-r--r--internal/gtsmodel/validate.go75
-rw-r--r--internal/gtsmodel/validate_test.go64
43 files changed, 274 insertions, 2449 deletions
diff --git a/internal/gtsmodel/account.go b/internal/gtsmodel/account.go
index 75ea02b4f..4f385b3a6 100644
--- a/internal/gtsmodel/account.go
+++ b/internal/gtsmodel/account.go
@@ -30,8 +30,8 @@ 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:",nullzero,notnull,default:current_timestamp"` // when was item created
- UpdatedAt time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"` // when was item last updated
+ CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created
+ UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated
Username string `validate:"required" bun:",nullzero,notnull,unique:userdomain"` // Username of the account, should just be a string of [a-zA-Z0-9_]. Can be added to domain to create the full username in the form ``[username]@[domain]`` eg., ``user_96@example.org``. Username and domain should be unique *with* each other
Domain string `validate:"omitempty,fqdn" bun:",nullzero,unique:userdomain"` // Domain of the account, will be null if this is a local account, otherwise something like ``example.org`` or ``mastodon.social``. Should be unique with username.
AvatarMediaAttachmentID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // Database ID of the media attachment, if present
@@ -54,20 +54,20 @@ type Account struct {
Sensitive bool `validate:"-" bun:",nullzero,default:false"` // Set posts from this account to sensitive by default?
Language string `validate:"-" bun:",nullzero,notnull,default:'en'"` // What language does this account post in?
URI string `validate:"required,url" bun:",nullzero,notnull,unique"` // ActivityPub URI for this account.
- URL string `validate:"omitempty,url" bun:",unique,nullzero"` // Web URL for this account's profile
- LastWebfingeredAt time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"` // Last time this account was refreshed/located with webfinger.
+ URL string `validate:"omitempty,url" bun:",nullzero,unique"` // Web URL for this account's profile
+ LastWebfingeredAt time.Time `validate:"required_with=Domain" bun:"type:timestamp,nullzero"` // Last time this account was refreshed/located with webfinger.
InboxURI string `validate:"omitempty,url" bun:",nullzero,unique"` // Address of this account's ActivityPub inbox, for sending activity to
OutboxURI string `validate:"omitempty,url" bun:",nullzero,unique"` // Address of this account's activitypub outbox
FollowingURI string `validate:"omitempty,url" bun:",nullzero,unique"` // URI for getting the following list of this account
FollowersURI string `validate:"omitempty,url" bun:",nullzero,unique"` // URI for getting the followers list of this account
FeaturedCollectionURI string `validate:"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?
+ ActorType string `validate:"oneof=Application Group Organization Person Service" bun:",nullzero,notnull"` // What type of activitypub actor is this account?
PrivateKey *rsa.PrivateKey `validate:"required_without=Domain"` // Privatekey for validating activitypub requests, will only be defined for local accounts
PublicKey *rsa.PublicKey `validate:"required"` // Publickey for encoding activitypub requests, will be defined for both local and remote accounts
- PublicKeyURI string `validate:"required" bun:",nullzero,notnull"` // Web-reachable location of this account's public key
- SensitizedAt time.Time `validate:"-" bun:",nullzero"` // When was this account set to have all its media shown as sensitive?
- SilencedAt time.Time `validate:"-" bun:",nullzero"` // When was this account silenced (eg., statuses only visible to followers, not public)?
- SuspendedAt time.Time `validate:"-" bun:",nullzero"` // When was this account suspended (eg., don't allow it to log in/post, don't accept media/posts from this account)
+ PublicKeyURI string `validate:"required,url" bun:",nullzero,notnull,unique"` // Web-reachable location of this account's public key
+ SensitizedAt time.Time `validate:"-" bun:"type:timestamp,nullzero"` // When was this account set to have all its media shown as sensitive?
+ SilencedAt time.Time `validate:"-" bun:"type:timestamp,nullzero"` // When was this account silenced (eg., statuses only visible to followers, not public)?
+ SuspendedAt time.Time `validate:"-" bun:"type:timestamp,nullzero"` // When was this account suspended (eg., don't allow it to log in/post, don't accept media/posts from this account)
HideCollections bool `validate:"-" bun:",nullzero,default:false"` // Hide this account's collections
SuspensionOrigin string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // id of the database entry that caused this account to become suspended -- can be an account ID or a domain block ID
}
@@ -80,3 +80,20 @@ type Field struct {
Value string `validate:"required"` // Value of this field.
VerifiedAt time.Time `validate:"-" bun:",nullzero"` // This field was verified at (optional).
}
+
+// Relationship describes a requester's relationship with another account.
+type Relationship struct {
+ ID string // The account id.
+ Following bool // Are you following this user?
+ ShowingReblogs bool // Are you receiving this user's boosts in your home timeline?
+ Notifying bool // Have you enabled notifications for this user?
+ FollowedBy bool // Are you followed by this user?
+ Blocking bool // Are you blocking this user?
+ BlockedBy bool // Is this user blocking you?
+ Muting bool // Are you muting this user?
+ MutingNotifications bool // Are you muting notifications from this user?
+ Requested bool // Do you have a pending follow request for this user?
+ DomainBlocking bool // Are you blocking this user's domain?
+ Endorsed bool // Are you featuring this user on your profile?
+ Note string // Your note on this account.
+}
diff --git a/internal/gtsmodel/application.go b/internal/gtsmodel/application.go
index 0791aae6a..30035123e 100644
--- a/internal/gtsmodel/application.go
+++ b/internal/gtsmodel/application.go
@@ -18,15 +18,18 @@
package gtsmodel
+import "time"
+
// Application represents an application that can perform actions on behalf of a user.
// It is used to authorize tokens etc, and is associated with an oauth client id in the database.
type Application struct {
- ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull"` // id of this application in the db
- Name string `validate:"required" bun:",nullzero,notnull"` // name of the application given when it was created (eg., 'tusky')
- Website string `validate:"omitempty,url" bun:",nullzero"` // website for the application given when it was created (eg., 'https://tusky.app')
- RedirectURI string `validate:"required" bun:",nullzero,notnull"` // redirect uri requested by the application for oauth2 flow
- ClientID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // id of the associated oauth client entity in the db
- ClientSecret string `validate:"required,uuid" bun:",nullzero,notnull"` // secret of the associated oauth client entity in the db
- Scopes string `validate:"required" bun:",nullzero,default:'read'"` // scopes requested when this app was created
- VapidKey string `validate:"-" bun:",nullzero"` // a vapid key generated for this app when it was created
+ ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database
+ CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created
+ UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated
+ Name string `validate:"required" bun:",nullzero,notnull"` // name of the application given when it was created (eg., 'tusky')
+ Website string `validate:"omitempty,url" bun:",nullzero"` // website for the application given when it was created (eg., 'https://tusky.app')
+ RedirectURI string `validate:"required" bun:",nullzero,notnull"` // redirect uri requested by the application for oauth2 flow
+ ClientID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // id of the associated oauth client entity in the db
+ ClientSecret string `validate:"required,uuid" bun:",nullzero,notnull"` // secret of the associated oauth client entity in the db
+ Scopes string `validate:"required" bun:",nullzero,notnull,default:'read'"` // scopes requested when this app was created
}
diff --git a/internal/gtsmodel/block.go b/internal/gtsmodel/block.go
index 61595c12d..2cc089e6b 100644
--- a/internal/gtsmodel/block.go
+++ b/internal/gtsmodel/block.go
@@ -1,15 +1,33 @@
+/*
+ GoToSocial
+ Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
package gtsmodel
import "time"
// Block refers to the blocking of one account by another.
type Block struct {
- ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database
- CreatedAt time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"` // when was item created
- UpdatedAt time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"` // when was item last updated
- URI string `validate:"required,url" bun:",notnull,nullzero,unique"` // ActivityPub uri of this block.
- AccountID string `validate:"required,ulid" bun:"type:CHAR(26),unique:blocksrctarget,notnull"` // Who does this block originate from?
- Account *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to accountID
- TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),unique:blocksrctarget,notnull"` // Who is the target of this block ?
- TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to targetAccountID
+ ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database
+ CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created
+ UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated
+ URI string `validate:"required,url" bun:",notnull,nullzero,unique"` // ActivityPub uri of this block.
+ AccountID string `validate:"required,ulid" bun:"type:CHAR(26),unique:blocksrctarget,notnull"` // Who does this block originate from?
+ Account *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to accountID
+ TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),unique:blocksrctarget,notnull"` // Who is the target of this block ?
+ TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to targetAccountID
}
diff --git a/internal/gtsmodel/block_test.go b/internal/gtsmodel/block_test.go
deleted file mode 100644
index 307f26cd9..000000000
--- a/internal/gtsmodel/block_test.go
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package gtsmodel_test
-
-import (
- "testing"
- "time"
-
- "github.com/stretchr/testify/suite"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
-)
-
-func happyBlock() *gtsmodel.Block {
- return &gtsmodel.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
- d := happyBlock()
- err := gtsmodel.ValidateStruct(*d)
- suite.NoError(err)
-}
-
-func (suite *BlockValidateTestSuite) TestValidateBlockBadID() {
- d := happyBlock()
-
- d.ID = ""
- err := gtsmodel.ValidateStruct(*d)
- suite.EqualError(err, "Key: 'Block.ID' Error:Field validation for 'ID' failed on the 'required' tag")
-
- d.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB"
- err = gtsmodel.ValidateStruct(*d)
- suite.EqualError(err, "Key: 'Block.ID' Error:Field validation for 'ID' failed on the 'ulid' tag")
-}
-
-func (suite *BlockValidateTestSuite) TestValidateBlockNoCreatedAt() {
- d := happyBlock()
-
- d.CreatedAt = time.Time{}
- err := gtsmodel.ValidateStruct(*d)
- suite.NoError(err)
-}
-
-func (suite *BlockValidateTestSuite) TestValidateBlockCreatedByAccountID() {
- d := happyBlock()
-
- d.AccountID = ""
- err := gtsmodel.ValidateStruct(*d)
- suite.EqualError(err, "Key: 'Block.AccountID' Error:Field validation for 'AccountID' failed on the 'required' tag")
-
- d.AccountID = "this-is-not-a-valid-ulid"
- err = gtsmodel.ValidateStruct(*d)
- suite.EqualError(err, "Key: 'Block.AccountID' Error:Field validation for 'AccountID' failed on the 'ulid' tag")
-}
-
-func (suite *BlockValidateTestSuite) TestValidateBlockTargetAccountID() {
- d := happyBlock()
-
- d.TargetAccountID = "invalid-ulid"
- err := gtsmodel.ValidateStruct(*d)
- suite.EqualError(err, "Key: 'Block.TargetAccountID' Error:Field validation for 'TargetAccountID' failed on the 'ulid' tag")
-
- d.TargetAccountID = "01FEEDHX4G7EGHF5GD9E82Y51Q"
- err = gtsmodel.ValidateStruct(*d)
- suite.NoError(err)
-
- d.TargetAccountID = ""
- err = gtsmodel.ValidateStruct(*d)
- suite.EqualError(err, "Key: 'Block.TargetAccountID' Error:Field validation for 'TargetAccountID' failed on the 'required' tag")
-}
-
-func (suite *BlockValidateTestSuite) TestValidateBlockURI() {
- d := happyBlock()
-
- d.URI = "invalid-uri"
- err := gtsmodel.ValidateStruct(*d)
- suite.EqualError(err, "Key: 'Block.URI' Error:Field validation for 'URI' failed on the 'url' tag")
-
- d.URI = ""
- err = gtsmodel.ValidateStruct(*d)
- 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/gtsmodel/client.go b/internal/gtsmodel/client.go
index 24028fd69..de9bd569a 100644
--- a/internal/gtsmodel/client.go
+++ b/internal/gtsmodel/client.go
@@ -1,9 +1,31 @@
+/*
+ GoToSocial
+ Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
package gtsmodel
-// Client is a handy little wrapper for typical oauth client details
+import "time"
+
+// Client is a wrapper for OAuth client details.
type Client struct {
- ID string `bun:"type:CHAR(26),pk,notnull"`
- Secret string
- Domain string
- UserID string
+ ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database
+ CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created
+ UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated
+ Secret string `validate:"required,uuid" bun:",nullzero,notnull"` // secret generated when client was created
+ Domain string `validate:"required" bun:",nullzero,notnull"` // domain requested for client
+ UserID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // id of the user that this client acts on behalf of
}
diff --git a/internal/gtsmodel/domainblock.go b/internal/gtsmodel/domainblock.go
index dd05ef0c6..4c72b842a 100644
--- a/internal/gtsmodel/domainblock.go
+++ b/internal/gtsmodel/domainblock.go
@@ -22,14 +22,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:",nullzero,notnull,default:current_timestamp"` // when was item created
- UpdatedAt time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"` // when was item last updated
- Domain string `validate:"required,fqdn" bun:",nullzero,notnull"` // domain to block. Eg. 'whatever.com'
- CreatedByAccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // Account ID of the creator of this block
- CreatedByAccount *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to createdByAccountID
- PrivateComment string `validate:"-" bun:",nullzero"` // Private comment on this block, viewable to admins
- PublicComment string `validate:"-" bun:",nullzero"` // Public comment on this block, viewable (optionally) by everyone
- Obfuscate bool `validate:"-" bun:",nullzero,default:false"` // whether the domain name should appear obfuscated when displaying it publicly
- SubscriptionID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // if this block was created through a subscription, what's the subscription ID?
+ ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database
+ CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created
+ UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated
+ Domain string `validate:"required,fqdn" bun:",nullzero,notnull"` // domain to block. Eg. 'whatever.com'
+ CreatedByAccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // Account ID of the creator of this block
+ CreatedByAccount *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to createdByAccountID
+ PrivateComment string `validate:"-" bun:",nullzero"` // Private comment on this block, viewable to admins
+ PublicComment string `validate:"-" bun:",nullzero"` // Public comment on this block, viewable (optionally) by everyone
+ Obfuscate bool `validate:"-" bun:",nullzero,default:false"` // whether the domain name should appear obfuscated when displaying it publicly
+ SubscriptionID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // if this block was created through a subscription, what's the subscription ID?
}
diff --git a/internal/gtsmodel/domainblock_test.go b/internal/gtsmodel/domainblock_test.go
deleted file mode 100644
index ced29ab31..000000000
--- a/internal/gtsmodel/domainblock_test.go
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package gtsmodel_test
-
-import (
- "testing"
- "time"
-
- "github.com/stretchr/testify/suite"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
-)
-
-func happyDomainBlock() *gtsmodel.DomainBlock {
- return &gtsmodel.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: false,
- SubscriptionID: "",
- }
-}
-
-type DomainBlockValidateTestSuite struct {
- suite.Suite
-}
-
-func (suite *DomainBlockValidateTestSuite) TestValidateDomainBlockHappyPath() {
- // no problem here
- d := happyDomainBlock()
- err := gtsmodel.ValidateStruct(*d)
- suite.NoError(err)
-}
-
-func (suite *DomainBlockValidateTestSuite) TestValidateDomainBlockBadID() {
- d := happyDomainBlock()
-
- d.ID = ""
- err := gtsmodel.ValidateStruct(*d)
- suite.EqualError(err, "Key: 'DomainBlock.ID' Error:Field validation for 'ID' failed on the 'required' tag")
-
- d.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB"
- err = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*d)
- suite.NoError(err)
-}
-
-func (suite *DomainBlockValidateTestSuite) TestValidateDomainBlockBadDomain() {
- d := happyDomainBlock()
-
- d.Domain = ""
- err := gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*d)
- suite.NoError(err)
-}
-
-func (suite *DomainBlockValidateTestSuite) TestValidateDomainSubscriptionID() {
- d := happyDomainBlock()
-
- d.SubscriptionID = "invalid-ulid"
- err := gtsmodel.ValidateStruct(*d)
- suite.EqualError(err, "Key: 'DomainBlock.SubscriptionID' Error:Field validation for 'SubscriptionID' failed on the 'ulid' tag")
-
- d.SubscriptionID = "01FEEDHX4G7EGHF5GD9E82Y51Q"
- err = gtsmodel.ValidateStruct(*d)
- suite.NoError(err)
-}
-
-func TestDomainBlockValidateTestSuite(t *testing.T) {
- suite.Run(t, new(DomainBlockValidateTestSuite))
-}
diff --git a/internal/gtsmodel/emaildomainblock.go b/internal/gtsmodel/emaildomainblock.go
index 38f4a9580..2118068f2 100644
--- a/internal/gtsmodel/emaildomainblock.go
+++ b/internal/gtsmodel/emaildomainblock.go
@@ -22,10 +22,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:",nullzero,notnull,default:current_timestamp"` // when was item created
- UpdatedAt time.Time `validate:"-" bun:",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 `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database
+ CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created
+ UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated
+ Domain string `validate:"required,fqdn" bun:",nullzero,notnull"` // Email domain to block. Eg. 'gmail.com' or 'hotmail.com'
+ CreatedByAccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // Account ID of the creator of this block
+ CreatedByAccount *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to createdByAccountID
}
diff --git a/internal/gtsmodel/emaildomainblock_test.go b/internal/gtsmodel/emaildomainblock_test.go
deleted file mode 100644
index 83d7c4c6a..000000000
--- a/internal/gtsmodel/emaildomainblock_test.go
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package gtsmodel_test
-
-import (
- "testing"
- "time"
-
- "github.com/stretchr/testify/suite"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
-)
-
-func happyEmailDomainBlock() *gtsmodel.EmailDomainBlock {
- return &gtsmodel.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 := gtsmodel.ValidateStruct(*e)
- suite.NoError(err)
-}
-
-func (suite *EmailDomainBlockValidateTestSuite) TestValidateEmailDomainBlockBadID() {
- e := happyEmailDomainBlock()
-
- e.ID = ""
- err := gtsmodel.ValidateStruct(*e)
- suite.EqualError(err, "Key: 'EmailDomainBlock.ID' Error:Field validation for 'ID' failed on the 'required' tag")
-
- e.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB"
- err = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*e)
- suite.NoError(err)
-}
-
-func (suite *EmailDomainBlockValidateTestSuite) TestValidateEmailDomainBlockBadDomain() {
- e := happyEmailDomainBlock()
-
- e.Domain = ""
- err := gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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/gtsmodel/emoji.go b/internal/gtsmodel/emoji.go
index 71287130a..93c43c0f7 100644
--- a/internal/gtsmodel/emoji.go
+++ b/internal/gtsmodel/emoji.go
@@ -23,8 +23,8 @@ import "time"
// Emoji represents a custom emoji that's been uploaded through the admin UI, and is useable by instance denizens.
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:",nullzero,notnull,default:current_timestamp"` // when was item created
- UpdatedAt time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"` // when was item last updated
+ CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created
+ UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated
Shortcode string `validate:"required" bun:",notnull,unique:shortcodedomain"` // String shortcode for this emoji -- the part that's between colons. This should be lowercase a-z_ eg., 'blob_hug' 'purple_heart' Must be unique with domain.
Domain string `validate:"omitempty,fqdn" bun:",notnull,default:'',unique:shortcodedomain"` // Origin domain of this emoji, eg 'example.org', 'queer.party'. empty string for local emojis.
ImageRemoteURL string `validate:"required_without=ImageURL,omitempty,url" bun:",nullzero"` // Where can this emoji be retrieved remotely? Null for local emojis.
@@ -37,7 +37,7 @@ type Emoji struct {
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:",nullzero,notnull,default:current_timestamp"` // When was the emoji image last updated?
+ ImageUpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // When was the emoji image last updated?
Disabled bool `validate:"-" bun:",notnull,default:false"` // Has a moderation action disabled this emoji from being shown?
URI string `validate:"url" bun:",nullzero,notnull,unique"` // ActivityPub uri of this emoji. Something like 'https://example.org/emojis/1234'
VisibleInPicker bool `validate:"-" bun:",notnull,default:true"` // Is this emoji visible in the admin emoji picker?
diff --git a/internal/gtsmodel/emoji_test.go b/internal/gtsmodel/emoji_test.go
deleted file mode 100644
index a0b48040c..000000000
--- a/internal/gtsmodel/emoji_test.go
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package gtsmodel_test
-
-import (
- "os"
- "testing"
- "time"
-
- "github.com/stretchr/testify/suite"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
-)
-
-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 &gtsmodel.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: false,
- URI: "https://example.org/emojis/blob_test",
- VisibleInPicker: true,
- CategoryID: "01FEE47ZH70PWDSEAVBRFNX325",
- }
-}
-
-type EmojiValidateTestSuite struct {
- suite.Suite
-}
-
-func (suite *EmojiValidateTestSuite) TestValidateEmojiHappyPath() {
- // no problem here
- m := happyEmoji()
- err := gtsmodel.ValidateStruct(*m)
- suite.NoError(err)
-}
-
-func (suite *EmojiValidateTestSuite) TestValidateEmojiBadFilePaths() {
- e := happyEmoji()
-
- e.ImagePath = "/tmp/nonexistent/file/for/gotosocial/test"
- err := gtsmodel.ValidateStruct(*e)
- suite.EqualError(err, "Key: 'Emoji.ImagePath' Error:Field validation for 'ImagePath' failed on the 'file' tag")
-
- e.ImagePath = ""
- err = gtsmodel.ValidateStruct(*e)
- suite.EqualError(err, "Key: 'Emoji.ImagePath' Error:Field validation for 'ImagePath' failed on the 'required' tag")
-
- e.ImagePath = "???????????thisnot a valid path####"
- err = gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*e)
- suite.EqualError(err, "Key: 'Emoji.URI' Error:Field validation for 'URI' failed on the 'url' tag")
-
- e.URI = ""
- err = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*e)
- suite.NoError(err)
-
- e.ImageStaticRemoteURL = ""
- err = gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*e)
- suite.NoError(err)
-
- e.ImageURL = ""
- e.ImageStaticURL = ""
- e.ImageRemoteURL = ""
- e.ImageStaticRemoteURL = ""
- err = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*e)
- suite.EqualError(err, "Key: 'Emoji.ImageFileSize' Error:Field validation for 'ImageFileSize' failed on the 'required' tag")
-
- e.ImageStaticFileSize = 0
- err = gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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/gtsmodel/follow.go b/internal/gtsmodel/follow.go
index c2b2633b9..8c4617f48 100644
--- a/internal/gtsmodel/follow.go
+++ b/internal/gtsmodel/follow.go
@@ -22,14 +22,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:",nullzero,notnull,default:current_timestamp"` // when was item created
- UpdatedAt time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"` // when was item last updated
- URI string `validate:"required,url" bun:",notnull,nullzero,unique"` // ActivityPub uri of this follow.
- AccountID string `validate:"required,ulid" bun:"type:CHAR(26),unique:srctarget,notnull"` // Who does this follow originate from?
- Account *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to accountID
- TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),unique:srctarget,notnull"` // Who is the target of this follow ?
- TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to targetAccountID
- ShowReblogs bool `validate:"-" bun:",nullzero,default:true"` // Does this follow also want to see reblogs and not just posts?
- Notify bool `validate:"-" bun:",nullzero,default:false"` // does the following account want to be notified when the followed account posts?
+ ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database
+ CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created
+ UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated
+ URI string `validate:"required,url" bun:",notnull,nullzero,unique"` // ActivityPub uri of this follow.
+ AccountID string `validate:"required,ulid" bun:"type:CHAR(26),unique:srctarget,notnull"` // Who does this follow originate from?
+ Account *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to accountID
+ TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),unique:srctarget,notnull"` // Who is the target of this follow ?
+ TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to targetAccountID
+ ShowReblogs bool `validate:"-" bun:",nullzero,default:true"` // Does this follow also want to see reblogs and not just posts?
+ Notify bool `validate:"-" bun:",nullzero,default:false"` // does the following account want to be notified when the followed account posts?
}
diff --git a/internal/gtsmodel/follow_test.go b/internal/gtsmodel/follow_test.go
deleted file mode 100644
index 2af0f5e4f..000000000
--- a/internal/gtsmodel/follow_test.go
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package gtsmodel_test
-
-import (
- "testing"
- "time"
-
- "github.com/stretchr/testify/suite"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
-)
-
-func happyFollow() *gtsmodel.Follow {
- return &gtsmodel.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 := gtsmodel.ValidateStruct(*f)
- suite.NoError(err)
-}
-
-func (suite *FollowValidateTestSuite) TestValidateFollowBadID() {
- f := happyFollow()
-
- f.ID = ""
- err := gtsmodel.ValidateStruct(*f)
- suite.EqualError(err, "Key: 'Follow.ID' Error:Field validation for 'ID' failed on the 'required' tag")
-
- f.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB"
- err = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*f)
- suite.NoError(err)
-}
-
-func (suite *FollowValidateTestSuite) TestValidateFollowNoURI() {
- f := happyFollow()
-
- f.URI = ""
- err := gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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/gtsmodel/followrequest.go b/internal/gtsmodel/followrequest.go
index ae22f6487..9ffdb5938 100644
--- a/internal/gtsmodel/followrequest.go
+++ b/internal/gtsmodel/followrequest.go
@@ -22,14 +22,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:",nullzero,notnull,default:current_timestamp"` // when was item created
- UpdatedAt time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"` // when was item last updated
- URI string `validate:"required,url" bun:",notnull,nullzero,unique"` // ActivityPub uri of this follow (request).
- AccountID string `validate:"required,ulid" bun:"type:CHAR(26),unique:frsrctarget,notnull"` // Who does this follow request originate from?
- Account *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to accountID
- TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),unique:frsrctarget,notnull"` // Who is the target of this follow request?
- TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to targetAccountID
- ShowReblogs bool `validate:"-" bun:",nullzero,default:true"` // Does this follow also want to see reblogs and not just posts?
- Notify bool `validate:"-" bun:",nullzero,default:false"` // does the following account want to be notified when the followed account posts?
+ ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database
+ CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created
+ UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated
+ URI string `validate:"required,url" bun:",notnull,nullzero,unique"` // ActivityPub uri of this follow (request).
+ AccountID string `validate:"required,ulid" bun:"type:CHAR(26),unique:frsrctarget,notnull"` // Who does this follow request originate from?
+ Account *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to accountID
+ TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),unique:frsrctarget,notnull"` // Who is the target of this follow request?
+ TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to targetAccountID
+ ShowReblogs bool `validate:"-" bun:",nullzero,default:true"` // Does this follow also want to see reblogs and not just posts?
+ Notify bool `validate:"-" bun:",nullzero,default:false"` // does the following account want to be notified when the followed account posts?
}
diff --git a/internal/gtsmodel/followrequest_test.go b/internal/gtsmodel/followrequest_test.go
deleted file mode 100644
index a3ae8ded8..000000000
--- a/internal/gtsmodel/followrequest_test.go
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package gtsmodel_test
-
-import (
- "testing"
- "time"
-
- "github.com/stretchr/testify/suite"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
-)
-
-func happyFollowRequest() *gtsmodel.FollowRequest {
- return &gtsmodel.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 := gtsmodel.ValidateStruct(*f)
- suite.NoError(err)
-}
-
-func (suite *FollowRequestValidateTestSuite) TestValidateFollowRequestBadID() {
- f := happyFollowRequest()
-
- f.ID = ""
- err := gtsmodel.ValidateStruct(*f)
- suite.EqualError(err, "Key: 'FollowRequest.ID' Error:Field validation for 'ID' failed on the 'required' tag")
-
- f.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB"
- err = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*f)
- suite.NoError(err)
-}
-
-func (suite *FollowRequestValidateTestSuite) TestValidateFollowRequestNoURI() {
- f := happyFollowRequest()
-
- f.URI = ""
- err := gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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/gtsmodel/instance.go b/internal/gtsmodel/instance.go
index 4d36dbba8..a7cc8a034 100644
--- a/internal/gtsmodel/instance.go
+++ b/internal/gtsmodel/instance.go
@@ -1,3 +1,21 @@
+/*
+ GoToSocial
+ Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
package gtsmodel
import "time"
@@ -5,12 +23,12 @@ 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:",nullzero,notnull,default:current_timestamp"` // when was item created
- UpdatedAt time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"` // when was item last updated
+ CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created
+ UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated
Domain string `validate:"required,fqdn" bun:",nullzero,notnull,unique"` // Instance domain eg example.org
Title string `validate:"-" bun:",nullzero"` // Title of this instance as it would like to be displayed.
URI string `validate:"required,url" bun:",nullzero,notnull,unique"` // base URI of this instance eg https://example.org
- SuspendedAt time.Time `validate:"-" bun:",nullzero"` // When was this instance suspended, if at all?
+ SuspendedAt time.Time `validate:"-" bun:"type:timestamp,nullzero"` // When was this instance suspended, if at all?
DomainBlockID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // ID of any existing domain block for this instance in the database
DomainBlock *DomainBlock `validate:"-" bun:"rel:belongs-to"` // Domain block corresponding to domainBlockID
ShortDescription string `validate:"-" bun:",nullzero"` // Short description of this instance
diff --git a/internal/gtsmodel/instance_test.go b/internal/gtsmodel/instance_test.go
deleted file mode 100644
index 5c685bb25..000000000
--- a/internal/gtsmodel/instance_test.go
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package gtsmodel_test
-
-import (
- "testing"
- "time"
-
- "github.com/stretchr/testify/suite"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
-)
-
-func happyInstance() *gtsmodel.Instance {
- return &gtsmodel.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 := gtsmodel.ValidateStruct(*m)
- suite.NoError(err)
-}
-
-func (suite *InstanceValidateTestSuite) TestValidateInstanceBadID() {
- m := happyInstance()
-
- m.ID = ""
- err := gtsmodel.ValidateStruct(*m)
- suite.EqualError(err, "Key: 'Instance.ID' Error:Field validation for 'ID' failed on the 'required' tag")
-
- m.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB"
- err = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*i)
- suite.EqualError(err, "Key: 'Instance.URI' Error:Field validation for 'URI' failed on the 'required' tag")
-
- i.URI = "---------------------------"
- err = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*i)
- suite.EqualError(err, "Key: 'Instance.ContactAccountID' Error:Field validation for 'ContactAccountID' failed on the 'ulid' tag")
-
- i.ContactAccountID = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!!!!!!!!!!!!"
- err = gtsmodel.ValidateStruct(*i)
- suite.EqualError(err, "Key: 'Instance.ContactAccountID' Error:Field validation for 'ContactAccountID' failed on the 'ulid' tag")
-
- i.ContactAccountID = ""
- err = gtsmodel.ValidateStruct(*i)
- suite.EqualError(err, "Key: 'Instance.ContactAccountID' Error:Field validation for 'ContactAccountID' failed on the 'required_with' tag")
-
- i.ContactAccountUsername = ""
- err = gtsmodel.ValidateStruct(*i)
- suite.NoError(err)
-}
-
-func (suite *InstanceValidateTestSuite) TestValidateInstanceDomain() {
- i := happyInstance()
-
- i.Domain = "poopoo"
- err := gtsmodel.ValidateStruct(*i)
- suite.EqualError(err, "Key: 'Instance.Domain' Error:Field validation for 'Domain' failed on the 'fqdn' tag")
-
- i.Domain = ""
- err = gtsmodel.ValidateStruct(*i)
- suite.EqualError(err, "Key: 'Instance.Domain' Error:Field validation for 'Domain' failed on the 'required' tag")
-
- i.Domain = "https://aaaaaaaaaaaaah.org"
- err = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*i)
- suite.EqualError(err, "Key: 'Instance.ContactEmail' Error:Field validation for 'ContactEmail' failed on the 'email' tag")
-
- i.ContactEmail = ""
- err = gtsmodel.ValidateStruct(*i)
- suite.NoError(err)
-}
-
-func (suite *InstanceValidateTestSuite) TestValidateInstanceNoCreatedAt() {
- i := happyInstance()
-
- i.CreatedAt = time.Time{}
- err := gtsmodel.ValidateStruct(*i)
- suite.NoError(err)
-}
-
-func TestInstanceValidateTestSuite(t *testing.T) {
- suite.Run(t, new(InstanceValidateTestSuite))
-}
diff --git a/internal/gtsmodel/mediaattachment.go b/internal/gtsmodel/mediaattachment.go
index 53f226ad7..59cf8aac1 100644
--- a/internal/gtsmodel/mediaattachment.go
+++ b/internal/gtsmodel/mediaattachment.go
@@ -26,8 +26,8 @@ import (
// 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:",nullzero,notnull,default:current_timestamp"` // when was item created
- UpdatedAt time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"` // when was item last updated
+ CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created
+ UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated
StatusID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // ID of the status to which this is attached
URL string `validate:"required_without=RemoteURL,omitempty,url" bun:",nullzero"` // Where can the attachment be retrieved on *this* server
RemoteURL string `validate:"required_without=URL,omitempty,url" bun:",nullzero"` // Where can the attachment be retrieved on a remote server (empty for local media)
@@ -47,20 +47,20 @@ type MediaAttachment struct {
// 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:",nullzero,notnull"` // File size in bytes
- UpdatedAt time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"` // When was the file last updated.
+ Path string `validate:"required,file" bun:",nullzero,notnull"` // Path of the file in storage.
+ ContentType string `validate:"required" bun:",nullzero,notnull"` // MIME content type of the file.
+ FileSize int `validate:"required" bun:",nullzero,notnull"` // File size in bytes
+ UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // When was the file last updated.
}
// Thumbnail refers to a small image thumbnail derived from a larger image, video, or audio file.
type Thumbnail struct {
- Path string `validate:"required,file" bun:",nullzero,notnull"` // Path of the file in storage.
- ContentType string `validate:"required" bun:",nullzero,notnull"` // MIME content type of the file.
- FileSize int `validate:"required" bun:",nullzero,notnull"` // File size in bytes
- UpdatedAt time.Time `validate:"-" bun:",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 `validate:"required,file" bun:",nullzero,notnull"` // Path of the file in storage.
+ ContentType string `validate:"required" bun:",nullzero,notnull"` // MIME content type of the file.
+ FileSize int `validate:"required" bun:",nullzero,notnull"` // File size in bytes
+ UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // When was the file last updated.
+ URL string `validate:"required_without=RemoteURL,omitempty,url" bun:",nullzero"` // What is the URL of the thumbnail on the local server
+ RemoteURL string `validate:"required_without=URL,omitempty,url" bun:",nullzero"` // What is the remote URL of the thumbnail (empty for local media)
}
// ProcessingStatus refers to how far along in the processing stage the attachment is.
diff --git a/internal/gtsmodel/mediaattachment_test.go b/internal/gtsmodel/mediaattachment_test.go
deleted file mode 100644
index e1502ba62..000000000
--- a/internal/gtsmodel/mediaattachment_test.go
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package gtsmodel_test
-
-import (
- "os"
- "testing"
- "time"
-
- "github.com/stretchr/testify/suite"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
-)
-
-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 &gtsmodel.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.jpeg",
- 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.jpeg",
- RemoteURL: "",
- },
- Avatar: false,
- Header: false,
- }
-}
-
-type MediaAttachmentValidateTestSuite struct {
- suite.Suite
-}
-
-func (suite *MediaAttachmentValidateTestSuite) TestValidateMediaAttachmentHappyPath() {
- // no problem here
- m := happyMediaAttachment()
- err := gtsmodel.ValidateStruct(*m)
- suite.NoError(err)
-}
-
-func (suite *MediaAttachmentValidateTestSuite) TestValidateMediaAttachmentBadFilePaths() {
- m := happyMediaAttachment()
-
- m.File.Path = "/tmp/nonexistent/file/for/gotosocial/test"
- err := gtsmodel.ValidateStruct(*m)
- suite.EqualError(err, "Key: 'MediaAttachment.File.Path' Error:Field validation for 'Path' failed on the 'file' tag")
-
- m.File.Path = ""
- err = gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*m)
- suite.EqualError(err, "Key: 'MediaAttachment.Type' Error:Field validation for 'Type' failed on the 'oneof' tag")
-
- m.Type = "Not Supported"
- err = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*m)
- suite.NoError(err)
-
- m.FileMeta.Focus.X = 3.6
- err = gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*m)
- suite.EqualError(err, "Key: 'MediaAttachment.URL' Error:Field validation for 'URL' failed on the 'url' tag")
-
- m.URL = ""
- err = gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*m)
- suite.NoError(err)
-}
-
-func (suite *MediaAttachmentValidateTestSuite) TestValidateMediaAttachmentBlurhash() {
- m := happyMediaAttachment()
-
- m.Blurhash = ""
- err := gtsmodel.ValidateStruct(*m)
- suite.EqualError(err, "Key: 'MediaAttachment.Blurhash' Error:Field validation for 'Blurhash' failed on the 'required_if' tag")
-
- m.Type = gtsmodel.FileTypeAudio
- err = gtsmodel.ValidateStruct(*m)
- suite.NoError(err)
-
- m.Blurhash = "some_blurhash"
- err = gtsmodel.ValidateStruct(*m)
- suite.NoError(err)
-}
-
-func (suite *MediaAttachmentValidateTestSuite) TestValidateMediaAttachmentProcessing() {
- m := happyMediaAttachment()
-
- m.Processing = 420
- err := gtsmodel.ValidateStruct(*m)
- suite.EqualError(err, "Key: 'MediaAttachment.Processing' Error:Field validation for 'Processing' failed on the 'oneof' tag")
-
- m.Processing = -5
- err = gtsmodel.ValidateStruct(*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/gtsmodel/mention.go b/internal/gtsmodel/mention.go
index d8359745d..492740d77 100644
--- a/internal/gtsmodel/mention.go
+++ b/internal/gtsmodel/mention.go
@@ -22,17 +22,17 @@ import "time"
// 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:",nullzero,notnull,default:current_timestamp"` // when was item created
- UpdatedAt time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"` // when was item last updated
- StatusID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // ID of the status this mention originates from
- Status *Status `validate:"-" bun:"rel:belongs-to"` // status referred to by statusID
- OriginAccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // ID of the mention creator account
- OriginAccountURI string `validate:"url" bun:",nullzero,notnull"` // ActivityPub URI of the originator/creator of the mention
- OriginAccount *Account `validate:"-" bun:"rel:belongs-to"` // account referred to by originAccountID
- TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // Mention target/receiver account ID
- TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // account referred to by targetAccountID
- Silent bool `validate:"-" bun:",notnull,default:false"` // Prevent this mention from generating a notification?
+ ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database
+ CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created
+ UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated
+ StatusID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // ID of the status this mention originates from
+ Status *Status `validate:"-" bun:"rel:belongs-to"` // status referred to by statusID
+ OriginAccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // ID of the mention creator account
+ OriginAccountURI string `validate:"url" bun:",nullzero,notnull"` // ActivityPub URI of the originator/creator of the mention
+ OriginAccount *Account `validate:"-" bun:"rel:belongs-to"` // account referred to by originAccountID
+ TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // Mention target/receiver account ID
+ TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // account referred to by targetAccountID
+ Silent bool `validate:"-" bun:",notnull,default:false"` // Prevent this mention from generating a notification?
/*
NON-DATABASE CONVENIENCE FIELDS
diff --git a/internal/gtsmodel/mention_test.go b/internal/gtsmodel/mention_test.go
deleted file mode 100644
index ac44e916b..000000000
--- a/internal/gtsmodel/mention_test.go
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package gtsmodel_test
-
-import (
- "testing"
- "time"
-
- "github.com/stretchr/testify/suite"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
-)
-
-func happyMention() *gtsmodel.Mention {
- return &gtsmodel.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 := gtsmodel.ValidateStruct(*m)
- suite.NoError(err)
-}
-
-func (suite *MentionValidateTestSuite) TestValidateMentionBadID() {
- m := happyMention()
-
- m.ID = ""
- err := gtsmodel.ValidateStruct(*m)
- suite.EqualError(err, "Key: 'Mention.ID' Error:Field validation for 'ID' failed on the 'required' tag")
-
- m.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB"
- err = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*m)
- suite.EqualError(err, "Key: 'Mention.OriginAccountURI' Error:Field validation for 'OriginAccountURI' failed on the 'url' tag")
-
- m.OriginAccountURI = "---------------------------"
- err = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*m)
- suite.EqualError(err, "Key: 'Mention.StatusID' Error:Field validation for 'StatusID' failed on the 'ulid' tag")
-
- m.StatusID = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!!!!!!!!!!!!"
- err = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*m)
- suite.NoError(err)
-}
-
-func TestMentionValidateTestSuite(t *testing.T) {
- suite.Run(t, new(MentionValidateTestSuite))
-}
diff --git a/internal/gtsmodel/notification.go b/internal/gtsmodel/notification.go
index bb69bc8d4..1b1f39a77 100644
--- a/internal/gtsmodel/notification.go
+++ b/internal/gtsmodel/notification.go
@@ -22,8 +22,9 @@ 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:"ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database
- CreatedAt time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"` // when was item created
+ ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database
+ CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created
+ UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated // when was item created
NotificationType NotificationType `validate:"oneof=follow follow_request mention reblog favourite poll status" bun:",nullzero,notnull"` // Type of this notification
TargetAccountID string `validate:"ulid" bun:"type:CHAR(26),nullzero,notnull"` // Which account does this notification target (ie., who will receive the notification?)
TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // Which account performed the action that created this notification?
diff --git a/internal/gtsmodel/notification_test.go b/internal/gtsmodel/notification_test.go
deleted file mode 100644
index 507a2cbfd..000000000
--- a/internal/gtsmodel/notification_test.go
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package gtsmodel_test
-
-import (
- "testing"
- "time"
-
- "github.com/stretchr/testify/suite"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
-)
-
-func happyNotification() *gtsmodel.Notification {
- return &gtsmodel.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
- m := happyNotification()
- err := gtsmodel.ValidateStruct(*m)
- suite.NoError(err)
-}
-
-func (suite *NotificationValidateTestSuite) TestValidateNotificationBadID() {
- m := happyNotification()
-
- m.ID = ""
- err := gtsmodel.ValidateStruct(*m)
- suite.EqualError(err, "Key: 'Notification.ID' Error:Field validation for 'ID' failed on the 'ulid' tag")
-
- m.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB"
- err = gtsmodel.ValidateStruct(*m)
- suite.EqualError(err, "Key: 'Notification.ID' Error:Field validation for 'ID' failed on the 'ulid' tag")
-}
-
-func (suite *NotificationValidateTestSuite) TestValidateNotificationStatusID() {
- m := happyNotification()
-
- m.StatusID = ""
- err := gtsmodel.ValidateStruct(*m)
- suite.EqualError(err, "Key: 'Notification.StatusID' Error:Field validation for 'StatusID' failed on the 'required_if' tag")
-
- m.StatusID = "9HZJ76B6VXSKF"
- err = gtsmodel.ValidateStruct(*m)
- suite.EqualError(err, "Key: 'Notification.StatusID' Error:Field validation for 'StatusID' failed on the 'ulid' tag")
-
- m.StatusID = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!!!!!!!!!!!!"
- err = gtsmodel.ValidateStruct(*m)
- suite.EqualError(err, "Key: 'Notification.StatusID' Error:Field validation for 'StatusID' failed on the 'ulid' tag")
-
- m.StatusID = ""
- m.NotificationType = gtsmodel.NotificationFollowRequest
- err = gtsmodel.ValidateStruct(*m)
- suite.NoError(err)
-}
-
-func (suite *NotificationValidateTestSuite) TestValidateNotificationNoCreatedAt() {
- m := happyNotification()
-
- m.CreatedAt = time.Time{}
- err := gtsmodel.ValidateStruct(*m)
- suite.NoError(err)
-}
-
-func TestNotificationValidateTestSuite(t *testing.T) {
- suite.Run(t, new(NotificationValidateTestSuite))
-}
diff --git a/internal/gtsmodel/poll.go b/internal/gtsmodel/poll.go
deleted file mode 100644
index c39497cdd..000000000
--- a/internal/gtsmodel/poll.go
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package gtsmodel
diff --git a/internal/gtsmodel/relationship.go b/internal/gtsmodel/relationship.go
deleted file mode 100644
index 3f753f6e9..000000000
--- a/internal/gtsmodel/relationship.go
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package gtsmodel
-
-// Relationship describes a requester's relationship with another account.
-type Relationship struct {
- ID string // The account id.
- Following bool // Are you following this user?
- ShowingReblogs bool // Are you receiving this user's boosts in your home timeline?
- Notifying bool // Have you enabled notifications for this user?
- FollowedBy bool // Are you followed by this user?
- Blocking bool // Are you blocking this user?
- BlockedBy bool // Is this user blocking you?
- Muting bool // Are you muting this user?
- MutingNotifications bool // Are you muting notifications from this user?
- Requested bool // Do you have a pending follow request for this user?
- DomainBlocking bool // Are you blocking this user's domain?
- Endorsed bool // Are you featuring this user on your profile?
- Note string // Your note on this account.
-}
diff --git a/internal/gtsmodel/routersession.go b/internal/gtsmodel/routersession.go
index 374264fe4..3edb8bc36 100644
--- a/internal/gtsmodel/routersession.go
+++ b/internal/gtsmodel/routersession.go
@@ -18,9 +18,13 @@
package gtsmodel
+import "time"
+
// RouterSession is used to store and retrieve settings for a router session.
type RouterSession struct {
- ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull"`
- Auth []byte `validate:"required,len=32" bun:"type:bytea,notnull,nullzero"`
- Crypt []byte `validate:"required,len=32" bun:"type:bytea,notnull,nullzero"`
+ ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database
+ CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created
+ UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated
+ Auth []byte `validate:"required,len=32" bun:"type:bytea,notnull,nullzero"`
+ Crypt []byte `validate:"required,len=32" bun:"type:bytea,notnull,nullzero"`
}
diff --git a/internal/gtsmodel/routersession_test.go b/internal/gtsmodel/routersession_test.go
deleted file mode 100644
index 3d6e1bcb0..000000000
--- a/internal/gtsmodel/routersession_test.go
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package gtsmodel_test
-
-import (
- "testing"
-
- "github.com/stretchr/testify/suite"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
-)
-
-func happyRouterSession() *gtsmodel.RouterSession {
- return &gtsmodel.RouterSession{
- ID: "01FE91RJR88PSEEE30EV35QR8N",
- Auth: []byte("12345678901234567890123456789012"),
- Crypt: []byte("12345678901234567890123456789012"),
- }
-}
-
-type RouterSessionValidateTestSuite struct {
- suite.Suite
-}
-
-func (suite *RouterSessionValidateTestSuite) TestValidateRouterSessionHappyPath() {
- // no problem here
- r := happyRouterSession()
- err := gtsmodel.ValidateStruct(*r)
- suite.NoError(err)
-}
-
-func (suite *RouterSessionValidateTestSuite) TestValidateRouterSessionAuth() {
- r := happyRouterSession()
-
- // remove auth struct
- r.Auth = nil
- err := gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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/gtsmodel/status.go b/internal/gtsmodel/status.go
index d81a45ec3..f298e71cd 100644
--- a/internal/gtsmodel/status.go
+++ b/internal/gtsmodel/status.go
@@ -25,18 +25,18 @@ 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:",nullzero,notnull,default:current_timestamp"` // when was item created
- UpdatedAt time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"` // when was item last updated
+ CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created
+ UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated
URI string `validate:"required,url" bun:",unique,nullzero,notnull"` // activitypub URI of this status
URL string `validate:"url" bun:",nullzero"` // web url for viewing this status
Content string `validate:"-" bun:",nullzero"` // content of this status; likely html-formatted but not guaranteed
- AttachmentIDs []string `validate:"dive,ulid" bun:"attachments,array,nullzero"` // Database IDs of any media attachments associated with this status
+ 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,nullzero"` // Database IDs of any tags used in this status
+ 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,nullzero"` // Database IDs of any mentions in this status
+ 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,nullzero"` // Database IDs of any emojis used in this status
+ EmojiIDs []string `validate:"dive,ulid" bun:"emojis,array"` // Database IDs of any emojis used in this status
Emojis []*Emoji `validate:"-" bun:"attached_emojis,m2m:status_to_emojis"` // Emojis corresponding to emojiIDs. https://bun.uptrace.dev/guide/relations.html#many-to-many-relation
Local bool `validate:"-" bun:",notnull,default:false"` // is this status from a local account?
AccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // which account posted this status?
diff --git a/internal/gtsmodel/status_test.go b/internal/gtsmodel/status_test.go
deleted file mode 100644
index 7f3b2f38f..000000000
--- a/internal/gtsmodel/status_test.go
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package gtsmodel_test
-
-import (
- "testing"
- "time"
-
- "github.com/stretchr/testify/suite"
- "github.com/superseriousbusiness/gotosocial/internal/ap"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
-)
-
-func happyStatus() *gtsmodel.Status {
- return &gtsmodel.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: true,
- 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: false,
- Language: "en",
- CreatedWithApplicationID: "01FEBBZHF4GFVRXSJVXD0JTZZ2",
- CreatedWithApplication: nil,
- VisibilityAdvanced: gtsmodel.VisibilityAdvanced{
- Federated: true,
- Boostable: true,
- Replyable: true,
- Likeable: true,
- },
- ActivityStreamsType: ap.ObjectNote,
- Text: "Test status! #hello",
- Pinned: false,
- }
-}
-
-type StatusValidateTestSuite struct {
- suite.Suite
-}
-
-func (suite *StatusValidateTestSuite) TestValidateStatusHappyPath() {
- // no problem here
- s := happyStatus()
- err := gtsmodel.ValidateStruct(*s)
- suite.NoError(err)
-}
-
-func (suite *StatusValidateTestSuite) TestValidateStatusBadID() {
- s := happyStatus()
-
- s.ID = ""
- err := gtsmodel.ValidateStruct(*s)
- suite.EqualError(err, "Key: 'Status.ID' Error:Field validation for 'ID' failed on the 'required' tag")
-
- s.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB"
- err = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*s)
- suite.EqualError(err, "Key: 'Status.AttachmentIDs[0]' Error:Field validation for 'AttachmentIDs[0]' failed on the 'ulid' tag")
-
- s.AttachmentIDs[0] = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB"
- err = gtsmodel.ValidateStruct(*s)
- suite.EqualError(err, "Key: 'Status.AttachmentIDs[0]' Error:Field validation for 'AttachmentIDs[0]' failed on the 'ulid' tag")
-
- s.AttachmentIDs[1] = ""
- err = gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*s)
- suite.NoError(err)
-
- s.AttachmentIDs = nil
- err = gtsmodel.ValidateStruct(*s)
- suite.NoError(err)
-}
-
-func (suite *StatusValidateTestSuite) TestStatusApplicationID() {
- s := happyStatus()
-
- s.CreatedWithApplicationID = ""
- err := gtsmodel.ValidateStruct(*s)
- suite.EqualError(err, "Key: 'Status.CreatedWithApplicationID' Error:Field validation for 'CreatedWithApplicationID' failed on the 'required_if' tag")
-
- s.Local = false
- err = gtsmodel.ValidateStruct(*s)
- suite.NoError(err)
-}
-
-func (suite *StatusValidateTestSuite) TestValidateStatusReplyFields() {
- s := happyStatus()
-
- s.InReplyToAccountID = "01FEBCTP6DN7961PN81C3DVM4N "
- err := gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*s)
- suite.EqualError(err, "Key: 'Status.InReplyToID' Error:Field validation for 'InReplyToID' failed on the 'ulid' tag")
-
- s.InReplyToID = "01FEBD07E72DEY6YB9K10ZA6ST"
- err = gtsmodel.ValidateStruct(*s)
- suite.NoError(err)
-}
-
-func TestStatusValidateTestSuite(t *testing.T) {
- suite.Run(t, new(StatusValidateTestSuite))
-}
diff --git a/internal/gtsmodel/statusbookmark.go b/internal/gtsmodel/statusbookmark.go
index 76a2a866d..3dcf4cb92 100644
--- a/internal/gtsmodel/statusbookmark.go
+++ b/internal/gtsmodel/statusbookmark.go
@@ -22,12 +22,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:",nullzero,notnull,default:current_timestamp"` // when was item created
- 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 `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database
+ CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created
+ UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated
+ AccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // id of the account that created ('did') the bookmark
+ Account *Account `validate:"-" bun:"rel:belongs-to"` // account that created the bookmark
+ TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // id the account owning the bookmarked status
+ TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // account owning the bookmarked status
+ StatusID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // database id of the status that has been bookmarked
+ Status *Status `validate:"-" bun:"rel:belongs-to"` // the bookmarked status
}
diff --git a/internal/gtsmodel/statusbookmark_test.go b/internal/gtsmodel/statusbookmark_test.go
deleted file mode 100644
index e7a67fc35..000000000
--- a/internal/gtsmodel/statusbookmark_test.go
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package gtsmodel_test
-
-import (
- "testing"
- "time"
-
- "github.com/stretchr/testify/suite"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
-)
-
-func happyStatusBookmark() *gtsmodel.StatusBookmark {
- return &gtsmodel.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
- m := happyStatusBookmark()
- err := gtsmodel.ValidateStruct(*m)
- suite.NoError(err)
-}
-
-func (suite *StatusBookmarkValidateTestSuite) TestValidateStatusBookmarkBadID() {
- m := happyStatusBookmark()
-
- m.ID = ""
- err := gtsmodel.ValidateStruct(*m)
- suite.EqualError(err, "Key: 'StatusBookmark.ID' Error:Field validation for 'ID' failed on the 'required' tag")
-
- m.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB"
- err = gtsmodel.ValidateStruct(*m)
- suite.EqualError(err, "Key: 'StatusBookmark.ID' Error:Field validation for 'ID' failed on the 'ulid' tag")
-}
-
-func (suite *StatusBookmarkValidateTestSuite) TestValidateStatusBookmarkDodgyStatusID() {
- m := happyStatusBookmark()
-
- m.StatusID = "9HZJ76B6VXSKF"
- err := gtsmodel.ValidateStruct(*m)
- suite.EqualError(err, "Key: 'StatusBookmark.StatusID' Error:Field validation for 'StatusID' failed on the 'ulid' tag")
-
- m.StatusID = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!!!!!!!!!!!!"
- err = gtsmodel.ValidateStruct(*m)
- suite.EqualError(err, "Key: 'StatusBookmark.StatusID' Error:Field validation for 'StatusID' failed on the 'ulid' tag")
-}
-
-func (suite *StatusBookmarkValidateTestSuite) TestValidateStatusBookmarkNoCreatedAt() {
- m := happyStatusBookmark()
-
- m.CreatedAt = time.Time{}
- err := gtsmodel.ValidateStruct(*m)
- suite.NoError(err)
-}
-
-func TestStatusBookmarkValidateTestSuite(t *testing.T) {
- suite.Run(t, new(StatusBookmarkValidateTestSuite))
-}
diff --git a/internal/gtsmodel/statusfave.go b/internal/gtsmodel/statusfave.go
index 6647e941a..93bcda0e6 100644
--- a/internal/gtsmodel/statusfave.go
+++ b/internal/gtsmodel/statusfave.go
@@ -22,13 +22,14 @@ import "time"
// StatusFave refers to a 'fave' or 'like' in the database, from one account, targeting the status of another account
type StatusFave struct {
- ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database
- CreatedAt time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"` // when was item created
- AccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // id of the account that created ('did') the fave
- Account *Account `validate:"-" bun:"rel:belongs-to"` // account that created the fave
- TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // id the account owning the faved status
- TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // account owning the faved status
- StatusID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // database id of the status that has been 'faved'
- Status *Status `validate:"-" bun:"rel:belongs-to"` // the faved status
- URI string `validate:"required,url" bun:",nullzero,notnull"` // ActivityPub URI of this fave
+ ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database
+ CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created
+ UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated
+ AccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // id of the account that created ('did') the fave
+ Account *Account `validate:"-" bun:"rel:belongs-to"` // account that created the fave
+ TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // id the account owning the faved status
+ TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // account owning the faved status
+ StatusID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // database id of the status that has been 'faved'
+ Status *Status `validate:"-" bun:"rel:belongs-to"` // the faved status
+ URI string `validate:"required,url" bun:",nullzero,notnull"` // ActivityPub URI of this fave
}
diff --git a/internal/gtsmodel/statusfave_test.go b/internal/gtsmodel/statusfave_test.go
deleted file mode 100644
index 37f555a7c..000000000
--- a/internal/gtsmodel/statusfave_test.go
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package gtsmodel_test
-
-import (
- "testing"
- "time"
-
- "github.com/stretchr/testify/suite"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
-)
-
-func happyStatusFave() *gtsmodel.StatusFave {
- return &gtsmodel.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 := gtsmodel.ValidateStruct(*f)
- suite.NoError(err)
-}
-
-func (suite *StatusFaveValidateTestSuite) TestValidateStatusFaveBadID() {
- f := happyStatusFave()
-
- f.ID = ""
- err := gtsmodel.ValidateStruct(*f)
- suite.EqualError(err, "Key: 'StatusFave.ID' Error:Field validation for 'ID' failed on the 'required' tag")
-
- f.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB"
- err = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*f)
- suite.EqualError(err, "Key: 'StatusFave.StatusID' Error:Field validation for 'StatusID' failed on the 'ulid' tag")
-
- f.StatusID = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!!!!!!!!!!!!"
- err = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*f)
- suite.NoError(err)
-}
-
-func (suite *StatusFaveValidateTestSuite) TestValidateStatusFaveNoURI() {
- f := happyStatusFave()
-
- f.URI = ""
- err := gtsmodel.ValidateStruct(*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 = gtsmodel.ValidateStruct(*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/gtsmodel/statusmute.go b/internal/gtsmodel/statusmute.go
index 70789e557..2c03b8085 100644
--- a/internal/gtsmodel/statusmute.go
+++ b/internal/gtsmodel/statusmute.go
@@ -22,12 +22,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:",nullzero,notnull,default:current_timestamp"` // when was item created
- 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 `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database
+ CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created
+ UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated
+ AccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // id of the account that created ('did') the mute
+ Account *Account `validate:"-" bun:"rel:belongs-to"` // pointer to the account specified by accountID
+ TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // id the account owning the muted status (can be the same as accountID)
+ TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // pointer to the account specified by targetAccountID
+ StatusID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // database id of the status that has been muted
+ Status *Status `validate:"-" bun:"rel:belongs-to"` // pointer to the muted status specified by statusID
}
diff --git a/internal/gtsmodel/statusmute_test.go b/internal/gtsmodel/statusmute_test.go
deleted file mode 100644
index b3926bb69..000000000
--- a/internal/gtsmodel/statusmute_test.go
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package gtsmodel_test
-
-import (
- "testing"
- "time"
-
- "github.com/stretchr/testify/suite"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
-)
-
-func happyStatusMute() *gtsmodel.StatusMute {
- return &gtsmodel.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 := gtsmodel.ValidateStruct(*m)
- suite.NoError(err)
-}
-
-func (suite *StatusMuteValidateTestSuite) TestValidateStatusMuteBadID() {
- m := happyStatusMute()
-
- m.ID = ""
- err := gtsmodel.ValidateStruct(*m)
- suite.EqualError(err, "Key: 'StatusMute.ID' Error:Field validation for 'ID' failed on the 'required' tag")
-
- m.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB"
- err = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*m)
- suite.EqualError(err, "Key: 'StatusMute.StatusID' Error:Field validation for 'StatusID' failed on the 'ulid' tag")
-
- m.StatusID = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!!!!!!!!!!!!"
- err = gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*m)
- suite.NoError(err)
-}
-
-func TestStatusMuteValidateTestSuite(t *testing.T) {
- suite.Run(t, new(StatusMuteValidateTestSuite))
-}
diff --git a/internal/gtsmodel/stream.go b/internal/gtsmodel/stream.go
deleted file mode 100644
index 4a1571de5..000000000
--- a/internal/gtsmodel/stream.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package gtsmodel
-
-import "sync"
-
-// StreamsForAccount is a wrapper for the multiple streams that one account can have running at the same time.
-// TODO: put a limit on this
-type StreamsForAccount struct {
- // The currently held streams for this account
- Streams []*Stream
- // Mutex to lock/unlock when modifying the slice of streams.
- sync.Mutex
-}
-
-// Stream represents one open stream for a client.
-type Stream struct {
- // ID of this stream, generated during creation.
- ID string
- // Type of this stream: user/public/etc
- Type string
- // Channel of messages for the client to read from
- Messages chan *Message
- // Channel to close when the client drops away
- Hangup chan interface{}
- // Only put messages in the stream when Connected
- Connected bool
- // Mutex to lock/unlock when inserting messages, hanging up, changing the connected state etc.
- sync.Mutex
-}
-
-// Message represents one streamed message.
-type Message struct {
- // All the stream types this message should be delivered to.
- Stream []string `json:"stream"`
- // The event type of the message (update/delete/notification etc)
- Event string `json:"event"`
- // The actual payload of the message. In case of an update or notification, this will be a JSON string.
- Payload string `json:"payload"`
-}
diff --git a/internal/gtsmodel/tag.go b/internal/gtsmodel/tag.go
index 14ff26f87..295447c4f 100644
--- a/internal/gtsmodel/tag.go
+++ b/internal/gtsmodel/tag.go
@@ -22,13 +22,13 @@ 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:",nullzero,notnull,default:current_timestamp"` // when was item created
- UpdatedAt time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"` // when was item last updated
- URL string `validate:"required,url" bun:",nullzero,notnull"` // Href/web address of this tag, eg https://example.org/tags/somehashtag
- Name string `validate:"required" bun:",unique,nullzero,notnull"` // name of this tag -- the tag without the hash part
- FirstSeenFromAccountID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // Which account ID is the first one we saw using this tag?
- Useable bool `validate:"-" bun:",notnull,default:true"` // can our instance users use this tag?
- Listable bool `validate:"-" bun:",notnull,default:true"` // can our instance users look up this tag?
- LastStatusAt time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"` // when was this tag last used?
+ ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database
+ CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created
+ UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated
+ URL string `validate:"required,url" bun:",nullzero,notnull"` // Href/web address of this tag, eg https://example.org/tags/somehashtag
+ Name string `validate:"required" bun:",unique,nullzero,notnull"` // name of this tag -- the tag without the hash part
+ FirstSeenFromAccountID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // Which account ID is the first one we saw using this tag?
+ Useable bool `validate:"-" bun:",notnull,default:true"` // can our instance users use this tag?
+ Listable bool `validate:"-" bun:",notnull,default:true"` // can our instance users look up this tag?
+ LastStatusAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was this tag last used?
}
diff --git a/internal/gtsmodel/tag_test.go b/internal/gtsmodel/tag_test.go
deleted file mode 100644
index baafe55bd..000000000
--- a/internal/gtsmodel/tag_test.go
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package gtsmodel_test
-
-import (
- "testing"
- "time"
-
- "github.com/stretchr/testify/suite"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
-)
-
-func happyTag() *gtsmodel.Tag {
- return &gtsmodel.Tag{
- ID: "01FE91RJR88PSEEE30EV35QR8N",
- CreatedAt: time.Now(),
- UpdatedAt: time.Now(),
- URL: "https://example.org/tags/some_tag",
- Name: "some_tag",
- FirstSeenFromAccountID: "01FE91SR5P2GW06K3AJ98P72MT",
- Useable: true,
- Listable: true,
- LastStatusAt: time.Now(),
- }
-}
-
-type TagValidateTestSuite struct {
- suite.Suite
-}
-
-func (suite *TagValidateTestSuite) TestValidateTagHappyPath() {
- // no problem here
- t := happyTag()
- err := gtsmodel.ValidateStruct(*t)
- suite.NoError(err)
-}
-
-func (suite *TagValidateTestSuite) TestValidateTagNoName() {
- t := happyTag()
- t.Name = ""
-
- err := gtsmodel.ValidateStruct(*t)
- suite.EqualError(err, "Key: 'Tag.Name' Error:Field validation for 'Name' failed on the 'required' tag")
-}
-
-func (suite *TagValidateTestSuite) TestValidateTagBadURL() {
- t := happyTag()
-
- t.URL = ""
- err := gtsmodel.ValidateStruct(*t)
- suite.EqualError(err, "Key: 'Tag.URL' Error:Field validation for 'URL' failed on the 'required' tag")
-
- t.URL = "no-schema.com"
- err = gtsmodel.ValidateStruct(*t)
- suite.EqualError(err, "Key: 'Tag.URL' Error:Field validation for 'URL' failed on the 'url' tag")
-
- t.URL = "justastring"
- err = gtsmodel.ValidateStruct(*t)
- suite.EqualError(err, "Key: 'Tag.URL' Error:Field validation for 'URL' failed on the 'url' tag")
-
- t.URL = "https://aaa\n\n\naaaaaaaa"
- err = gtsmodel.ValidateStruct(*t)
- suite.EqualError(err, "Key: 'Tag.URL' Error:Field validation for 'URL' failed on the 'url' tag")
-}
-
-func (suite *TagValidateTestSuite) TestValidateTagNoFirstSeenFromAccountID() {
- t := happyTag()
- t.FirstSeenFromAccountID = ""
-
- err := gtsmodel.ValidateStruct(*t)
- suite.NoError(err)
-}
-
-func TestTagValidateTestSuite(t *testing.T) {
- suite.Run(t, new(TagValidateTestSuite))
-}
diff --git a/internal/gtsmodel/token.go b/internal/gtsmodel/token.go
index 1ede26aee..65728ac60 100644
--- a/internal/gtsmodel/token.go
+++ b/internal/gtsmodel/token.go
@@ -21,30 +21,23 @@ package gtsmodel
import "time"
// Token is a translation of the gotosocial token with the ExpiresIn fields replaced with ExpiresAt.
-//
-// Explanation for this: gotosocial assumes an in-memory or file database of some kind, where a time-to-live parameter (TTL) can be defined,
-// and tokens with expired TTLs are automatically removed. Since some databases don't have that feature, it's easier to set an expiry time and
-// then periodically sweep out tokens when that time has passed.
-//
-// Note that this struct does *not* satisfy the token interface shown here: https://github.com/superseriousbusiness/oauth2/blob/master/model.go#L22
-// and implemented here: https://github.com/superseriousbusiness/oauth2/blob/master/models/token.go.
-// As such, manual translation is always required between Token and the gotosocial *model.Token. The helper functions oauthTokenToPGToken
-// and pgTokenToOauthToken can be used for that.
type Token struct {
- ID string `validate:"ulid" bun:"type:CHAR(26),pk,nullzero,notnull"`
- ClientID string
- UserID string
- RedirectURI string
- Scope string
- Code string `bun:"default:'',pk"`
- CodeChallenge string
- CodeChallengeMethod string
- CodeCreateAt time.Time `bun:",nullzero"`
- CodeExpiresAt time.Time `bun:",nullzero"`
- Access string `bun:"default:'',pk"`
- AccessCreateAt time.Time `bun:",nullzero"`
- AccessExpiresAt time.Time `bun:",nullzero"`
- Refresh string `bun:"default:'',pk"`
- RefreshCreateAt time.Time `bun:",nullzero"`
- RefreshExpiresAt time.Time `bun:",nullzero"`
+ ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database
+ CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created
+ UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated
+ ClientID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // ID of the client who owns this token
+ UserID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // ID of the user who owns this token
+ RedirectURI string `validate:"required,url" bun:",nullzero,notnull"` // Oauth redirect URI for this token
+ Scope string `validate:"omitempty,url" bun:",nullzero,notnull,default:'read'"` // Oauth scope
+ Code string `validate:"-" bun:",pk,nullzero,notnull,default:''"` // Code, if present
+ CodeChallenge string `validate:"-" bun:",nullzero"` // Code challenge, if code present
+ CodeChallengeMethod string `validate:"-" bun:",nullzero"` // Code challenge method, if code present
+ CodeCreateAt time.Time `validate:"required_with=Code" bun:"type:timestamp,nullzero"` // Code created time, if code present
+ CodeExpiresAt time.Time `validate:"-" bun:"type:timestamp,nullzero"` // Code expires at -- null means the code never expires
+ Access string `validate:"-" bun:",pk,nullzero,notnull,default:''"` // User level access token, if present
+ AccessCreateAt time.Time `validate:"required_with=Access" bun:"type:timestamp,nullzero"` // User level access token created time, if access present
+ AccessExpiresAt time.Time `validate:"-" bun:"type:timestamp,nullzero"` // User level access token expires at -- null means the token never expires
+ Refresh string `validate:"-" bun:",pk,nullzero,notnull,default:''"` // Refresh token, if present
+ RefreshCreateAt time.Time `validate:"required_with=Refresh" bun:"type:timestamp,nullzero"` // Refresh created at, if refresh present
+ RefreshExpiresAt time.Time `validate:"-" bun:"type:timestamp,nullzero"` // Refresh expires at -- null means the refresh token never expires
}
diff --git a/internal/gtsmodel/user.go b/internal/gtsmodel/user.go
index e0568d6a0..70f328619 100644
--- a/internal/gtsmodel/user.go
+++ b/internal/gtsmodel/user.go
@@ -26,45 +26,34 @@ import (
// User represents an actual human user of gotosocial. Note, this is a LOCAL gotosocial user, not a remote account.
// To cross reference this local user with their account (which can be local or remote), use the AccountID field.
type User struct {
- 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:",nullzero,notnull,default:current_timestamp"` // when was item created
- UpdatedAt time.Time `validate:"-" bun:",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:",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:",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:"-" bun:",nullzero,notnull,default:0"` // How many times has this user signed in?
- InviteID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // id of the user who invited this user (who let this joker in?)
- ChosenLanguages []string `validate:"-" bun:",nullzero"` // What languages does this user want to see?
- FilteredLanguages []string `validate:"-" bun:",nullzero"` // What languages does this user not want to see?
- Locale string `validate:"-" bun:",nullzero"` // In what timezone/locale is this user located?
- CreatedByApplicationID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // 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:",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:",nullzero"` // When did we send email confirmation to this user?
- ConfirmedAt time.Time `validate:"required_with=Email" bun:",nullzero"` // When did the user confirm their email address
- UnconfirmedEmail string `validate:"required_without=Email" bun:",nullzero"` // Email address that hasn't yet been confirmed
- Moderator bool `validate:"-" bun:",notnull,default:false"` // Is this user a moderator?
- Admin bool `validate:"-" bun:",notnull,default:false"` // Is this user an admin?
- Disabled bool `validate:"-" bun:",notnull,default:false"` // Is this user disabled from posting?
- Approved bool `validate:"-" bun:",notnull,default:false"` // Has this user been approved by a moderator?
- ResetPasswordToken string `validate:"required_with=ResetPasswordSentAt" bun:",nullzero"` // The generated token that the user can use to reset their password
- ResetPasswordSentAt time.Time `validate:"required_with=ResetPasswordToken" bun:",nullzero"` // When did we email the user their reset-password email?
-
- EncryptedOTPSecret string `validate:"-" bun:",nullzero"`
- EncryptedOTPSecretIv string `validate:"-" bun:",nullzero"`
- EncryptedOTPSecretSalt string `validate:"-" bun:",nullzero"`
- OTPRequiredForLogin bool `validate:"-" bun:",notnull,default:false"`
- OTPBackupCodes []string `validate:"-" bun:",nullzero"`
- ConsumedTimestamp int `validate:"-" bun:",nullzero"`
- RememberToken string `validate:"-" bun:",nullzero"`
- SignInToken string `validate:"-" bun:",nullzero"`
- SignInTokenSentAt time.Time `validate:"-" bun:",nullzero"`
- WebauthnID string `validate:"-" bun:",nullzero"`
+ ID string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database
+ CreatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item created
+ UpdatedAt time.Time `validate:"-" bun:"type:timestamp,nullzero,notnull,default:current_timestamp"` // when was item last updated
+ Email string `validate:"required_with=ConfirmedAt" bun:",nullzero,unique"` // confirmed email address for this user, this should be unique -- only one email address registered per instance, multiple users per email are not supported
+ AccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull,unique"` // The id of the local gtsmodel.Account entry for this user.
+ Account *Account `validate:"-" bun:"rel:belongs-to"` // Pointer to the account of this user that corresponds to AccountID.
+ EncryptedPassword string `validate:"required" bun:",nullzero,notnull"` // The encrypted password of this user, generated using https://pkg.go.dev/golang.org/x/crypto/bcrypt#GenerateFromPassword. A salt is included so we're safe against 🌈 tables.
+ SignUpIP net.IP `validate:"-" bun:",nullzero"` // From what IP was this user created?
+ CurrentSignInAt time.Time `validate:"-" bun:"type:timestamp,nullzero"` // When did the user sign in with their current session.
+ CurrentSignInIP net.IP `validate:"-" bun:",nullzero"` // What's the most recent IP of this user
+ LastSignInAt time.Time `validate:"-" bun:"type:timestamp,nullzero"` // When did this user last sign in?
+ LastSignInIP net.IP `validate:"-" bun:",nullzero"` // What's the previous IP of this user?
+ SignInCount int `validate:"-" bun:",nullzero,notnull,default:0"` // How many times has this user signed in?
+ InviteID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // id of the user who invited this user (who let this joker in?)
+ ChosenLanguages []string `validate:"-" bun:",nullzero"` // What languages does this user want to see?
+ FilteredLanguages []string `validate:"-" bun:",nullzero"` // What languages does this user not want to see?
+ Locale string `validate:"-" bun:",nullzero"` // In what timezone/locale is this user located?
+ CreatedByApplicationID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // Which application id created this user? See gtsmodel.Application
+ CreatedByApplication *Application `validate:"-" bun:"rel:belongs-to"` // Pointer to the application corresponding to createdbyapplicationID.
+ LastEmailedAt time.Time `validate:"-" bun:"type:timestamp,nullzero"` // When was this user last contacted by email.
+ ConfirmationToken string `validate:"required_with=ConfirmationSentAt" bun:",nullzero"` // What confirmation token did we send this user/what are we expecting back?
+ ConfirmationSentAt time.Time `validate:"required_with=ConfirmationToken" bun:"type:timestamp,nullzero"` // When did we send email confirmation to this user?
+ ConfirmedAt time.Time `validate:"required_with=Email" bun:"type:timestamp,nullzero"` // When did the user confirm their email address
+ UnconfirmedEmail string `validate:"required_without=Email" bun:",nullzero"` // Email address that hasn't yet been confirmed
+ Moderator bool `validate:"-" bun:",notnull,default:false"` // Is this user a moderator?
+ Admin bool `validate:"-" bun:",notnull,default:false"` // Is this user an admin?
+ Disabled bool `validate:"-" bun:",notnull,default:false"` // Is this user disabled from posting?
+ Approved bool `validate:"-" bun:",notnull,default:false"` // Has this user been approved by a moderator?
+ ResetPasswordToken string `validate:"required_with=ResetPasswordSentAt" bun:",nullzero"` // The generated token that the user can use to reset their password
+ ResetPasswordSentAt time.Time `validate:"required_with=ResetPasswordToken" bun:"type:timestamp,nullzero"` // When did we email the user their reset-password email?
}
diff --git a/internal/gtsmodel/user_test.go b/internal/gtsmodel/user_test.go
deleted file mode 100644
index a13b31075..000000000
--- a/internal/gtsmodel/user_test.go
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package gtsmodel_test
-
-import (
- "net"
- "testing"
- "time"
-
- "github.com/stretchr/testify/suite"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
-)
-
-func happyUser() *gtsmodel.User {
- return &gtsmodel.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: false,
- Admin: false,
- Disabled: false,
- Approved: true,
- }
-}
-
-type UserValidateTestSuite struct {
- suite.Suite
-}
-
-func (suite *UserValidateTestSuite) TestValidateUserHappyPath() {
- // no problem here
- u := happyUser()
- err := gtsmodel.ValidateStruct(*u)
- suite.NoError(err)
-}
-
-func (suite *UserValidateTestSuite) TestValidateUserNoID() {
- // user has no id set
- u := happyUser()
- u.ID = ""
-
- err := gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*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 := gtsmodel.ValidateStruct(*u)
- suite.NoError(err)
-}
-
-func (suite *UserValidateTestSuite) TestValidateUserNoConfirmedAt() {
- // user has Email but no ConfirmedAt
- u := happyUser()
- u.ConfirmedAt = time.Time{}
-
- err := gtsmodel.ValidateStruct(*u)
- suite.EqualError(err, "Key: 'User.ConfirmedAt' Error:Field validation for 'ConfirmedAt' failed on the 'required_with' tag")
-}
-
-func TestUserValidateTestSuite(t *testing.T) {
- suite.Run(t, new(UserValidateTestSuite))
-}
diff --git a/internal/gtsmodel/validate.go b/internal/gtsmodel/validate.go
deleted file mode 100644
index 0e1957b28..000000000
--- a/internal/gtsmodel/validate.go
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package gtsmodel
-
-import (
- "reflect"
-
- "github.com/go-playground/validator/v10"
- "github.com/superseriousbusiness/gotosocial/internal/util"
-)
-
-var v *validator.Validate
-
-// Validation Panic messages
-const (
- PointerValidationPanic = "validate function was passed pointer"
- InvalidValidationPanic = "validate function was passed invalid item"
-)
-
-func ulidValidator(fl validator.FieldLevel) bool {
- field := fl.Field()
-
- switch field.Kind() {
- case reflect.String:
- return util.ValidateULID(field.String())
- default:
- return false
- }
-}
-
-func init() {
- v = validator.New()
- v.RegisterValidation("ulid", ulidValidator)
-}
-
-// ValidateStruct validates the passed struct, returning validator.ValidationErrors if invalid, or nil if OK.
-func ValidateStruct(s interface{}) error {
- switch reflect.ValueOf(s).Kind() {
- case reflect.Invalid:
- panic(InvalidValidationPanic)
- case reflect.Ptr:
- panic(PointerValidationPanic)
- }
-
- err := v.Struct(s)
- return processValidationError(err)
-}
-
-func processValidationError(err error) error {
- if err == nil {
- return nil
- }
-
- if ive, ok := err.(*validator.InvalidValidationError); ok {
- panic(ive)
- }
-
- return err.(validator.ValidationErrors)
-}
diff --git a/internal/gtsmodel/validate_test.go b/internal/gtsmodel/validate_test.go
deleted file mode 100644
index 7200522bc..000000000
--- a/internal/gtsmodel/validate_test.go
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package gtsmodel_test
-
-import (
- "testing"
-
- "github.com/stretchr/testify/suite"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
-)
-
-type ValidateTestSuite struct {
- suite.Suite
-}
-
-func (suite *ValidateTestSuite) TestValidatePointer() {
- var nilUser *gtsmodel.User
- suite.PanicsWithValue(gtsmodel.PointerValidationPanic, func() {
- gtsmodel.ValidateStruct(nilUser)
- })
-}
-
-func (suite *ValidateTestSuite) TestValidateNil() {
- suite.PanicsWithValue(gtsmodel.InvalidValidationPanic, func() {
- gtsmodel.ValidateStruct(nil)
- })
-}
-
-func (suite *ValidateTestSuite) TestValidateWeirdULID() {
- type a struct {
- ID bool `validate:"required,ulid"`
- }
-
- err := gtsmodel.ValidateStruct(a{ID: true})
- suite.Error(err)
-}
-
-func (suite *ValidateTestSuite) TestValidateNotStruct() {
- type aaaaaaa string
- aaaaaa := aaaaaaa("aaaa")
- suite.Panics(func() {
- gtsmodel.ValidateStruct(aaaaaa)
- })
-}
-
-func TestValidateTestSuite(t *testing.T) {
- suite.Run(t, new(ValidateTestSuite))
-}