mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-11-12 12:37:30 -06:00
some tidying, some favedby, the usual
This commit is contained in:
parent
ddfb9aae65
commit
c92a72fdea
19 changed files with 1550 additions and 353 deletions
|
|
@ -235,6 +235,18 @@ type DB interface {
|
|||
// 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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -44,26 +44,10 @@ type Account struct {
|
|||
ACCOUNT METADATA
|
||||
*/
|
||||
|
||||
// File name of the avatar on local storage
|
||||
AvatarFileName string
|
||||
// Gif? png? jpeg?
|
||||
AvatarContentType string
|
||||
// Size of the avatar in bytes
|
||||
AvatarFileSize int
|
||||
// When was the avatar last updated?
|
||||
AvatarUpdatedAt time.Time `pg:"type:timestamp"`
|
||||
// Where can the avatar be retrieved?
|
||||
AvatarRemoteURL string
|
||||
// File name of the header on local storage
|
||||
HeaderFileName string
|
||||
// Gif? png? jpeg?
|
||||
HeaderContentType string
|
||||
// Size of the header in bytes
|
||||
HeaderFileSize int
|
||||
// When was the header last updated?
|
||||
HeaderUpdatedAt time.Time `pg:"type:timestamp"`
|
||||
// Where can the header be retrieved?
|
||||
HeaderRemoteURL string
|
||||
// ID of the avatar as a media attachment
|
||||
AvatarMediaAttachmentID string
|
||||
// ID of the header as a media attachment
|
||||
HeaderMediaAttachmentID string
|
||||
// DisplayName for this account. Can be empty, then just the Username will be used for display purposes.
|
||||
DisplayName string
|
||||
// a key/value map of fields that this account has added to their profile
|
||||
|
|
|
|||
|
|
@ -23,13 +23,16 @@ 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:uuid,default:gen_random_uuid(),pk,notnull,unique"`
|
||||
// when was this fave created
|
||||
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
||||
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:",notnull"`
|
||||
// id the account owning the faved status
|
||||
TargetAccountID string `pg:",notnull"`
|
||||
TargetAccountID string `pg:",notnull"`
|
||||
// database id of the status that has been 'faved'
|
||||
StatusID string `pg:",notnull"`
|
||||
StatusID string `pg:",notnull"`
|
||||
|
||||
// FavedStatus is the status being interacted with. It won't be put or retrieved from the db, it's just for conveniently passing a pointer around.
|
||||
FavedStatus *Status `pg:"-"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -497,12 +497,44 @@ func (ps *postgresService) NewSignup(username string, reason string, requireAppr
|
|||
}
|
||||
|
||||
func (ps *postgresService) SetHeaderOrAvatarForAccountID(mediaAttachment *gtsmodel.MediaAttachment, accountID string) error {
|
||||
_, err := ps.conn.Model(mediaAttachment).Insert()
|
||||
return err
|
||||
if mediaAttachment.Avatar && mediaAttachment.Header {
|
||||
return errors.New("one media attachment cannot be both header and avatar")
|
||||
}
|
||||
|
||||
var headerOrAVI string
|
||||
if mediaAttachment.Avatar {
|
||||
headerOrAVI = "avatar"
|
||||
} else if mediaAttachment.Header {
|
||||
headerOrAVI = "header"
|
||||
} else {
|
||||
return errors.New("given media attachment was neither a header nor an avatar")
|
||||
}
|
||||
|
||||
// TODO: there are probably more side effects here that need to be handled
|
||||
if _, err := ps.conn.Model(mediaAttachment).OnConflict("(id) DO UPDATE").Insert(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := ps.conn.Model(>smodel.Account{}).Set(fmt.Sprintf("%s_media_attachment_id = ?", headerOrAVI), mediaAttachment.ID).Where("id = ?", accountID).Update(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ps *postgresService) GetHeaderForAccountID(header *gtsmodel.MediaAttachment, accountID string) error {
|
||||
if err := ps.conn.Model(header).Where("account_id = ?", accountID).Where("header = ?", true).Select(); err != nil {
|
||||
acct := >smodel.Account{}
|
||||
if err := ps.conn.Model(acct).Where("id = ?", accountID).Select(); err != nil {
|
||||
if err == pg.ErrNoRows {
|
||||
return ErrNoEntries{}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if acct.HeaderMediaAttachmentID == "" {
|
||||
return ErrNoEntries{}
|
||||
}
|
||||
|
||||
if err := ps.conn.Model(header).Where("id = ?", acct.HeaderMediaAttachmentID).Select(); err != nil {
|
||||
if err == pg.ErrNoRows {
|
||||
return ErrNoEntries{}
|
||||
}
|
||||
|
|
@ -512,7 +544,19 @@ func (ps *postgresService) GetHeaderForAccountID(header *gtsmodel.MediaAttachmen
|
|||
}
|
||||
|
||||
func (ps *postgresService) GetAvatarForAccountID(avatar *gtsmodel.MediaAttachment, accountID string) error {
|
||||
if err := ps.conn.Model(avatar).Where("account_id = ?", accountID).Where("avatar = ?", true).Select(); err != nil {
|
||||
acct := >smodel.Account{}
|
||||
if err := ps.conn.Model(acct).Where("id = ?", accountID).Select(); err != nil {
|
||||
if err == pg.ErrNoRows {
|
||||
return ErrNoEntries{}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if acct.AvatarMediaAttachmentID == "" {
|
||||
return ErrNoEntries{}
|
||||
}
|
||||
|
||||
if err := ps.conn.Model(avatar).Where("id = ?", acct.AvatarMediaAttachmentID).Select(); err != nil {
|
||||
if err == pg.ErrNoRows {
|
||||
return ErrNoEntries{}
|
||||
}
|
||||
|
|
@ -806,6 +850,79 @@ func (ps *postgresService) StatusPinnedBy(status *gtsmodel.Status, accountID str
|
|||
return ps.conn.Model(>smodel.StatusPin{}).Where("status_id = ?", status.ID).Where("account_id = ?", accountID).Exists()
|
||||
}
|
||||
|
||||
func (ps *postgresService) FaveStatus(status *gtsmodel.Status, accountID string) (*gtsmodel.StatusFave, error) {
|
||||
// first check if a fave already exists, we can just return if so
|
||||
existingFave := >smodel.StatusFave{}
|
||||
err := ps.conn.Model(existingFave).Where("status_id = ?", status.ID).Where("account_id = ?", accountID).Select()
|
||||
if err == nil {
|
||||
// fave already exists so just return nothing at all
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// an error occurred so it might exist or not, we don't know
|
||||
if err != pg.ErrNoRows {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// it doesn't exist so create it
|
||||
newFave := >smodel.StatusFave{
|
||||
AccountID: accountID,
|
||||
TargetAccountID: status.AccountID,
|
||||
StatusID: status.ID,
|
||||
}
|
||||
if _, err = ps.conn.Model(newFave).Insert(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newFave, nil
|
||||
}
|
||||
|
||||
func (ps *postgresService) UnfaveStatus(status *gtsmodel.Status, accountID string) (*gtsmodel.StatusFave, error) {
|
||||
// if a fave doesn't exist, we don't need to do anything
|
||||
existingFave := >smodel.StatusFave{}
|
||||
err := ps.conn.Model(existingFave).Where("status_id = ?", status.ID).Where("account_id = ?", accountID).Select()
|
||||
// the fave doesn't exist so return nothing at all
|
||||
if err == pg.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// an error occurred so it might exist or not, we don't know
|
||||
if err != nil && err != pg.ErrNoRows {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// the fave exists so remove it
|
||||
if _, err = ps.conn.Model(>smodel.StatusFave{}).Where("status_id = ?", status.ID).Where("account_id = ?", accountID).Delete(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return existingFave, nil
|
||||
}
|
||||
|
||||
func (ps *postgresService) WhoFavedStatus(status *gtsmodel.Status) ([]*gtsmodel.Account, error) {
|
||||
accounts := []*gtsmodel.Account{}
|
||||
|
||||
faves := []*gtsmodel.StatusFave{}
|
||||
if err := ps.conn.Model(&faves).Where("status_id = ?", status.ID).Select(); err != nil {
|
||||
if err == pg.ErrNoRows {
|
||||
return accounts, nil // no rows just means nobody has faved this status, so that's fine
|
||||
}
|
||||
return nil, err // an actual error has occurred
|
||||
}
|
||||
|
||||
for _, f := range faves {
|
||||
acc := >smodel.Account{}
|
||||
if err := ps.conn.Model(acc).Where("id = ?", f.AccountID).Select(); err != nil {
|
||||
if err == pg.ErrNoRows {
|
||||
continue // the account doesn't exist for some reason??? but this isn't the place to worry about that so just skip it
|
||||
}
|
||||
return nil, err // an actual error has occurred
|
||||
}
|
||||
accounts = append(accounts, acc)
|
||||
}
|
||||
return accounts, nil
|
||||
}
|
||||
|
||||
/*
|
||||
CONVERSION FUNCTIONS
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue