diff options
Diffstat (limited to 'internal/db/db.go')
-rw-r--r-- | internal/db/db.go | 138 |
1 files changed, 116 insertions, 22 deletions
diff --git a/internal/db/db.go b/internal/db/db.go index 4921270e7..69ad7b822 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -27,8 +27,7 @@ import ( "github.com/go-fed/activity/pub" "github.com/sirupsen/logrus" "github.com/superseriousbusiness/gotosocial/internal/config" - "github.com/superseriousbusiness/gotosocial/internal/db/model" - "github.com/superseriousbusiness/gotosocial/pkg/mastotypes" + "github.com/superseriousbusiness/gotosocial/internal/db/gtsmodel" ) const dbTypePostgres string = "POSTGRES" @@ -79,6 +78,11 @@ type DB interface { // In case of no entries, a 'no entries' error will be returned GetWhere(key string, value interface{}, i interface{}) error + // // GetWhereMany gets one entry where key = value for *ALL* parameters passed as "where". + // // That is, if you pass 2 'where' entries, with 1 being Key username and Value test, and the second + // // being Key domain and Value example.org, only entries will be returned where BOTH conditions are true. + // GetWhereMany(i interface{}, where ...model.Where) error + // GetAll will try to get all entries of type i. // The given interface i will be set to the result of the query, whatever it is. Use a pointer or a slice. // In case of no entries, a 'no entries' error will be returned @@ -88,6 +92,11 @@ type DB interface { // The given interface i will be set to the result of the query, whatever it is. Use a pointer or a slice. Put(i interface{}) error + // Upsert stores or updates i based on the given conflict column, as in https://www.postgresqltutorial.com/postgresql-upsert/ + // It is up to the implementation to figure out how to store it, and using what key. + // The given interface i will be set to the result of the query, whatever it is. Use a pointer or a slice. + Upsert(i interface{}, conflictColumn string) error + // UpdateByID updates i with id id. // The given interface i will be set to the result of the query, whatever it is. Use a pointer or a slice. UpdateByID(id string, i interface{}) error @@ -107,41 +116,46 @@ type DB interface { HANDY SHORTCUTS */ + // CreateInstanceAccount creates an account in the database with the same username as the instance host value. + // Ie., if the instance is hosted at 'example.org' the instance user will have a username of 'example.org'. + // This is needed for things like serving files that belong to the instance and not an individual user/account. + CreateInstanceAccount() error + // GetAccountByUserID is a shortcut for the common action of fetching an account corresponding to a user ID. // The given account pointer will be set to the result of the query, whatever it is. // In case of no entries, a 'no entries' error will be returned - GetAccountByUserID(userID string, account *model.Account) error + GetAccountByUserID(userID string, account *gtsmodel.Account) error // GetFollowRequestsForAccountID is a shortcut for the common action of fetching a list of follow requests targeting the given account ID. // The given slice 'followRequests' will be set to the result of the query, whatever it is. // In case of no entries, a 'no entries' error will be returned - GetFollowRequestsForAccountID(accountID string, followRequests *[]model.FollowRequest) error + GetFollowRequestsForAccountID(accountID string, followRequests *[]gtsmodel.FollowRequest) error // GetFollowingByAccountID is a shortcut for the common action of fetching a list of accounts that accountID is following. // The given slice 'following' will be set to the result of the query, whatever it is. // In case of no entries, a 'no entries' error will be returned - GetFollowingByAccountID(accountID string, following *[]model.Follow) error + GetFollowingByAccountID(accountID string, following *[]gtsmodel.Follow) error // GetFollowersByAccountID is a shortcut for the common action of fetching a list of accounts that accountID is followed by. // The given slice 'followers' will be set to the result of the query, whatever it is. // In case of no entries, a 'no entries' error will be returned - GetFollowersByAccountID(accountID string, followers *[]model.Follow) error + GetFollowersByAccountID(accountID string, followers *[]gtsmodel.Follow) error // GetStatusesByAccountID is a shortcut for the common action of fetching a list of statuses produced by accountID. // The given slice 'statuses' will be set to the result of the query, whatever it is. // In case of no entries, a 'no entries' error will be returned - GetStatusesByAccountID(accountID string, statuses *[]model.Status) error + GetStatusesByAccountID(accountID string, statuses *[]gtsmodel.Status) error // GetStatusesByTimeDescending is a shortcut for getting the most recent statuses. accountID is optional, if not provided // then all statuses will be returned. If limit is set to 0, the size of the returned slice will not be limited. This can // be very memory intensive so you probably shouldn't do this! // In case of no entries, a 'no entries' error will be returned - GetStatusesByTimeDescending(accountID string, statuses *[]model.Status, limit int) error + GetStatusesByTimeDescending(accountID string, statuses *[]gtsmodel.Status, limit int) error // GetLastStatusForAccountID simply gets the most recent status by the given account. // The given slice 'status' pointer will be set to the result of the query, whatever it is. // In case of no entries, a 'no entries' error will be returned - GetLastStatusForAccountID(accountID string, status *model.Status) error + GetLastStatusForAccountID(accountID string, status *gtsmodel.Status) error // IsUsernameAvailable checks whether a given username is available on our domain. // Returns an error if the username is already taken, or something went wrong in the db. @@ -156,32 +170,112 @@ type DB interface { // NewSignup creates a new user in the database with the given parameters, with an *unconfirmed* email address. // By the time this function is called, it should be assumed that all the parameters have passed validation! - NewSignup(username string, reason string, requireApproval bool, email string, password string, signUpIP net.IP, locale string, appID string) (*model.User, error) + NewSignup(username string, reason string, requireApproval bool, email string, password string, signUpIP net.IP, locale string, appID string) (*gtsmodel.User, error) // SetHeaderOrAvatarForAccountID sets the header or avatar for the given accountID to the given media attachment. - SetHeaderOrAvatarForAccountID(mediaAttachment *model.MediaAttachment, accountID string) error + SetHeaderOrAvatarForAccountID(mediaAttachment *gtsmodel.MediaAttachment, accountID string) error // GetHeaderAvatarForAccountID gets the current avatar for the given account ID. // The passed mediaAttachment pointer will be populated with the value of the avatar, if it exists. - GetAvatarForAccountID(avatar *model.MediaAttachment, accountID string) error + GetAvatarForAccountID(avatar *gtsmodel.MediaAttachment, accountID string) error // GetHeaderForAccountID gets the current header for the given account ID. // The passed mediaAttachment pointer will be populated with the value of the header, if it exists. - GetHeaderForAccountID(header *model.MediaAttachment, accountID string) error + GetHeaderForAccountID(header *gtsmodel.MediaAttachment, accountID string) error + + // Blocked checks whether a block exists in eiher direction between two accounts. + // That is, it returns true if account1 blocks account2, OR if account2 blocks account1. + Blocked(account1 string, account2 string) (bool, error) + + // StatusVisible returns true if targetStatus is visible to requestingAccount, based on the + // privacy settings of the status, and any blocks/mutes that might exist between the two accounts + // or account domains. + // + // StatusVisible will also check through the given slice of 'otherRelevantAccounts', which should include: + // + // 1. Accounts mentioned in the targetStatus + // + // 2. Accounts replied to by the target status + // + // 3. Accounts boosted by the target status + // + // Will return an error if something goes wrong while pulling stuff out of the database. + StatusVisible(targetStatus *gtsmodel.Status, targetAccount *gtsmodel.Account, requestingAccount *gtsmodel.Account, relevantAccounts *gtsmodel.RelevantAccounts) (bool, error) + + // Follows returns true if sourceAccount follows target account, or an error if something goes wrong while finding out. + Follows(sourceAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) (bool, error) + + // Mutuals returns true if account1 and account2 both follow each other, or an error if something goes wrong while finding out. + Mutuals(account1 *gtsmodel.Account, account2 *gtsmodel.Account) (bool, error) + + // PullRelevantAccountsFromStatus returns all accounts mentioned in a status, replied to by a status, or boosted by a status + PullRelevantAccountsFromStatus(status *gtsmodel.Status) (*gtsmodel.RelevantAccounts, error) + + // GetReplyCountForStatus returns the amount of replies recorded for a status, or an error if something goes wrong + GetReplyCountForStatus(status *gtsmodel.Status) (int, error) + + // GetReblogCountForStatus returns the amount of reblogs/boosts recorded for a status, or an error if something goes wrong + GetReblogCountForStatus(status *gtsmodel.Status) (int, error) + + // GetFaveCountForStatus returns the amount of faves/likes recorded for a status, or an error if something goes wrong + GetFaveCountForStatus(status *gtsmodel.Status) (int, error) + + // StatusFavedBy checks if a given status has been faved by a given account ID + StatusFavedBy(status *gtsmodel.Status, accountID string) (bool, error) + + // StatusRebloggedBy checks if a given status has been reblogged/boosted by a given account ID + StatusRebloggedBy(status *gtsmodel.Status, accountID string) (bool, error) + + // StatusMutedBy checks if a given status has been muted by a given account ID + StatusMutedBy(status *gtsmodel.Status, accountID string) (bool, error) + + // StatusBookmarkedBy checks if a given status has been bookmarked by a given account ID + StatusBookmarkedBy(status *gtsmodel.Status, accountID string) (bool, error) + + // StatusPinnedBy checks if a given status has been pinned by a given account ID + StatusPinnedBy(status *gtsmodel.Status, accountID string) (bool, error) + + // FaveStatus faves the given status, using accountID as the faver. + // The returned fave will be nil if the status was already faved. + FaveStatus(status *gtsmodel.Status, accountID string) (*gtsmodel.StatusFave, error) + + // UnfaveStatus unfaves the given status, using accountID as the unfaver (sure, that's a word). + // The returned fave will be nil if the status was already not faved. + UnfaveStatus(status *gtsmodel.Status, accountID string) (*gtsmodel.StatusFave, error) + + // WhoFavedStatus returns a slice of accounts who faved the given status. + // This slice will be unfiltered, not taking account of blocks and whatnot, so filter it before serving it back to a user. + WhoFavedStatus(status *gtsmodel.Status) ([]*gtsmodel.Account, error) /* USEFUL CONVERSION FUNCTIONS */ - // AccountToMastoSensitive takes a db model account as a param, and returns a populated mastotype account, or an error - // if something goes wrong. The returned account should be ready to serialize on an API level, and may have sensitive fields, - // so serve it only to an authorized user who should have permission to see it. - AccountToMastoSensitive(account *model.Account) (*mastotypes.Account, error) - - // AccountToMastoPublic takes a db model account as a param, and returns a populated mastotype account, or an error - // if something goes wrong. The returned account should be ready to serialize on an API level, and may NOT have sensitive fields. - // In other words, this is the public record that the server has of an account. - AccountToMastoPublic(account *model.Account) (*mastotypes.Account, error) + // MentionStringsToMentions takes a slice of deduplicated, lowercase account names in the form "@test@whatever.example.org" for a remote account, + // or @test for a local account, which have been mentioned in a status. + // It takes the id of the account that wrote the status, and the id of the status itself, and then + // checks in the database for the mentioned accounts, and returns a slice of mentions generated based on the given parameters. + // + // Note: this func doesn't/shouldn't do any manipulation of the accounts in the DB, it's just for checking + // if they exist in the db and conveniently returning them if they do. + MentionStringsToMentions(targetAccounts []string, originAccountID string, statusID string) ([]*gtsmodel.Mention, error) + + // TagStringsToTags takes a slice of deduplicated, lowercase tags in the form "somehashtag", which have been + // used in a status. It takes the id of the account that wrote the status, and the id of the status itself, and then + // returns a slice of *model.Tag corresponding to the given tags. If the tag already exists in database, that tag + // will be returned. Otherwise a pointer to a new tag struct will be created and returned. + // + // Note: this func doesn't/shouldn't do any manipulation of the tags in the DB, it's just for checking + // if they exist in the db already, and conveniently returning them, or creating new tag structs. + TagStringsToTags(tags []string, originAccountID string, statusID string) ([]*gtsmodel.Tag, error) + + // EmojiStringsToEmojis takes a slice of deduplicated, lowercase emojis in the form ":emojiname:", which have been + // used in a status. It takes the id of the account that wrote the status, and the id of the status itself, and then + // returns a slice of *model.Emoji corresponding to the given emojis. + // + // Note: this func doesn't/shouldn't do any manipulation of the emoji in the DB, it's just for checking + // if they exist in the db and conveniently returning them if they do. + EmojiStringsToEmojis(emojis []string, originAccountID string, statusID string) ([]*gtsmodel.Emoji, error) } // New returns a new database service that satisfies the DB interface and, by extension, |