federate status deletes properly
This commit is contained in:
parent
5d2b69c256
commit
197ef03ead
@ -56,5 +56,11 @@ func (m *Module) StatusDELETEHandler(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// the status was already gone/never existed
|
||||
if mastoStatus == nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Record not found"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, mastoStatus)
|
||||
}
|
||||
|
@ -212,7 +212,7 @@ type DB interface {
|
||||
// 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)
|
||||
StatusVisible(targetStatus *gtsmodel.Status, 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)
|
||||
@ -247,10 +247,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)
|
||||
|
||||
// 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)
|
||||
@ -261,10 +257,6 @@ type DB interface {
|
||||
|
||||
GetStatusesWhereFollowing(accountID string, limit int, offsetStatusID string) ([]*gtsmodel.Status, error)
|
||||
|
||||
// GetHomeTimelineForAccount fetches the account's HOME timeline -- ie., posts and replies from people they *follow*.
|
||||
// It will use the given filters and try to return as many statuses up to the limit as possible.
|
||||
GetHomeTimelineForAccount(accountID string, maxID string, sinceID string, minID string, limit int, local bool) ([]*gtsmodel.Status, error)
|
||||
|
||||
// GetPublicTimelineForAccount fetches the account's PUBLIC timline -- ie., posts and replies that are public.
|
||||
// It will use the given filters and try to return as many statuses as possible up to the limit.
|
||||
GetPublicTimelineForAccount(accountID string, maxID string, sinceID string, minID string, limit int, local bool) ([]*gtsmodel.Status, error)
|
||||
|
@ -785,9 +785,11 @@ func (ps *postgresService) GetRelationship(requestingAccount string, targetAccou
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (ps *postgresService) StatusVisible(targetStatus *gtsmodel.Status, targetAccount *gtsmodel.Account, requestingAccount *gtsmodel.Account, relevantAccounts *gtsmodel.RelevantAccounts) (bool, error) {
|
||||
func (ps *postgresService) StatusVisible(targetStatus *gtsmodel.Status, requestingAccount *gtsmodel.Account, relevantAccounts *gtsmodel.RelevantAccounts) (bool, error) {
|
||||
l := ps.log.WithField("func", "StatusVisible")
|
||||
|
||||
targetAccount := relevantAccounts.StatusAuthor
|
||||
|
||||
// if target account is suspended then don't show the status
|
||||
if !targetAccount.SuspendedAt.IsZero() {
|
||||
l.Debug("target account suspended at is not zero")
|
||||
@ -869,7 +871,7 @@ func (ps *postgresService) StatusVisible(targetStatus *gtsmodel.Status, targetAc
|
||||
// check other accounts mentioned/boosted by/replied to by the status, if they exist
|
||||
if relevantAccounts != nil {
|
||||
// status replies to account id
|
||||
if relevantAccounts.ReplyToAccount != nil {
|
||||
if relevantAccounts.ReplyToAccount != nil && relevantAccounts.ReplyToAccount.ID != requestingAccount.ID {
|
||||
if blocked, err := ps.Blocked(relevantAccounts.ReplyToAccount.ID, requestingAccount.ID); err != nil {
|
||||
return false, err
|
||||
} else if blocked {
|
||||
@ -1087,55 +1089,6 @@ func (ps *postgresService) StatusBookmarkedBy(status *gtsmodel.Status, accountID
|
||||
return ps.conn.Model(>smodel.StatusBookmark{}).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{}
|
||||
|
||||
@ -1216,56 +1169,13 @@ func (ps *postgresService) GetStatusesWhereFollowing(accountID string, limit int
|
||||
return statuses, nil
|
||||
}
|
||||
|
||||
func (ps *postgresService) GetHomeTimelineForAccount(accountID string, maxID string, sinceID string, minID string, limit int, local bool) ([]*gtsmodel.Status, error) {
|
||||
statuses := []*gtsmodel.Status{}
|
||||
|
||||
q := ps.conn.Model(&statuses)
|
||||
|
||||
q = q.ColumnExpr("status.*").
|
||||
Join("JOIN follows AS f ON f.target_account_id = status.account_id").
|
||||
Where("f.account_id = ?", accountID).
|
||||
Limit(limit).
|
||||
Order("status.created_at DESC")
|
||||
|
||||
if maxID != "" {
|
||||
s := >smodel.Status{}
|
||||
if err := ps.conn.Model(s).Where("id = ?", maxID).Select(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
q = q.Where("status.created_at < ?", s.CreatedAt)
|
||||
}
|
||||
|
||||
if minID != "" {
|
||||
s := >smodel.Status{}
|
||||
if err := ps.conn.Model(s).Where("id = ?", minID).Select(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
q = q.Where("status.created_at > ?", s.CreatedAt)
|
||||
}
|
||||
|
||||
if sinceID != "" {
|
||||
s := >smodel.Status{}
|
||||
if err := ps.conn.Model(s).Where("id = ?", sinceID).Select(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
q = q.Where("status.created_at > ?", s.CreatedAt)
|
||||
}
|
||||
|
||||
err := q.Select()
|
||||
if err != nil {
|
||||
if err != pg.ErrNoRows {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return statuses, nil
|
||||
}
|
||||
|
||||
func (ps *postgresService) GetPublicTimelineForAccount(accountID string, maxID string, sinceID string, minID string, limit int, local bool) ([]*gtsmodel.Status, error) {
|
||||
statuses := []*gtsmodel.Status{}
|
||||
|
||||
q := ps.conn.Model(&statuses).
|
||||
Where("visibility = ?", gtsmodel.VisibilityPublic).
|
||||
Where("? IS NULL", pg.Ident("in_reply_to_id")).
|
||||
Where("? IS NULL", pg.Ident("boost_of_id")).
|
||||
Limit(limit).
|
||||
Order("created_at DESC")
|
||||
|
||||
|
@ -227,7 +227,7 @@ func (p *processor) AccountStatusesGet(authed *oauth.Auth, targetAccountID strin
|
||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error getting relevant statuses: %s", err))
|
||||
}
|
||||
|
||||
visible, err := p.db.StatusVisible(&s, targetAccount, authed.Account, relevantAccounts)
|
||||
visible, err := p.db.StatusVisible(&s, authed.Account, relevantAccounts)
|
||||
if err != nil {
|
||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error checking status visibility: %s", err))
|
||||
}
|
||||
@ -246,7 +246,7 @@ func (p *processor) AccountStatusesGet(authed *oauth.Auth, targetAccountID strin
|
||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error getting relevant accounts from boosted status: %s", err))
|
||||
}
|
||||
|
||||
boostedVisible, err := p.db.StatusVisible(bs, relevantAccounts.BoostedAccount, authed.Account, boostedRelevantAccounts)
|
||||
boostedVisible, err := p.db.StatusVisible(bs, authed.Account, boostedRelevantAccounts)
|
||||
if err != nil {
|
||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error checking boosted status visibility: %s", err))
|
||||
}
|
||||
|
@ -135,6 +135,22 @@ func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error
|
||||
}
|
||||
return p.federateUnfave(fave, clientMsg.OriginAccount, clientMsg.TargetAccount)
|
||||
}
|
||||
case gtsmodel.ActivityStreamsDelete:
|
||||
// DELETE
|
||||
switch clientMsg.APObjectType {
|
||||
case gtsmodel.ActivityStreamsNote:
|
||||
// DELETE STATUS/NOTE
|
||||
statusToDelete, ok := clientMsg.GTSModel.(*gtsmodel.Status)
|
||||
if !ok {
|
||||
return errors.New("note was not parseable as *gtsmodel.Status")
|
||||
}
|
||||
|
||||
if err := p.deleteStatusFromTimelines(statusToDelete); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return p.federateStatusDelete(statusToDelete, clientMsg.OriginAccount)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -154,6 +170,43 @@ func (p *processor) federateStatus(status *gtsmodel.Status) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *processor) federateStatusDelete(status *gtsmodel.Status, originAccount *gtsmodel.Account) error {
|
||||
asStatus, err := p.tc.StatusToAS(status)
|
||||
if err != nil {
|
||||
return fmt.Errorf("federateStatusDelete: error converting status to as format: %s", err)
|
||||
}
|
||||
|
||||
outboxIRI, err := url.Parse(originAccount.OutboxURI)
|
||||
if err != nil {
|
||||
return fmt.Errorf("federateStatusDelete: error parsing outboxURI %s: %s", originAccount.OutboxURI, err)
|
||||
}
|
||||
|
||||
actorIRI, err := url.Parse(originAccount.URI)
|
||||
if err != nil {
|
||||
return fmt.Errorf("federateStatusDelete: error parsing actorIRI %s: %s", originAccount.URI, err)
|
||||
}
|
||||
|
||||
// create a delete and set the appropriate actor on it
|
||||
delete := streams.NewActivityStreamsDelete()
|
||||
|
||||
// set the actor for the delete
|
||||
deleteActor := streams.NewActivityStreamsActorProperty()
|
||||
deleteActor.AppendIRI(actorIRI)
|
||||
delete.SetActivityStreamsActor(deleteActor)
|
||||
|
||||
// Set the status as the 'object' property.
|
||||
deleteObject := streams.NewActivityStreamsObjectProperty()
|
||||
deleteObject.AppendActivityStreamsNote(asStatus)
|
||||
delete.SetActivityStreamsObject(deleteObject)
|
||||
|
||||
// set the to and cc as the original to/cc of the original status
|
||||
delete.SetActivityStreamsTo(asStatus.GetActivityStreamsTo())
|
||||
delete.SetActivityStreamsCc(asStatus.GetActivityStreamsCc())
|
||||
|
||||
_, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, delete)
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *processor) federateFollow(followRequest *gtsmodel.FollowRequest, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error {
|
||||
// if both accounts are local there's nothing to do here
|
||||
if originAccount.Domain == "" && targetAccount.Domain == "" {
|
||||
|
@ -286,7 +286,7 @@ func (p *processor) timelineStatusForAccount(status *gtsmodel.Status, accountID
|
||||
}
|
||||
|
||||
// make sure the status is visible
|
||||
visible, err := p.db.StatusVisible(status, status.GTSAuthorAccount, timelineAccount, relevantAccounts)
|
||||
visible, err := p.db.StatusVisible(status, timelineAccount, relevantAccounts)
|
||||
if err != nil {
|
||||
errors <- fmt.Errorf("timelineStatus: error getting visibility for status for timeline with id %s: %s", accountID, err)
|
||||
return
|
||||
@ -301,6 +301,6 @@ func (p *processor) timelineStatusForAccount(status *gtsmodel.Status, accountID
|
||||
}
|
||||
}
|
||||
|
||||
func (p *processor) fullyDeleteStatus(status *gtsmodel.Status, accountID string) error {
|
||||
return nil
|
||||
func (p *processor) deleteStatusFromTimelines(status *gtsmodel.Status) error {
|
||||
return p.timelineManager.WipeStatusFromAllTimelines(status.ID)
|
||||
}
|
||||
|
@ -146,6 +146,11 @@ func (p *processor) processFromFederator(federatorMsg gtsmodel.FromFederator) er
|
||||
// 1. delete all media associated with status
|
||||
// 2. delete boosts of status
|
||||
// 3. etc etc etc
|
||||
statusToDelete, ok := federatorMsg.GTSModel.(*gtsmodel.Status)
|
||||
if !ok {
|
||||
return errors.New("note was not parseable as *gtsmodel.Status")
|
||||
}
|
||||
return p.deleteStatusFromTimelines(statusToDelete)
|
||||
case gtsmodel.ActivityStreamsProfile:
|
||||
// DELETE A PROFILE/ACCOUNT
|
||||
// TODO: handle side effects of account deletion here: delete all objects, statuses, media etc associated with account
|
||||
|
@ -109,7 +109,7 @@ func (p *processor) SearchGet(authed *oauth.Auth, searchQuery *apimodel.SearchQu
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if visible, err := p.db.StatusVisible(foundStatus, statusOwner, authed.Account, relevantAccounts); !visible || err != nil {
|
||||
if visible, err := p.db.StatusVisible(foundStatus, authed.Account, relevantAccounts); !visible || err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ func (p *processor) Boost(account *gtsmodel.Account, application *gtsmodel.Appli
|
||||
}
|
||||
|
||||
l.Trace("going to see if status is visible")
|
||||
visible, err := p.db.StatusVisible(targetStatus, targetAccount, account, relevantAccounts) // requestingAccount might well be nil here, but StatusVisible knows how to take care of that
|
||||
visible, err := p.db.StatusVisible(targetStatus, account, relevantAccounts)
|
||||
if err != nil {
|
||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ func (p *processor) BoostedBy(account *gtsmodel.Account, targetStatusID string)
|
||||
}
|
||||
|
||||
l.Trace("going to see if status is visible")
|
||||
visible, err := p.db.StatusVisible(targetStatus, targetAccount, account, relevantAccounts) // requestingAccount might well be nil here, but StatusVisible knows how to take care of that
|
||||
visible, err := p.db.StatusVisible(targetStatus, account, relevantAccounts)
|
||||
if err != nil {
|
||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("StatusBoostedBy: error seeing if status %s is visible: %s", targetStatus.ID, err))
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
)
|
||||
@ -14,7 +15,11 @@ func (p *processor) Delete(account *gtsmodel.Account, targetStatusID string) (*a
|
||||
l.Tracef("going to search for target status %s", targetStatusID)
|
||||
targetStatus := >smodel.Status{}
|
||||
if err := p.db.GetByID(targetStatusID, targetStatus); err != nil {
|
||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
|
||||
if _, ok := err.(db.ErrNoEntries); !ok {
|
||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
|
||||
}
|
||||
// status is already gone
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if targetStatus.AccountID != account.ID {
|
||||
@ -40,10 +45,10 @@ func (p *processor) Delete(account *gtsmodel.Account, targetStatusID string) (*a
|
||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err))
|
||||
}
|
||||
|
||||
if err := p.db.DeleteByID(targetStatus.ID, targetStatus); err != nil {
|
||||
if err := p.db.DeleteByID(targetStatus.ID, >smodel.Status{}); err != nil {
|
||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error deleting status from the database: %s", err))
|
||||
}
|
||||
|
||||
|
||||
// send it back to the processor for async processing
|
||||
p.fromClientAPI <- gtsmodel.FromClientAPI{
|
||||
APObjectType: gtsmodel.ActivityStreamsNote,
|
||||
|
@ -41,7 +41,7 @@ func (p *processor) Fave(account *gtsmodel.Account, targetStatusID string) (*api
|
||||
}
|
||||
|
||||
l.Trace("going to see if status is visible")
|
||||
visible, err := p.db.StatusVisible(targetStatus, targetAccount, account, relevantAccounts) // requestingAccount might well be nil here, but StatusVisible knows how to take care of that
|
||||
visible, err := p.db.StatusVisible(targetStatus, account, relevantAccounts) // requestingAccount might well be nil here, but StatusVisible knows how to take care of that
|
||||
if err != nil {
|
||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ func (p *processor) FavedBy(account *gtsmodel.Account, targetStatusID string) ([
|
||||
}
|
||||
|
||||
l.Trace("going to see if status is visible")
|
||||
visible, err := p.db.StatusVisible(targetStatus, targetAccount, account, relevantAccounts) // requestingAccount might well be nil here, but StatusVisible knows how to take care of that
|
||||
visible, err := p.db.StatusVisible(targetStatus, account, relevantAccounts) // requestingAccount might well be nil here, but StatusVisible knows how to take care of that
|
||||
if err != nil {
|
||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ func (p *processor) Get(account *gtsmodel.Account, targetStatusID string) (*apim
|
||||
}
|
||||
|
||||
l.Trace("going to see if status is visible")
|
||||
visible, err := p.db.StatusVisible(targetStatus, targetAccount, account, relevantAccounts) // requestingAccount might well be nil here, but StatusVisible knows how to take care of that
|
||||
visible, err := p.db.StatusVisible(targetStatus, account, relevantAccounts) // requestingAccount might well be nil here, but StatusVisible knows how to take care of that
|
||||
if err != nil {
|
||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ func (p *processor) Unfave(account *gtsmodel.Account, targetStatusID string) (*a
|
||||
}
|
||||
|
||||
l.Trace("going to see if status is visible")
|
||||
visible, err := p.db.StatusVisible(targetStatus, targetAccount, account, relevantAccounts) // requestingAccount might well be nil here, but StatusVisible knows how to take care of that
|
||||
visible, err := p.db.StatusVisible(targetStatus, account, relevantAccounts) // requestingAccount might well be nil here, but StatusVisible knows how to take care of that
|
||||
if err != nil {
|
||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
|
||||
}
|
||||
@ -60,8 +60,7 @@ func (p *processor) Unfave(account *gtsmodel.Account, targetStatusID string) (*a
|
||||
|
||||
if toUnfave {
|
||||
// we had a fave, so take some action to get rid of it
|
||||
_, err = p.db.UnfaveStatus(targetStatus, account.ID)
|
||||
if err != nil {
|
||||
if err := p.db.DeleteWhere([]db.Where{{Key: "status_id", Value: targetStatus.ID}, {Key: "account_id", Value: account.ID}}, gtsFave); err != nil {
|
||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error unfaveing status: %s", err))
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ func (p *processor) filterStatuses(authed *oauth.Auth, statuses []*gtsmodel.Stat
|
||||
continue
|
||||
}
|
||||
|
||||
visible, err := p.db.StatusVisible(s, targetAccount, authed.Account, relevantAccounts)
|
||||
visible, err := p.db.StatusVisible(s, authed.Account, relevantAccounts)
|
||||
if err != nil {
|
||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("HomeTimelineGet: error checking status visibility: %s", err))
|
||||
}
|
||||
@ -98,7 +98,7 @@ func (p *processor) filterStatuses(authed *oauth.Auth, statuses []*gtsmodel.Stat
|
||||
continue
|
||||
}
|
||||
|
||||
boostedVisible, err := p.db.StatusVisible(bs, relevantAccounts.BoostedAccount, authed.Account, boostedRelevantAccounts)
|
||||
boostedVisible, err := p.db.StatusVisible(bs, authed.Account, boostedRelevantAccounts)
|
||||
if err != nil {
|
||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("HomeTimelineGet: error checking boosted status visibility: %s", err))
|
||||
}
|
||||
@ -204,7 +204,7 @@ func (p *processor) indexAndIngest(statuses []*gtsmodel.Status, timelineAccount
|
||||
l.Error(fmt.Errorf("initTimelineFor: error getting relevant accounts from status %s: %s", s.ID, err))
|
||||
continue
|
||||
}
|
||||
visible, err := p.db.StatusVisible(s, relevantAccounts.StatusAuthor, timelineAccount, relevantAccounts)
|
||||
visible, err := p.db.StatusVisible(s, timelineAccount, relevantAccounts)
|
||||
if err != nil {
|
||||
l.Error(fmt.Errorf("initTimelineFor: error checking visibility of status %s: %s", s.ID, err))
|
||||
continue
|
||||
|
@ -19,6 +19,8 @@
|
||||
package timeline
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -66,6 +68,10 @@ type Manager interface {
|
||||
GetOldestIndexedID(timelineAccountID string) (string, error)
|
||||
// PrepareXFromTop prepares limit n amount of posts, based on their indexed representations, from the top of the index.
|
||||
PrepareXFromTop(timelineAccountID string, limit int) error
|
||||
// WipeStatusFromTimeline completely removes a status and from the index and prepared posts of the given account ID
|
||||
WipeStatusFromTimeline(timelineAccountID string, statusID string) error
|
||||
// WipeStatusFromAllTimelines removes the status from the index and prepared posts of all timelines
|
||||
WipeStatusFromAllTimelines(statusID string) error
|
||||
}
|
||||
|
||||
// NewManager returns a new timeline manager with the given database, typeconverter, config, and log.
|
||||
@ -172,6 +178,37 @@ func (m *manager) PrepareXFromTop(timelineAccountID string, limit int) error {
|
||||
return t.PrepareXFromTop(limit)
|
||||
}
|
||||
|
||||
func (m *manager) WipeStatusFromTimeline(timelineAccountID string, statusID string) error {
|
||||
t := m.getOrCreateTimeline(timelineAccountID)
|
||||
|
||||
return t.Remove(statusID)
|
||||
}
|
||||
|
||||
func (m *manager) WipeStatusFromAllTimelines(statusID string) error {
|
||||
|
||||
errors := []string{}
|
||||
|
||||
m.accountTimelines.Range(func(k interface{}, i interface{}) bool {
|
||||
t, ok := i.(Timeline)
|
||||
if !ok {
|
||||
panic("couldn't parse entry as Timeline, this should never happen so panic")
|
||||
}
|
||||
|
||||
if err := t.Remove(statusID); err != nil {
|
||||
errors = append(errors, err.Error())
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
var err error
|
||||
if len(errors) > 0 {
|
||||
err = fmt.Errorf("one or more errors removing status %s from all timelines: %s", statusID, strings.Join(errors, ";"))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *manager) getOrCreateTimeline(timelineAccountID string) Timeline {
|
||||
var t Timeline
|
||||
i, ok := m.accountTimelines.Load(timelineAccountID)
|
||||
|
@ -334,27 +334,31 @@ func (t *timeline) Remove(statusID string) error {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
// remove the entry from the post index
|
||||
for e := t.postIndex.data.Front(); e != nil; e = e.Next() {
|
||||
entry, ok := e.Value.(*postIndexEntry)
|
||||
if !ok {
|
||||
return errors.New("Remove: could not parse e as a postIndexEntry")
|
||||
}
|
||||
if entry.statusID == statusID {
|
||||
t.postIndex.data.Remove(e)
|
||||
break // bail once we found and removed it
|
||||
if t.postIndex != nil && t.postIndex.data != nil {
|
||||
// remove the entry from the post index
|
||||
for e := t.postIndex.data.Front(); e != nil; e = e.Next() {
|
||||
entry, ok := e.Value.(*postIndexEntry)
|
||||
if !ok {
|
||||
return errors.New("Remove: could not parse e as a postIndexEntry")
|
||||
}
|
||||
if entry.statusID == statusID {
|
||||
t.postIndex.data.Remove(e)
|
||||
break // bail once we found and removed it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove the entry from prepared posts
|
||||
for e := t.preparedPosts.data.Front(); e != nil; e = e.Next() {
|
||||
entry, ok := e.Value.(*preparedPostsEntry)
|
||||
if !ok {
|
||||
return errors.New("Remove: could not parse e as a preparedPostsEntry")
|
||||
}
|
||||
if entry.statusID == statusID {
|
||||
t.preparedPosts.data.Remove(e)
|
||||
break // bail once we found and removed it
|
||||
if t.preparedPosts != nil && t.preparedPosts.data != nil {
|
||||
for e := t.preparedPosts.data.Front(); e != nil; e = e.Next() {
|
||||
entry, ok := e.Value.(*preparedPostsEntry)
|
||||
if !ok {
|
||||
return errors.New("Remove: could not parse e as a preparedPostsEntry")
|
||||
}
|
||||
if entry.statusID == statusID {
|
||||
t.preparedPosts.data.Remove(e)
|
||||
break // bail once we found and removed it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -222,7 +222,7 @@ func (c *converter) ASStatusToStatus(statusable Statusable) (*gtsmodel.Status, e
|
||||
status.APStatusOwnerURI = attributedTo.String()
|
||||
|
||||
statusOwner := >smodel.Account{}
|
||||
if err := c.db.GetWhere([]db.Where{{Key: "uri", Value: attributedTo.String()}}, statusOwner); err != nil {
|
||||
if err := c.db.GetWhere([]db.Where{{Key: "uri", Value: attributedTo.String(), CaseInsensitive: true}}, statusOwner); err != nil {
|
||||
return nil, fmt.Errorf("couldn't get status owner from db: %s", err)
|
||||
}
|
||||
status.AccountID = statusOwner.ID
|
||||
|
Loading…
Reference in New Issue
Block a user