|
|
|
|
@ -21,6 +21,7 @@ import (
|
|
|
|
|
"context" |
|
|
|
|
"errors" |
|
|
|
|
|
|
|
|
|
timeline2 "github.com/superseriousbusiness/gotosocial/internal/cache/timeline" |
|
|
|
|
statusfilter "github.com/superseriousbusiness/gotosocial/internal/filter/status" |
|
|
|
|
"github.com/superseriousbusiness/gotosocial/internal/filter/usermute" |
|
|
|
|
"github.com/superseriousbusiness/gotosocial/internal/gtscontext" |
|
|
|
|
@ -28,7 +29,6 @@ import (
|
|
|
|
|
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" |
|
|
|
|
"github.com/superseriousbusiness/gotosocial/internal/log" |
|
|
|
|
"github.com/superseriousbusiness/gotosocial/internal/stream" |
|
|
|
|
"github.com/superseriousbusiness/gotosocial/internal/timeline" |
|
|
|
|
"github.com/superseriousbusiness/gotosocial/internal/util" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
@ -161,21 +161,16 @@ func (s *Surface) timelineAndNotifyStatusForFollowers(
|
|
|
|
|
|
|
|
|
|
// Add status to home timeline for owner of
|
|
|
|
|
// this follow (origin account), if applicable.
|
|
|
|
|
homeTimelined, err = s.timelineStatus(ctx, |
|
|
|
|
s.State.Timelines.Home.IngestOne, |
|
|
|
|
follow.AccountID, // home timelines are keyed by account ID
|
|
|
|
|
if homeTimelined := s.timelineStatus(ctx, |
|
|
|
|
s.State.Caches.Timelines.Home.MustGet(follow.AccountID), |
|
|
|
|
follow.Account, |
|
|
|
|
status, |
|
|
|
|
stream.TimelineHome, |
|
|
|
|
statusfilter.FilterContextHome, |
|
|
|
|
filters, |
|
|
|
|
mutes, |
|
|
|
|
) |
|
|
|
|
if err != nil { |
|
|
|
|
log.Errorf(ctx, "error home timelining status: %v", err) |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
); homeTimelined { |
|
|
|
|
|
|
|
|
|
if homeTimelined { |
|
|
|
|
// If hometimelined, add to list of returned account IDs.
|
|
|
|
|
homeTimelinedAccountIDs = append(homeTimelinedAccountIDs, follow.AccountID) |
|
|
|
|
} |
|
|
|
|
@ -261,21 +256,16 @@ func (s *Surface) listTimelineStatusForFollow(
|
|
|
|
|
exclusive = exclusive || *list.Exclusive |
|
|
|
|
|
|
|
|
|
// At this point we are certain this status
|
|
|
|
|
// should be included in the timeline of the
|
|
|
|
|
// list that this list entry belongs to.
|
|
|
|
|
listTimelined, err := s.timelineStatus(ctx, |
|
|
|
|
s.State.Timelines.List.IngestOne, |
|
|
|
|
list.ID, // list timelines are keyed by list ID
|
|
|
|
|
// should be included in timeline of this list.
|
|
|
|
|
listTimelined := s.timelineStatus(ctx, |
|
|
|
|
s.State.Caches.Timelines.List.MustGet(list.ID), |
|
|
|
|
follow.Account, |
|
|
|
|
status, |
|
|
|
|
stream.TimelineList+":"+list.ID, // key streamType to this specific list
|
|
|
|
|
statusfilter.FilterContextHome, |
|
|
|
|
filters, |
|
|
|
|
mutes, |
|
|
|
|
) |
|
|
|
|
if err != nil { |
|
|
|
|
log.Errorf(ctx, "error adding status to list timeline: %v", err) |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Update flag based on if timelined.
|
|
|
|
|
timelined = timelined || listTimelined |
|
|
|
|
@ -371,48 +361,46 @@ func (s *Surface) listEligible(
|
|
|
|
|
//
|
|
|
|
|
// If the status was inserted into the timeline, true will be returned
|
|
|
|
|
// + it will also be streamed to the user using the given streamType.
|
|
|
|
|
|
|
|
|
|
// timelineStatus ...
|
|
|
|
|
func (s *Surface) timelineStatus( |
|
|
|
|
ctx context.Context, |
|
|
|
|
ingest func(context.Context, string, timeline.Timelineable) (bool, error), |
|
|
|
|
timelineID string, |
|
|
|
|
timeline *timeline2.StatusTimeline, |
|
|
|
|
account *gtsmodel.Account, |
|
|
|
|
status *gtsmodel.Status, |
|
|
|
|
streamType string, |
|
|
|
|
filterCtx statusfilter.FilterContext, |
|
|
|
|
filters []*gtsmodel.Filter, |
|
|
|
|
mutes *usermute.CompiledUserMuteList, |
|
|
|
|
) (bool, error) { |
|
|
|
|
|
|
|
|
|
// Ingest status into given timeline using provided function.
|
|
|
|
|
if inserted, err := ingest(ctx, timelineID, status); err != nil && |
|
|
|
|
!errors.Is(err, statusfilter.ErrHideStatus) { |
|
|
|
|
err := gtserror.Newf("error ingesting status %s: %w", status.ID, err) |
|
|
|
|
return false, err |
|
|
|
|
} else if !inserted { |
|
|
|
|
// Nothing more to do.
|
|
|
|
|
return false, nil |
|
|
|
|
} |
|
|
|
|
) bool { |
|
|
|
|
|
|
|
|
|
// Convert updated database model to frontend model.
|
|
|
|
|
apiStatus, err := s.Converter.StatusToAPIStatus(ctx, |
|
|
|
|
// Attempt to convert status to frontend API representation,
|
|
|
|
|
// this will check whether status is filtered / muted.
|
|
|
|
|
apiModel, err := s.Converter.StatusToAPIStatus(ctx, |
|
|
|
|
status, |
|
|
|
|
account, |
|
|
|
|
statusfilter.FilterContextHome, |
|
|
|
|
filterCtx, |
|
|
|
|
filters, |
|
|
|
|
mutes, |
|
|
|
|
) |
|
|
|
|
if err != nil && !errors.Is(err, statusfilter.ErrHideStatus) { |
|
|
|
|
err := gtserror.Newf("error converting status %s to frontend representation: %w", status.ID, err) |
|
|
|
|
return true, err |
|
|
|
|
log.Error(ctx, "error converting status %s to frontend: %v", status.URI, err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if apiStatus != nil { |
|
|
|
|
// The status was inserted so stream it to the user.
|
|
|
|
|
s.Stream.Update(ctx, account, apiStatus, streamType) |
|
|
|
|
return true, nil |
|
|
|
|
// Insert status to timeline cache regardless of
|
|
|
|
|
// if API model was successfully prepared or not.
|
|
|
|
|
timeline.InsertOne(status, apiModel) |
|
|
|
|
|
|
|
|
|
if apiModel != nil { |
|
|
|
|
// Only send the status to user's stream if not
|
|
|
|
|
// filtered / muted, i.e. successfully prepared model.
|
|
|
|
|
s.Stream.Update(ctx, account, apiModel, streamType) |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Status was hidden.
|
|
|
|
|
return false, nil |
|
|
|
|
// Status was
|
|
|
|
|
// filtered / muted.
|
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// timelineAndNotifyStatusForTagFollowers inserts the status into the
|
|
|
|
|
@ -443,22 +431,15 @@ func (s *Surface) timelineAndNotifyStatusForTagFollowers(
|
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if _, err := s.timelineStatus(ctx, |
|
|
|
|
s.State.Timelines.Home.IngestOne, |
|
|
|
|
tagFollowerAccount.ID, // home timelines are keyed by account ID
|
|
|
|
|
_ = s.timelineStatus(ctx, |
|
|
|
|
s.State.Caches.Timelines.Home.MustGet(tagFollowerAccount.ID), |
|
|
|
|
tagFollowerAccount, |
|
|
|
|
status, |
|
|
|
|
stream.TimelineHome, |
|
|
|
|
statusfilter.FilterContextHome, |
|
|
|
|
filters, |
|
|
|
|
mutes, |
|
|
|
|
); err != nil { |
|
|
|
|
errs.Appendf( |
|
|
|
|
"error inserting status %s into home timeline for account %s: %w", |
|
|
|
|
status.ID, |
|
|
|
|
tagFollowerAccount.ID, |
|
|
|
|
err, |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return errs.Combine() |
|
|
|
|
|