Timeline manager (#40)

* start messing about with timeline manager

* i have no idea what i'm doing

* i continue to not know what i'm doing

* it's coming along

* bit more progress

* update timeline with new posts as they come in

* lint and fmt

* Select accounts where empty string

* restructure a bunch, get unfaves working

* moving stuff around

* federate status deletes properly

* mention regex better but not 100% there

* fix regex

* some more hacking away at the timeline code phew

* fix up some little things

* i can't even

* more timeline stuff

* move to ulid

* fiddley

* some lil fixes for kibou compatibility

* timelines working pretty alright!

* tidy + lint
This commit is contained in:
Tobi Smethurst
2021-06-13 18:42:28 +02:00
committed by GitHub
parent 6ac6f8d614
commit b4288f3c47
96 changed files with 3458 additions and 1679 deletions

View File

@ -1,5 +0,0 @@
# gtsmodel
This package contains types used *internally* by GoToSocial and added/removed/selected from the database. As such, they contain sensitive fields which should **never** be serialized or reach the API level. Use the [mastotypes](../../pkg/mastotypes) package for that.
The annotation used on these structs is for handling them via the go-pg ORM. See [here](https://pg.uptrace.dev/models/).

View File

@ -33,8 +33,8 @@ type Account struct {
BASIC INFO
*/
// id of this account in the local database; the end-user will never need to know this, it's strictly internal
ID string `pg:"type:uuid,default:gen_random_uuid(),pk,notnull,unique"`
// id of this account in the local database
ID string `pg:"type:CHAR(26),pk,notnull,unique"`
// Username of the account, should just be a string of [a-z0-9_]. Can be added to domain to create the full username in the form ``[username]@[domain]`` eg., ``user_96@example.org``
Username string `pg:",notnull,unique:userdomain"` // username and domain should be unique *with* each other
// Domain of the account, will be null if this is a local account, otherwise something like ``example.org`` or ``mastodon.social``. Should be unique with username.
@ -45,11 +45,11 @@ type Account struct {
*/
// ID of the avatar as a media attachment
AvatarMediaAttachmentID string
AvatarMediaAttachmentID string `pg:"type:CHAR(26)"`
// For a non-local account, where can the header be fetched?
AvatarRemoteURL string
// ID of the header as a media attachment
HeaderMediaAttachmentID string
HeaderMediaAttachmentID string `pg:"type:CHAR(26)"`
// For a non-local account, where can the header be fetched?
HeaderRemoteURL string
// DisplayName for this account. Can be empty, then just the Username will be used for display purposes.
@ -61,7 +61,7 @@ type Account struct {
// Is this a memorial account, ie., has the user passed away?
Memorial bool
// This account has moved this account id in the database
MovedToAccountID string
MovedToAccountID string `pg:"type:CHAR(26)"`
// When was this account created?
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// When was this account last updated?

View File

@ -22,7 +22,7 @@ package gtsmodel
// It is used to authorize tokens etc, and is associated with an oauth client id in the database.
type Application struct {
// id of this application in the db
ID string `pg:"type:uuid,default:gen_random_uuid(),pk,notnull"`
ID string `pg:"type:CHAR(26),pk,notnull"`
// name of the application given when it was created (eg., 'tusky')
Name string
// website for the application given when it was created (eg., 'https://tusky.app')
@ -30,7 +30,7 @@ type Application struct {
// redirect uri requested by the application for oauth2 flow
RedirectURI string
// id of the associated oauth client entity in the db
ClientID string
ClientID string `pg:"type:CHAR(26)"`
// secret of the associated oauth client entity in the db
ClientSecret string
// scopes requested when this app was created

View File

@ -5,15 +5,15 @@ import "time"
// Block refers to the blocking of one account by another.
type Block struct {
// id of this block in the database
ID string `pg:"type:uuid,default:gen_random_uuid(),pk,notnull"`
ID string `pg:"type:CHAR(26),pk,notnull"`
// When was this block created
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// When was this block updated
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// Who created this block?
AccountID string `pg:",notnull"`
AccountID string `pg:"type:CHAR(26),notnull"`
// Who is targeted by this block?
TargetAccountID string `pg:",notnull"`
TargetAccountID string `pg:"type:CHAR(26),notnull"`
// Activitypub URI for this block
URI string
}

View File

@ -23,7 +23,7 @@ import "time"
// DomainBlock represents a federation block against a particular domain, of varying severity.
type DomainBlock struct {
// ID of this block in the database
ID string `pg:"type:uuid,default:gen_random_uuid(),pk,notnull,unique"`
ID string `pg:"type:CHAR(26),pk,notnull,unique"`
// Domain to block. If ANY PART of the candidate domain contains this string, it will be blocked.
// For example: 'example.org' also blocks 'gts.example.org'. '.com' blocks *any* '.com' domains.
// TODO: implement wildcards here
@ -33,7 +33,7 @@ type DomainBlock struct {
// When was this block updated
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// Account ID of the creator of this block
CreatedByAccountID string `pg:",notnull"`
CreatedByAccountID string `pg:"type:CHAR(26),notnull"`
// TODO: define this
Severity int
// Reject media from this domain?

View File

@ -23,7 +23,7 @@ import "time"
// EmailDomainBlock represents a domain that the server should automatically reject sign-up requests from.
type EmailDomainBlock struct {
// ID of this block in the database
ID string `pg:"type:uuid,default:gen_random_uuid(),pk,notnull,unique"`
ID string `pg:"type:CHAR(26),pk,notnull,unique"`
// Email domain to block. Eg. 'gmail.com' or 'hotmail.com'
Domain string `pg:",notnull"`
// When was this block created
@ -31,5 +31,5 @@ type EmailDomainBlock struct {
// When was this block updated
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// Account ID of the creator of this block
CreatedByAccountID string `pg:",notnull"`
CreatedByAccountID string `pg:"type:CHAR(26),notnull"`
}

View File

@ -23,7 +23,7 @@ import "time"
// Emoji represents a custom emoji that's been uploaded through the admin UI, and is useable by instance denizens.
type Emoji struct {
// database ID of this emoji
ID string `pg:"type:uuid,default:gen_random_uuid(),pk,notnull"`
ID string `pg:"type:CHAR(26),pk,notnull"`
// String shortcode for this emoji -- the part that's between colons. This should be lowercase a-z_
// eg., 'blob_hug' 'purple_heart' Must be unique with domain.
Shortcode string `pg:",notnull,unique:shortcodedomain"`
@ -73,5 +73,5 @@ type Emoji struct {
// Is this emoji visible in the admin emoji picker?
VisibleInPicker bool `pg:",notnull,default:true"`
// In which emoji category is this emoji visible?
CategoryID string
CategoryID string `pg:"type:CHAR(26)"`
}

View File

@ -23,15 +23,15 @@ import "time"
// Follow represents one account following another, and the metadata around that follow.
type Follow struct {
// id of this follow in the database
ID string `pg:"type:uuid,default:gen_random_uuid(),pk,notnull,unique"`
ID string `pg:"type:CHAR(26),pk,notnull,unique"`
// When was this follow created?
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// When was this follow last updated?
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// Who does this follow belong to?
AccountID string `pg:",unique:srctarget,notnull"`
AccountID string `pg:"type:CHAR(26),unique:srctarget,notnull"`
// Who does AccountID follow?
TargetAccountID string `pg:",unique:srctarget,notnull"`
TargetAccountID string `pg:"type:CHAR(26),unique:srctarget,notnull"`
// Does this follow also want to see reblogs and not just posts?
ShowReblogs bool `pg:"default:true"`
// What is the activitypub URI of this follow?

View File

@ -23,15 +23,15 @@ import "time"
// FollowRequest represents one account requesting to follow another, and the metadata around that request.
type FollowRequest struct {
// id of this follow request in the database
ID string `pg:"type:uuid,default:gen_random_uuid(),pk,notnull,unique"`
ID string `pg:"type:CHAR(26),pk,notnull,unique"`
// When was this follow request created?
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// When was this follow request last updated?
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// Who does this follow request originate from?
AccountID string `pg:",unique:srctarget,notnull"`
AccountID string `pg:"type:CHAR(26),unique:srctarget,notnull"`
// Who is the target of this follow request?
TargetAccountID string `pg:",unique:srctarget,notnull"`
TargetAccountID string `pg:"type:CHAR(26),unique:srctarget,notnull"`
// Does this follow also want to see reblogs and not just posts?
ShowReblogs bool `pg:"default:true"`
// What is the activitypub URI of this follow request?

View File

@ -5,7 +5,7 @@ import "time"
// Instance represents a federated instance, either local or remote.
type Instance struct {
// ID of this instance in the database
ID string `pg:"type:uuid,default:gen_random_uuid(),pk,notnull,unique"`
ID string `pg:"type:CHAR(26),pk,notnull,unique"`
// Instance domain eg example.org
Domain string `pg:",notnull,unique"`
// Title of this instance as it would like to be displayed.
@ -19,7 +19,7 @@ type Instance struct {
// When was this instance suspended, if at all?
SuspendedAt time.Time
// ID of any existing domain block for this instance in the database
DomainBlockID string
DomainBlockID string `pg:"type:CHAR(26)"`
// Short description of this instance
ShortDescription string
// Longer description of this instance
@ -27,7 +27,7 @@ type Instance struct {
// Contact email address for this instance
ContactEmail string
// Contact account ID in the database for this instance
ContactAccountID string
ContactAccountID string `pg:"type:CHAR(26)"`
// Reputation score of this instance
Reputation int64 `pg:",notnull,default:0"`
// Version of the software used on this instance

View File

@ -26,9 +26,9 @@ import (
// somewhere in storage and that can be retrieved and served by the router.
type MediaAttachment struct {
// ID of the attachment in the database
ID string `pg:"type:uuid,default:gen_random_uuid(),pk,notnull,unique"`
ID string `pg:"type:CHAR(26),pk,notnull,unique"`
// ID of the status to which this is attached
StatusID string
StatusID string `pg:"type:CHAR(26)"`
// Where can the attachment be retrieved on *this* server
URL string
// Where can the attachment be retrieved on a remote server (empty for local media)
@ -42,11 +42,11 @@ type MediaAttachment struct {
// Metadata about the file
FileMeta FileMeta
// To which account does this attachment belong
AccountID string `pg:",notnull"`
AccountID string `pg:"type:CHAR(26),notnull"`
// Description of the attachment (for screenreaders)
Description string
// To which scheduled status does this attachment belong
ScheduledStatusID string
ScheduledStatusID string `pg:"type:CHAR(26)"`
// What is the generated blurhash of this attachment
Blurhash string
// What is the processing status of this attachment

View File

@ -23,19 +23,19 @@ import "time"
// Mention refers to the 'tagging' or 'mention' of a user within a status.
type Mention struct {
// ID of this mention in the database
ID string `pg:"type:uuid,default:gen_random_uuid(),pk,notnull,unique"`
ID string `pg:"type:CHAR(26),pk,notnull,unique"`
// ID of the status this mention originates from
StatusID string `pg:",notnull"`
StatusID string `pg:"type:CHAR(26),notnull"`
// When was this mention created?
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// When was this mention last updated?
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// What's the internal account ID of the originator of the mention?
OriginAccountID string `pg:",notnull"`
OriginAccountID string `pg:"type:CHAR(26),notnull"`
// What's the AP URI of the originator of the mention?
OriginAccountURI string `pg:",notnull"`
// What's the internal account ID of the mention target?
TargetAccountID string `pg:",notnull"`
TargetAccountID string `pg:"type:CHAR(26),notnull"`
// Prevent this mention from generating a notification?
Silent bool
@ -56,6 +56,10 @@ type Mention struct {
//
// This will not be put in the database, it's just for convenience.
MentionedAccountURI string `pg:"-"`
// MentionedAccountURL is the web url of the user mentioned.
//
// This will not be put in the database, it's just for convenience.
MentionedAccountURL string `pg:"-"`
// A pointer to the gtsmodel account of the mentioned account.
GTSAccount *Account `pg:"-"`
}

View File

@ -23,17 +23,17 @@ import "time"
// Notification models an alert/notification sent to an account about something like a reblog, like, new follow request, etc.
type Notification struct {
// ID of this notification in the database
ID string `pg:"type:uuid,default:gen_random_uuid(),pk,notnull"`
ID string `pg:"type:CHAR(26),pk,notnull"`
// Type of this notification
NotificationType NotificationType `pg:",notnull"`
// Creation time of this notification
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// Which account does this notification target (ie., who will receive the notification?)
TargetAccountID string `pg:",notnull"`
TargetAccountID string `pg:"type:CHAR(26),notnull"`
// Which account performed the action that created this notification?
OriginAccountID string `pg:",notnull"`
OriginAccountID string `pg:"type:CHAR(26),notnull"`
// If the notification pertains to a status, what is the database ID of that status?
StatusID string
StatusID string `pg:"type:CHAR(26)"`
// Has this notification been read already?
Read bool

View File

@ -23,7 +23,7 @@ import "time"
// Status represents a user-created 'post' or 'status' in the database, either remote or local
type Status struct {
// id of the status in the database
ID string `pg:"type:uuid,default:gen_random_uuid(),pk,notnull"`
ID string `pg:"type:CHAR(26),pk,notnull"`
// uri at which this status is reachable
URI string `pg:",unique"`
// web url for viewing this status
@ -45,13 +45,13 @@ type Status struct {
// is this status from a local account?
Local bool
// which account posted this status?
AccountID string
AccountID string `pg:"type:CHAR(26),notnull"`
// id of the status this status is a reply to
InReplyToID string
InReplyToID string `pg:"type:CHAR(26)"`
// id of the account that this status replies to
InReplyToAccountID string
InReplyToAccountID string `pg:"type:CHAR(26)"`
// id of the status this status is a boost of
BoostOfID string
BoostOfID string `pg:"type:CHAR(26)"`
// cw string for this status
ContentWarning string
// visibility entry for this status
@ -61,7 +61,7 @@ type Status struct {
// what language is this status written in?
Language string
// Which application was used to create this status?
CreatedWithApplicationID string
CreatedWithApplicationID string `pg:"type:CHAR(26)"`
// advanced visibility for this status
VisibilityAdvanced *VisibilityAdvanced
// What is the activitystreams type of this status? See: https://www.w3.org/TR/activitystreams-vocabulary/#object-types
@ -153,6 +153,7 @@ type VisibilityAdvanced struct {
// RelevantAccounts denotes accounts that are replied to, boosted by, or mentioned in a status.
type RelevantAccounts struct {
StatusAuthor *Account
ReplyToAccount *Account
BoostedAccount *Account
BoostedReplyToAccount *Account

View File

@ -23,13 +23,13 @@ import "time"
// StatusBookmark refers to one account having a 'bookmark' of the status of another account
type StatusBookmark struct {
// id of this bookmark in the database
ID string `pg:"type:uuid,default:gen_random_uuid(),pk,notnull,unique"`
ID string `pg:"type:CHAR(26),pk,notnull,unique"`
// when was this bookmark created
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// id of the account that created ('did') the bookmarking
AccountID string `pg:",notnull"`
AccountID string `pg:"type:CHAR(26),notnull"`
// id the account owning the bookmarked status
TargetAccountID string `pg:",notnull"`
TargetAccountID string `pg:"type:CHAR(26),notnull"`
// database id of the status that has been bookmarked
StatusID string `pg:",notnull"`
StatusID string `pg:"type:CHAR(26),notnull"`
}

View File

@ -23,15 +23,15 @@ import "time"
// StatusFave refers to a 'fave' or 'like' in the database, from one account, targeting the status of another account
type StatusFave struct {
// id of this fave in the database
ID string `pg:"type:uuid,default:gen_random_uuid(),pk,notnull,unique"`
ID string `pg:"type:CHAR(26),pk,notnull,unique"`
// when was this fave created
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// id of the account that created ('did') the fave
AccountID string `pg:",notnull"`
AccountID string `pg:"type:CHAR(26),notnull"`
// id the account owning the faved status
TargetAccountID string `pg:",notnull"`
TargetAccountID string `pg:"type:CHAR(26),notnull"`
// database id of the status that has been 'faved'
StatusID string `pg:",notnull"`
StatusID string `pg:"type:CHAR(26),notnull"`
// ActivityPub URI of this fave
URI string `pg:",notnull"`

View File

@ -23,13 +23,13 @@ import "time"
// StatusMute refers to one account having muted the status of another account or its own
type StatusMute struct {
// id of this mute in the database
ID string `pg:"type:uuid,default:gen_random_uuid(),pk,notnull,unique"`
ID string `pg:"type:CHAR(26),pk,notnull,unique"`
// when was this mute created
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// id of the account that created ('did') the mute
AccountID string `pg:",notnull"`
AccountID string `pg:"type:CHAR(26),notnull"`
// id the account owning the muted status (can be the same as accountID)
TargetAccountID string `pg:",notnull"`
TargetAccountID string `pg:"type:CHAR(26),notnull"`
// database id of the status that has been muted
StatusID string `pg:",notnull"`
StatusID string `pg:"type:CHAR(26),notnull"`
}

View File

@ -23,13 +23,13 @@ import "time"
// Tag represents a hashtag for gathering public statuses together
type Tag struct {
// id of this tag in the database
ID string `pg:",unique,type:uuid,default:gen_random_uuid(),pk,notnull"`
ID string `pg:",unique,type:CHAR(26),pk,notnull"`
// Href of this tag, eg https://example.org/tags/somehashtag
URL string
// name of this tag -- the tag without the hash part
Name string `pg:",unique,pk,notnull"`
// Which account ID is the first one we saw using this tag?
FirstSeenFromAccountID string
FirstSeenFromAccountID string `pg:"type:CHAR(26)"`
// when was this tag created
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// when was this tag last updated

View File

@ -31,11 +31,11 @@ type User struct {
*/
// id of this user in the local database; the end-user will never need to know this, it's strictly internal
ID string `pg:"type:uuid,default:gen_random_uuid(),pk,notnull,unique"`
ID string `pg:"type:CHAR(26),pk,notnull,unique"`
// confirmed email address for this user, this should be unique -- only one email address registered per instance, multiple users per email are not supported
Email string `pg:"default:null,unique"`
// The id of the local gtsmodel.Account entry for this user, if it exists (unconfirmed users don't have an account yet)
AccountID string `pg:"default:'',notnull,unique"`
AccountID string `pg:"type:CHAR(26),unique"`
// The encrypted password of this user, generated using https://pkg.go.dev/golang.org/x/crypto/bcrypt#GenerateFromPassword. A salt is included so we're safe against 🌈 tables
EncryptedPassword string `pg:",notnull"`
@ -60,7 +60,7 @@ type User struct {
// How many times has this user signed in?
SignInCount int
// id of the user who invited this user (who let this guy in?)
InviteID string
InviteID string `pg:"type:CHAR(26)"`
// What languages does this user want to see?
ChosenLanguages []string
// What languages does this user not want to see?
@ -68,7 +68,7 @@ type User struct {
// In what timezone/locale is this user located?
Locale string
// Which application id created this user? See gtsmodel.Application
CreatedByApplicationID string
CreatedByApplicationID string `pg:"type:CHAR(26)"`
// When did we last contact this user
LastEmailedAt time.Time `pg:"type:timestamp"`