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:
@ -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/).
|
@ -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?
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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?
|
||||
|
@ -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"`
|
||||
}
|
||||
|
@ -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)"`
|
||||
}
|
||||
|
@ -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?
|
||||
|
@ -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?
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:"-"`
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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"`
|
||||
}
|
||||
|
@ -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"`
|
||||
|
||||
|
@ -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"`
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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"`
|
||||
|
||||
|
Reference in New Issue
Block a user