summaryrefslogtreecommitdiff
path: root/internal/db
diff options
context:
space:
mode:
Diffstat (limited to 'internal/db')
-rw-r--r--internal/db/db.go11
-rw-r--r--internal/db/pg/pg.go91
2 files changed, 61 insertions, 41 deletions
diff --git a/internal/db/db.go b/internal/db/db.go
index a354ddee8..cbcd698c9 100644
--- a/internal/db/db.go
+++ b/internal/db/db.go
@@ -160,16 +160,14 @@ type DB interface {
// In case of no entries, a 'no entries' error will be returned
GetFavesByAccountID(accountID string, faves *[]gtsmodel.StatusFave) 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 *[]gtsmodel.Status) error
+ // CountStatusesByAccountID is a shortcut for the common action of counting statuses produced by accountID.
+ CountStatusesByAccountID(accountID string) (int, 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 *[]gtsmodel.Status, limit int) error
+ GetStatusesByTimeDescending(accountID string, statuses *[]gtsmodel.Status, limit int, excludeReplies bool, maxID string, pinned bool, mediaOnly bool) 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.
@@ -251,9 +249,6 @@ type DB interface {
// 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)
diff --git a/internal/db/pg/pg.go b/internal/db/pg/pg.go
index f8c2fdbe8..d3590a027 100644
--- a/internal/db/pg/pg.go
+++ b/internal/db/pg/pg.go
@@ -456,23 +456,35 @@ func (ps *postgresService) GetFavesByAccountID(accountID string, faves *[]gtsmod
return nil
}
-func (ps *postgresService) GetStatusesByAccountID(accountID string, statuses *[]gtsmodel.Status) error {
- if err := ps.conn.Model(statuses).Where("account_id = ?", accountID).Select(); err != nil {
+func (ps *postgresService) CountStatusesByAccountID(accountID string) (int, error) {
+ count, err := ps.conn.Model(&gtsmodel.Status{}).Where("account_id = ?", accountID).Count()
+ if err != nil {
if err == pg.ErrNoRows {
- return db.ErrNoEntries{}
+ return 0, nil
}
- return err
+ return 0, err
}
- return nil
+ return count, nil
}
-func (ps *postgresService) GetStatusesByTimeDescending(accountID string, statuses *[]gtsmodel.Status, limit int) error {
+func (ps *postgresService) GetStatusesByTimeDescending(accountID string, statuses *[]gtsmodel.Status, limit int, excludeReplies bool, maxID string, pinned bool, mediaOnly bool) error {
q := ps.conn.Model(statuses).Order("created_at DESC")
+ if accountID != "" {
+ q = q.Where("account_id = ?", accountID)
+ }
if limit != 0 {
q = q.Limit(limit)
}
- if accountID != "" {
- q = q.Where("account_id = ?", accountID)
+ if excludeReplies {
+ q = q.Where("? IS NULL", pg.Ident("in_reply_to_id"))
+ }
+ if pinned {
+ q = q.Where("pinned = ?", true)
+ }
+ if mediaOnly {
+ q = q.WhereGroup(func(q *pg.Query) (*pg.Query, error) {
+ return q.Where("? IS NOT NULL", pg.Ident("attachments")).Where("attachments != '{}'"), nil
+ })
}
if err := q.Select(); err != nil {
if err == pg.ErrNoRows {
@@ -679,20 +691,23 @@ func (ps *postgresService) StatusVisible(targetStatus *gtsmodel.Status, targetAc
}
// if the target user doesn't exist (anymore) then the status also shouldn't be visible
- targetUser := &gtsmodel.User{}
- if err := ps.conn.Model(targetUser).Where("account_id = ?", targetAccount.ID).Select(); err != nil {
- l.Debug("target user could not be selected")
- if err == pg.ErrNoRows {
- return false, db.ErrNoEntries{}
+ // note: we only do this for local users
+ if targetAccount.Domain == "" {
+ targetUser := &gtsmodel.User{}
+ if err := ps.conn.Model(targetUser).Where("account_id = ?", targetAccount.ID).Select(); err != nil {
+ l.Debug("target user could not be selected")
+ if err == pg.ErrNoRows {
+ return false, db.ErrNoEntries{}
+ }
+ return false, err
}
- return false, err
- }
- // if target user is disabled, not yet approved, or not confirmed then don't show the status
- // (although in the latter two cases it's unlikely they posted a status yet anyway, but you never know!)
- if targetUser.Disabled || !targetUser.Approved || targetUser.ConfirmedAt.IsZero() {
- l.Debug("target user is disabled, not approved, or not confirmed")
- return false, nil
+ // if target user is disabled, not yet approved, or not confirmed then don't show the status
+ // (although in the latter two cases it's unlikely they posted a status yet anyway, but you never know!)
+ if targetUser.Disabled || !targetUser.Approved || targetUser.ConfirmedAt.IsZero() {
+ l.Debug("target user is disabled, not approved, or not confirmed")
+ return false, nil
+ }
}
// If requesting account is nil, that means whoever requested the status didn't auth, or their auth failed.
@@ -755,6 +770,7 @@ func (ps *postgresService) StatusVisible(targetStatus *gtsmodel.Status, targetAc
if blocked, err := ps.Blocked(relevantAccounts.ReplyToAccount.ID, requestingAccount.ID); err != nil {
return false, err
} else if blocked {
+ l.Debug("a block exists between requesting account and reply to account")
return false, nil
}
}
@@ -764,6 +780,7 @@ func (ps *postgresService) StatusVisible(targetStatus *gtsmodel.Status, targetAc
if blocked, err := ps.Blocked(relevantAccounts.BoostedAccount.ID, requestingAccount.ID); err != nil {
return false, err
} else if blocked {
+ l.Debug("a block exists between requesting account and boosted account")
return false, nil
}
}
@@ -773,6 +790,7 @@ func (ps *postgresService) StatusVisible(targetStatus *gtsmodel.Status, targetAc
if blocked, err := ps.Blocked(relevantAccounts.BoostedReplyToAccount.ID, requestingAccount.ID); err != nil {
return false, err
} else if blocked {
+ l.Debug("a block exists between requesting account and boosted reply to account")
return false, nil
}
}
@@ -782,9 +800,17 @@ func (ps *postgresService) StatusVisible(targetStatus *gtsmodel.Status, targetAc
if blocked, err := ps.Blocked(a.ID, requestingAccount.ID); err != nil {
return false, err
} else if blocked {
+ l.Debug("a block exists between requesting account and a mentioned account")
return false, nil
}
}
+
+ // if the requesting account is mentioned in the status it should always be visible
+ for _, acct := range relevantAccounts.MentionedAccounts {
+ if acct.ID == requestingAccount.ID {
+ return true, nil // yep it's mentioned!
+ }
+ }
}
// at this point we know neither account blocks the other, or another account mentioned or otherwise referred to in the status
@@ -800,6 +826,7 @@ func (ps *postgresService) StatusVisible(targetStatus *gtsmodel.Status, targetAc
return false, err
}
if !follows {
+ l.Debug("requested status is followers only but requesting account is not a follower")
return false, nil
}
return true, nil
@@ -810,16 +837,12 @@ func (ps *postgresService) StatusVisible(targetStatus *gtsmodel.Status, targetAc
return false, err
}
if !mutuals {
+ l.Debug("requested status is mutuals only but accounts aren't mufos")
return false, nil
}
return true, nil
case gtsmodel.VisibilityDirect:
- // make sure the requesting account is mentioned in the status
- for _, menchie := range targetStatus.Mentions {
- if menchie == requestingAccount.ID {
- return true, nil // yep it's mentioned!
- }
- }
+ l.Debug("requesting account requests a status it's not mentioned in")
return false, nil // it's not mentioned -_-
}
@@ -890,10 +913,16 @@ func (ps *postgresService) PullRelevantAccountsFromStatus(targetStatus *gtsmodel
}
// now get all accounts with IDs that are mentioned in the status
- for _, mentionedAccountID := range targetStatus.Mentions {
+ for _, mentionID := range targetStatus.Mentions {
+
+ mention := &gtsmodel.Mention{}
+ if err := ps.conn.Model(mention).Where("id = ?", mentionID).Select(); err != nil {
+ return accounts, fmt.Errorf("error getting mention with id %s: %s", mentionID, err)
+ }
+
mentionedAccount := &gtsmodel.Account{}
- if err := ps.conn.Model(mentionedAccount).Where("id = ?", mentionedAccountID).Select(); err != nil {
- return accounts, err
+ if err := ps.conn.Model(mentionedAccount).Where("id = ?", mention.TargetAccountID).Select(); err != nil {
+ return accounts, fmt.Errorf("error getting mentioned account: %s", err)
}
accounts.MentionedAccounts = append(accounts.MentionedAccounts, mentionedAccount)
}
@@ -929,10 +958,6 @@ func (ps *postgresService) StatusBookmarkedBy(status *gtsmodel.Status, accountID
return ps.conn.Model(&gtsmodel.StatusBookmark{}).Where("status_id = ?", status.ID).Where("account_id = ?", accountID).Exists()
}
-func (ps *postgresService) StatusPinnedBy(status *gtsmodel.Status, accountID string) (bool, error) {
- return ps.conn.Model(&gtsmodel.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 := &gtsmodel.StatusFave{}