mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-11-30 23:33:31 -06:00
moving stuff around
This commit is contained in:
parent
684bd56528
commit
4696e1a7b3
93 changed files with 878 additions and 1750 deletions
|
|
@ -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.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 >smodel.Block{
|
||||
ID: "01FE91RJR88PSEEE30EV35QR8N",
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
URI: "https://example.org/accounts/someone/blocks/01FE91RJR88PSEEE30EV35QR8N",
|
||||
AccountID: "01FEED79PRMVWPRMFHFQM8MJQN",
|
||||
Account: nil,
|
||||
TargetAccountID: "01FEEDMF6C0QD589MRK7919Z0R",
|
||||
TargetAccount: nil,
|
||||
}
|
||||
}
|
||||
|
||||
type BlockValidateTestSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func (suite *BlockValidateTestSuite) TestValidateBlockHappyPath() {
|
||||
// no problem here
|
||||
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))
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 >smodel.DomainBlock{
|
||||
ID: "01FE91RJR88PSEEE30EV35QR8N",
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
Domain: "baddudes.suck",
|
||||
CreatedByAccountID: "01FEED79PRMVWPRMFHFQM8MJQN",
|
||||
PrivateComment: "we don't like em",
|
||||
PublicComment: "poo poo dudes",
|
||||
Obfuscate: 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))
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 >smodel.EmailDomainBlock{
|
||||
ID: "01FE91RJR88PSEEE30EV35QR8N",
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
Domain: "baddudes.suck",
|
||||
CreatedByAccountID: "01FEED79PRMVWPRMFHFQM8MJQN",
|
||||
}
|
||||
}
|
||||
|
||||
type EmailDomainBlockValidateTestSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func (suite *EmailDomainBlockValidateTestSuite) TestValidateEmailDomainBlockHappyPath() {
|
||||
// no problem here
|
||||
e := happyEmailDomainBlock()
|
||||
err := 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))
|
||||
}
|
||||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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 >smodel.Emoji{
|
||||
ID: "01F8MH6NEM8D7527KZAECTCR76",
|
||||
CreatedAt: time.Now().Add(-71 * time.Hour),
|
||||
UpdatedAt: time.Now().Add(-71 * time.Hour),
|
||||
Shortcode: "blob_test",
|
||||
Domain: "example.org",
|
||||
ImageRemoteURL: "https://example.org/emojis/blob_test.gif",
|
||||
ImageStaticRemoteURL: "https://example.org/emojis/blob_test.png",
|
||||
ImageURL: "",
|
||||
ImageStaticURL: "",
|
||||
ImagePath: imagePath,
|
||||
ImageStaticPath: imageStaticPath,
|
||||
ImageContentType: "image/gif",
|
||||
ImageStaticContentType: "image/png",
|
||||
ImageFileSize: 1024,
|
||||
ImageStaticFileSize: 256,
|
||||
ImageUpdatedAt: time.Now(),
|
||||
Disabled: 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))
|
||||
}
|
||||
|
|
@ -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?
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 >smodel.Follow{
|
||||
ID: "01FE91RJR88PSEEE30EV35QR8N",
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
AccountID: "01FE96MAE58MXCE5C4SSMEMCEK",
|
||||
Account: nil,
|
||||
TargetAccountID: "01FE96MXRHWZHKC0WH5FT82H1A",
|
||||
TargetAccount: nil,
|
||||
URI: "https://example.org/users/user1/activity/follow/01FE91RJR88PSEEE30EV35QR8N",
|
||||
}
|
||||
}
|
||||
|
||||
type FollowValidateTestSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func (suite *FollowValidateTestSuite) TestValidateFollowHappyPath() {
|
||||
// no problem here
|
||||
f := happyFollow()
|
||||
err := 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))
|
||||
}
|
||||
|
|
@ -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?
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 >smodel.FollowRequest{
|
||||
ID: "01FE91RJR88PSEEE30EV35QR8N",
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
AccountID: "01FE96MAE58MXCE5C4SSMEMCEK",
|
||||
Account: nil,
|
||||
TargetAccountID: "01FE96MXRHWZHKC0WH5FT82H1A",
|
||||
TargetAccount: nil,
|
||||
URI: "https://example.org/users/user1/activity/follow/01FE91RJR88PSEEE30EV35QR8N",
|
||||
}
|
||||
}
|
||||
|
||||
type FollowRequestValidateTestSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func (suite *FollowRequestValidateTestSuite) TestValidateFollowRequestHappyPath() {
|
||||
// no problem here
|
||||
f := happyFollowRequest()
|
||||
err := 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))
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 >smodel.Instance{
|
||||
ID: "01FE91RJR88PSEEE30EV35QR8N",
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
Domain: "example.org",
|
||||
Title: "Example Instance",
|
||||
URI: "https://example.org",
|
||||
SuspendedAt: time.Time{},
|
||||
DomainBlockID: "",
|
||||
DomainBlock: nil,
|
||||
ShortDescription: "This is a description for the example/testing instance.",
|
||||
Description: "This is a way longer description for the example/testing instance!",
|
||||
Terms: "Don't be a knobhead.",
|
||||
ContactEmail: "admin@example.org",
|
||||
ContactAccountUsername: "admin",
|
||||
ContactAccountID: "01FEE20H5QWHJDEXAEE9G96PR0",
|
||||
ContactAccount: nil,
|
||||
Reputation: 420,
|
||||
Version: "gotosocial 0.1.0",
|
||||
}
|
||||
}
|
||||
|
||||
type InstanceValidateTestSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func (suite *InstanceValidateTestSuite) TestValidateInstanceHappyPath() {
|
||||
// no problem here
|
||||
m := happyInstance()
|
||||
err := 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))
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 >smodel.MediaAttachment{
|
||||
ID: "01F8MH6NEM8D7527KZAECTCR76",
|
||||
CreatedAt: time.Now().Add(-71 * time.Hour),
|
||||
UpdatedAt: time.Now().Add(-71 * time.Hour),
|
||||
StatusID: "01F8MH75CBF9JFX4ZAD54N0W0R",
|
||||
URL: "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.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))
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 >smodel.Mention{
|
||||
ID: "01FE91RJR88PSEEE30EV35QR8N",
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
OriginAccountID: "01FE96MAE58MXCE5C4SSMEMCEK",
|
||||
OriginAccountURI: "https://some-instance/accounts/bleepbloop",
|
||||
OriginAccount: nil,
|
||||
TargetAccountID: "01FE96MXRHWZHKC0WH5FT82H1A",
|
||||
TargetAccount: nil,
|
||||
StatusID: "01FE96NBPNJNY26730FT6GZTFE",
|
||||
Status: nil,
|
||||
}
|
||||
}
|
||||
|
||||
type MentionValidateTestSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func (suite *MentionValidateTestSuite) TestValidateMentionHappyPath() {
|
||||
// no problem here
|
||||
m := happyMention()
|
||||
err := 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))
|
||||
}
|
||||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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 >smodel.Notification{
|
||||
ID: "01FE91RJR88PSEEE30EV35QR8N",
|
||||
CreatedAt: time.Now(),
|
||||
NotificationType: gtsmodel.NotificationFave,
|
||||
OriginAccountID: "01FE96MAE58MXCE5C4SSMEMCEK",
|
||||
OriginAccount: nil,
|
||||
TargetAccountID: "01FE96MXRHWZHKC0WH5FT82H1A",
|
||||
TargetAccount: nil,
|
||||
StatusID: "01FE96NBPNJNY26730FT6GZTFE",
|
||||
Status: nil,
|
||||
}
|
||||
}
|
||||
|
||||
type NotificationValidateTestSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func (suite *NotificationValidateTestSuite) TestValidateNotificationHappyPath() {
|
||||
// no problem here
|
||||
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))
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
}
|
||||
|
|
@ -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"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 >smodel.RouterSession{
|
||||
ID: "01FE91RJR88PSEEE30EV35QR8N",
|
||||
Auth: []byte("12345678901234567890123456789012"),
|
||||
Crypt: []byte("12345678901234567890123456789012"),
|
||||
}
|
||||
}
|
||||
|
||||
type RouterSessionValidateTestSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func (suite *RouterSessionValidateTestSuite) TestValidateRouterSessionHappyPath() {
|
||||
// no problem here
|
||||
r := happyRouterSession()
|
||||
err := 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))
|
||||
}
|
||||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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 >smodel.Status{
|
||||
ID: "01FEBBH6NYDG87NK6A6EC543ED",
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
URI: "https://example.org/users/test_user/statuses/01FEBBH6NYDG87NK6A6EC543ED",
|
||||
URL: "https://example.org/@test_user/01FEBBH6NYDG87NK6A6EC543ED",
|
||||
Content: "<p>Test status! #hello</p>",
|
||||
AttachmentIDs: []string{"01FEBBKZBY9H5FEP3PHVVAAGN1", "01FEBBM7S2R4WT6WWW22KN1PWE"},
|
||||
Attachments: nil,
|
||||
TagIDs: []string{"01FEBBNBMBSN1FESMZ1TCXNWYP"},
|
||||
Tags: nil,
|
||||
MentionIDs: nil,
|
||||
Mentions: nil,
|
||||
EmojiIDs: nil,
|
||||
Emojis: nil,
|
||||
Local: 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))
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 >smodel.StatusBookmark{
|
||||
ID: "01FE91RJR88PSEEE30EV35QR8N",
|
||||
CreatedAt: time.Now(),
|
||||
AccountID: "01FE96MAE58MXCE5C4SSMEMCEK",
|
||||
Account: nil,
|
||||
TargetAccountID: "01FE96MXRHWZHKC0WH5FT82H1A",
|
||||
TargetAccount: nil,
|
||||
StatusID: "01FE96NBPNJNY26730FT6GZTFE",
|
||||
Status: nil,
|
||||
}
|
||||
}
|
||||
|
||||
type StatusBookmarkValidateTestSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func (suite *StatusBookmarkValidateTestSuite) TestValidateStatusBookmarkHappyPath() {
|
||||
// no problem here
|
||||
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))
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 >smodel.StatusFave{
|
||||
ID: "01FE91RJR88PSEEE30EV35QR8N",
|
||||
CreatedAt: time.Now(),
|
||||
AccountID: "01FE96MAE58MXCE5C4SSMEMCEK",
|
||||
Account: nil,
|
||||
TargetAccountID: "01FE96MXRHWZHKC0WH5FT82H1A",
|
||||
TargetAccount: nil,
|
||||
StatusID: "01FE96NBPNJNY26730FT6GZTFE",
|
||||
Status: nil,
|
||||
URI: "https://example.org/users/user1/activity/faves/01FE91RJR88PSEEE30EV35QR8N",
|
||||
}
|
||||
}
|
||||
|
||||
type StatusFaveValidateTestSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func (suite *StatusFaveValidateTestSuite) TestValidateStatusFaveHappyPath() {
|
||||
// no problem here
|
||||
f := happyStatusFave()
|
||||
err := 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))
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 >smodel.StatusMute{
|
||||
ID: "01FE91RJR88PSEEE30EV35QR8N",
|
||||
CreatedAt: time.Now(),
|
||||
AccountID: "01FE96MAE58MXCE5C4SSMEMCEK",
|
||||
Account: nil,
|
||||
TargetAccountID: "01FE96MXRHWZHKC0WH5FT82H1A",
|
||||
TargetAccount: nil,
|
||||
StatusID: "01FE96NBPNJNY26730FT6GZTFE",
|
||||
Status: nil,
|
||||
}
|
||||
}
|
||||
|
||||
type StatusMuteValidateTestSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func (suite *StatusMuteValidateTestSuite) TestValidateStatusMuteHappyPath() {
|
||||
// no problem here
|
||||
m := happyStatusMute()
|
||||
err := 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))
|
||||
}
|
||||
|
|
@ -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"`
|
||||
}
|
||||
|
|
@ -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?
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 >smodel.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))
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 >smodel.User{
|
||||
ID: "01FE8TTK9F34BR0KG7639AJQTX",
|
||||
Email: "whatever@example.org",
|
||||
AccountID: "01FE8TWA7CN8J7237K5DFS1RY5",
|
||||
Account: nil,
|
||||
EncryptedPassword: "$2y$10$tkRapNGW.RWkEuCMWdgArunABFvsPGRvFQY3OibfSJo0RDL3z8WfC",
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
SignUpIP: net.ParseIP("128.64.32.16"),
|
||||
CurrentSignInAt: time.Now(),
|
||||
CurrentSignInIP: net.ParseIP("128.64.32.16"),
|
||||
LastSignInAt: time.Now(),
|
||||
LastSignInIP: net.ParseIP("128.64.32.16"),
|
||||
SignInCount: 0,
|
||||
InviteID: "",
|
||||
ChosenLanguages: []string{},
|
||||
FilteredLanguages: []string{},
|
||||
Locale: "en",
|
||||
CreatedByApplicationID: "01FE8Y5EHMWCA1MHMTNHRVZ1X4",
|
||||
CreatedByApplication: nil,
|
||||
LastEmailedAt: time.Now(),
|
||||
ConfirmationToken: "",
|
||||
ConfirmedAt: time.Now(),
|
||||
ConfirmationSentAt: time.Time{},
|
||||
UnconfirmedEmail: "",
|
||||
Moderator: 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))
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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))
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue