mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-11-02 13:22:24 -06:00
Merge branch 'main' into profile-boosts
This commit is contained in:
commit
90b773ae2a
82 changed files with 2313 additions and 954 deletions
|
|
@ -42,6 +42,7 @@ func (p *Processor) GetTargetAccountBy(
|
|||
// Fetch the target account from db.
|
||||
target, err := getTargetFromDB()
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
err := gtserror.Newf("error getting from db: %w", err)
|
||||
return nil, false, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
|
|
@ -57,6 +58,7 @@ func (p *Processor) GetTargetAccountBy(
|
|||
// Check whether target account is visible to requesting account.
|
||||
visible, err = p.visFilter.AccountVisible(ctx, requester, target)
|
||||
if err != nil {
|
||||
err := gtserror.Newf("error checking visibility: %w", err)
|
||||
return nil, false, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
|
|
@ -128,7 +130,8 @@ func (p *Processor) GetVisibleTargetAccount(
|
|||
return target, nil
|
||||
}
|
||||
|
||||
// GetAPIAccount fetches the appropriate API account model depending on whether requester = target.
|
||||
// GetAPIAccount fetches the appropriate API account
|
||||
// model depending on whether requester = target.
|
||||
func (p *Processor) GetAPIAccount(
|
||||
ctx context.Context,
|
||||
requester *gtsmodel.Account,
|
||||
|
|
@ -148,14 +151,15 @@ func (p *Processor) GetAPIAccount(
|
|||
}
|
||||
|
||||
if err != nil {
|
||||
err := gtserror.Newf("error converting account: %w", err)
|
||||
err := gtserror.Newf("error converting: %w", err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
return apiAcc, nil
|
||||
}
|
||||
|
||||
// GetAPIAccountBlocked fetches the limited "blocked" account model for given target.
|
||||
// GetAPIAccountBlocked fetches the limited
|
||||
// "blocked" account model for given target.
|
||||
func (p *Processor) GetAPIAccountBlocked(
|
||||
ctx context.Context,
|
||||
targetAcc *gtsmodel.Account,
|
||||
|
|
@ -165,7 +169,7 @@ func (p *Processor) GetAPIAccountBlocked(
|
|||
) {
|
||||
apiAccount, err := p.converter.AccountToAPIAccountBlocked(ctx, targetAcc)
|
||||
if err != nil {
|
||||
err = gtserror.Newf("error converting account: %w", err)
|
||||
err := gtserror.Newf("error converting: %w", err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
return apiAccount, nil
|
||||
|
|
@ -182,7 +186,7 @@ func (p *Processor) GetAPIAccountSensitive(
|
|||
) {
|
||||
apiAccount, err := p.converter.AccountToAPIAccountSensitive(ctx, targetAcc)
|
||||
if err != nil {
|
||||
err = gtserror.Newf("error converting account: %w", err)
|
||||
err := gtserror.Newf("error converting: %w", err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
return apiAccount, nil
|
||||
|
|
@ -226,8 +230,7 @@ func (p *Processor) getVisibleAPIAccounts(
|
|||
) []*apimodel.Account {
|
||||
// Start new log entry with
|
||||
// the above calling func's name.
|
||||
l := log.
|
||||
WithContext(ctx).
|
||||
l := log.WithContext(ctx).
|
||||
WithField("caller", log.Caller(calldepth+1))
|
||||
|
||||
// Preallocate slice according to expected length.
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/federation/dereferencing"
|
||||
statusfilter "github.com/superseriousbusiness/gotosocial/internal/filter/status"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/filter/usermute"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/log"
|
||||
|
|
@ -50,6 +51,7 @@ func (p *Processor) GetTargetStatusBy(
|
|||
// Fetch the target status from db.
|
||||
target, err := getTargetFromDB()
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
err := gtserror.Newf("error getting from db: %w", err)
|
||||
return nil, false, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
|
|
@ -65,6 +67,7 @@ func (p *Processor) GetTargetStatusBy(
|
|||
// Check whether target status is visible to requesting account.
|
||||
visible, err = p.visFilter.StatusVisible(ctx, requester, target)
|
||||
if err != nil {
|
||||
err := gtserror.Newf("error checking visibility: %w", err)
|
||||
return nil, false, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
|
|
@ -174,14 +177,83 @@ func (p *Processor) GetAPIStatus(
|
|||
apiStatus *apimodel.Status,
|
||||
errWithCode gtserror.WithCode,
|
||||
) {
|
||||
apiStatus, err := p.converter.StatusToAPIStatus(ctx, target, requester, statusfilter.FilterContextNone, nil, nil)
|
||||
apiStatus, err := p.converter.StatusToAPIStatus(ctx,
|
||||
target,
|
||||
requester,
|
||||
statusfilter.FilterContextNone,
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
err = gtserror.Newf("error converting status: %w", err)
|
||||
err := gtserror.Newf("error converting: %w", err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
return apiStatus, nil
|
||||
}
|
||||
|
||||
// GetVisibleAPIStatuses converts a slice of statuses to API
|
||||
// model statuses, filtering according to visibility to requester
|
||||
// along with given filter context, filters and user mutes.
|
||||
//
|
||||
// Please note that all errors will be logged at ERROR level,
|
||||
// but will not be returned. Callers are likely to run into
|
||||
// show-stopping errors in the lead-up to this function.
|
||||
func (p *Processor) GetVisibleAPIStatuses(
|
||||
ctx context.Context,
|
||||
requester *gtsmodel.Account,
|
||||
statuses []*gtsmodel.Status,
|
||||
filterContext statusfilter.FilterContext,
|
||||
filters []*gtsmodel.Filter,
|
||||
userMutes []*gtsmodel.UserMute,
|
||||
) []apimodel.Status {
|
||||
|
||||
// Start new log entry with
|
||||
// the calling function name
|
||||
// as a field in each entry.
|
||||
l := log.WithContext(ctx).
|
||||
WithField("caller", log.Caller(3))
|
||||
|
||||
// Compile mutes to useable user mutes for type converter.
|
||||
compUserMutes := usermute.NewCompiledUserMuteList(userMutes)
|
||||
|
||||
// Iterate filtered statuses for conversion to API model.
|
||||
apiStatuses := make([]apimodel.Status, 0, len(statuses))
|
||||
for _, status := range statuses {
|
||||
|
||||
// Check whether status is visible to requester.
|
||||
visible, err := p.visFilter.StatusVisible(ctx,
|
||||
requester,
|
||||
status,
|
||||
)
|
||||
if err != nil {
|
||||
l.Errorf("error checking visibility: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !visible {
|
||||
continue
|
||||
}
|
||||
|
||||
// Convert to API status, taking mute / filter into account.
|
||||
apiStatus, err := p.converter.StatusToAPIStatus(ctx,
|
||||
status,
|
||||
requester,
|
||||
filterContext,
|
||||
filters,
|
||||
compUserMutes,
|
||||
)
|
||||
if err != nil && !errors.Is(err, statusfilter.ErrHideStatus) {
|
||||
l.Errorf("error converting: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Append converted status to return slice.
|
||||
apiStatuses = append(apiStatuses, *apiStatus)
|
||||
}
|
||||
|
||||
return apiStatuses
|
||||
}
|
||||
|
||||
// InvalidateTimelinedStatus is a shortcut function for invalidating the cached
|
||||
// representation one status in the home timeline and all list timelines of the
|
||||
// given accountID. It should only be called in cases where a status update
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ func NewProcessor(
|
|||
processor.tags = tags.New(state, converter)
|
||||
processor.timeline = timeline.New(state, converter, visFilter)
|
||||
processor.search = search.New(state, federator, converter, visFilter)
|
||||
processor.status = status.New(state, &common, &processor.polls, federator, converter, visFilter, intFilter, parseMentionFunc)
|
||||
processor.status = status.New(state, &common, &processor.polls, &processor.interactionRequests, federator, converter, visFilter, intFilter, parseMentionFunc)
|
||||
processor.user = user.New(state, converter, oauthServer, emailSender)
|
||||
|
||||
// The advanced migrations processor sequences advanced migrations from all other processors.
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import (
|
|||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/messages"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
)
|
||||
|
||||
// BoostCreate processes the boost/reblog of target
|
||||
|
|
@ -138,6 +139,23 @@ func (p *Processor) BoostCreate(
|
|||
Target: target.Account,
|
||||
})
|
||||
|
||||
// If the boost target status replies to a status
|
||||
// that we own, and has a pending interaction
|
||||
// request, use the boost as an implicit accept.
|
||||
implicitlyAccepted, errWithCode := p.implicitlyAccept(ctx,
|
||||
requester, target,
|
||||
)
|
||||
if errWithCode != nil {
|
||||
return nil, errWithCode
|
||||
}
|
||||
|
||||
// If we ended up implicitly accepting, mark the
|
||||
// target status as no longer pending approval so
|
||||
// it's serialized properly via the API.
|
||||
if implicitlyAccepted {
|
||||
target.PendingApproval = util.Ptr(false)
|
||||
}
|
||||
|
||||
return p.c.GetAPIStatus(ctx, requester, boost)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import (
|
|||
|
||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||
statusfilter "github.com/superseriousbusiness/gotosocial/internal/filter/status"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/filter/usermute"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtscontext"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
|
|
@ -308,22 +307,7 @@ func (p *Processor) ContextGet(
|
|||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
convert := func(
|
||||
ctx context.Context,
|
||||
status *gtsmodel.Status,
|
||||
requestingAccount *gtsmodel.Account,
|
||||
) (*apimodel.Status, error) {
|
||||
return p.converter.StatusToAPIStatus(
|
||||
ctx,
|
||||
status,
|
||||
requestingAccount,
|
||||
statusfilter.FilterContextThread,
|
||||
filters,
|
||||
usermute.NewCompiledUserMuteList(mutes),
|
||||
)
|
||||
}
|
||||
|
||||
// Retrieve the thread context.
|
||||
// Retrieve the full thread context.
|
||||
threadContext, errWithCode := p.contextGet(
|
||||
ctx,
|
||||
requester,
|
||||
|
|
@ -333,34 +317,27 @@ func (p *Processor) ContextGet(
|
|||
return nil, errWithCode
|
||||
}
|
||||
|
||||
apiContext := &apimodel.ThreadContext{
|
||||
Ancestors: make([]apimodel.Status, 0, len(threadContext.ancestors)),
|
||||
Descendants: make([]apimodel.Status, 0, len(threadContext.descendants)),
|
||||
}
|
||||
var apiContext apimodel.ThreadContext
|
||||
|
||||
// Convert ancestors + filter
|
||||
// out ones that aren't visible.
|
||||
for _, status := range threadContext.ancestors {
|
||||
if v, err := p.visFilter.StatusVisible(ctx, requester, status); err == nil && v {
|
||||
status, err := convert(ctx, status, requester)
|
||||
if err == nil {
|
||||
apiContext.Ancestors = append(apiContext.Ancestors, *status)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Convert and filter the thread context ancestors.
|
||||
apiContext.Ancestors = p.c.GetVisibleAPIStatuses(ctx,
|
||||
requester,
|
||||
threadContext.ancestors,
|
||||
statusfilter.FilterContextThread,
|
||||
filters,
|
||||
mutes,
|
||||
)
|
||||
|
||||
// Convert descendants + filter
|
||||
// out ones that aren't visible.
|
||||
for _, status := range threadContext.descendants {
|
||||
if v, err := p.visFilter.StatusVisible(ctx, requester, status); err == nil && v {
|
||||
status, err := convert(ctx, status, requester)
|
||||
if err == nil {
|
||||
apiContext.Descendants = append(apiContext.Descendants, *status)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Convert and filter the thread context descendants
|
||||
apiContext.Descendants = p.c.GetVisibleAPIStatuses(ctx,
|
||||
requester,
|
||||
threadContext.descendants,
|
||||
statusfilter.FilterContextThread,
|
||||
filters,
|
||||
mutes,
|
||||
)
|
||||
|
||||
return apiContext, nil
|
||||
return &apiContext, nil
|
||||
}
|
||||
|
||||
// WebContextGet is like ContextGet, but is explicitly
|
||||
|
|
|
|||
|
|
@ -164,6 +164,23 @@ func (p *Processor) Create(
|
|||
}
|
||||
}
|
||||
|
||||
// If the new status replies to a status that
|
||||
// replies to us, use our reply as an implicit
|
||||
// accept of any pending interaction.
|
||||
implicitlyAccepted, errWithCode := p.implicitlyAccept(ctx,
|
||||
requester, status,
|
||||
)
|
||||
if errWithCode != nil {
|
||||
return nil, errWithCode
|
||||
}
|
||||
|
||||
// If we ended up implicitly accepting, mark the
|
||||
// replied-to status as no longer pending approval
|
||||
// so it's serialized properly via the API.
|
||||
if implicitlyAccepted {
|
||||
status.InReplyTo.PendingApproval = util.Ptr(false)
|
||||
}
|
||||
|
||||
return p.c.GetAPIStatus(ctx, requester, status)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import (
|
|||
"github.com/superseriousbusiness/gotosocial/internal/log"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/messages"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/uris"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
)
|
||||
|
||||
func (p *Processor) getFaveableStatus(
|
||||
|
|
@ -138,8 +139,6 @@ func (p *Processor) FaveCreate(
|
|||
pendingApproval = false
|
||||
}
|
||||
|
||||
status.PendingApproval = &pendingApproval
|
||||
|
||||
// Create a new fave, marking it
|
||||
// as pending approval if necessary.
|
||||
faveID := id.NewULID()
|
||||
|
|
@ -157,7 +156,7 @@ func (p *Processor) FaveCreate(
|
|||
}
|
||||
|
||||
if err := p.state.DB.PutStatusFave(ctx, gtsFave); err != nil {
|
||||
err = fmt.Errorf("FaveCreate: error putting fave in database: %w", err)
|
||||
err = gtserror.Newf("db error putting fave: %w", err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
|
|
@ -170,6 +169,23 @@ func (p *Processor) FaveCreate(
|
|||
Target: status.Account,
|
||||
})
|
||||
|
||||
// If the fave target status replies to a status
|
||||
// that we own, and has a pending interaction
|
||||
// request, use the fave as an implicit accept.
|
||||
implicitlyAccepted, errWithCode := p.implicitlyAccept(ctx,
|
||||
requester, status,
|
||||
)
|
||||
if errWithCode != nil {
|
||||
return nil, errWithCode
|
||||
}
|
||||
|
||||
// If we ended up implicitly accepting, mark the
|
||||
// target status as no longer pending approval so
|
||||
// it's serialized properly via the API.
|
||||
if implicitlyAccepted {
|
||||
status.PendingApproval = util.Ptr(false)
|
||||
}
|
||||
|
||||
return p.c.GetAPIStatus(ctx, requester, status)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"github.com/superseriousbusiness/gotosocial/internal/filter/visibility"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/processing/common"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/processing/interactionrequests"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/processing/polls"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/state"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/text"
|
||||
|
|
@ -42,7 +43,8 @@ type Processor struct {
|
|||
parseMention gtsmodel.ParseMentionFunc
|
||||
|
||||
// other processors
|
||||
polls *polls.Processor
|
||||
polls *polls.Processor
|
||||
intReqs *interactionrequests.Processor
|
||||
}
|
||||
|
||||
// New returns a new status processor.
|
||||
|
|
@ -50,6 +52,7 @@ func New(
|
|||
state *state.State,
|
||||
common *common.Processor,
|
||||
polls *polls.Processor,
|
||||
intReqs *interactionrequests.Processor,
|
||||
federator *federation.Federator,
|
||||
converter *typeutils.Converter,
|
||||
visFilter *visibility.Filter,
|
||||
|
|
@ -66,5 +69,6 @@ func New(
|
|||
formatter: text.NewFormatter(state.DB),
|
||||
parseMention: parseMention,
|
||||
polls: polls,
|
||||
intReqs: intReqs,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import (
|
|||
"github.com/superseriousbusiness/gotosocial/internal/media"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/processing"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/processing/common"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/processing/interactionrequests"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/processing/polls"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/processing/status"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/state"
|
||||
|
|
@ -100,11 +101,13 @@ func (suite *StatusStandardTestSuite) SetupTest() {
|
|||
|
||||
common := common.New(&suite.state, suite.mediaManager, suite.typeConverter, suite.federator, visFilter)
|
||||
polls := polls.New(&common, &suite.state, suite.typeConverter)
|
||||
intReqs := interactionrequests.New(&common, &suite.state, suite.typeConverter)
|
||||
|
||||
suite.status = status.New(
|
||||
&suite.state,
|
||||
&common,
|
||||
&polls,
|
||||
&intReqs,
|
||||
suite.federator,
|
||||
suite.typeConverter,
|
||||
visFilter,
|
||||
|
|
|
|||
72
internal/processing/status/util.go
Normal file
72
internal/processing/status/util.go
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
// GoToSocial
|
||||
// Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package status
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
)
|
||||
|
||||
func (p *Processor) implicitlyAccept(
|
||||
ctx context.Context,
|
||||
requester *gtsmodel.Account,
|
||||
status *gtsmodel.Status,
|
||||
) (bool, gtserror.WithCode) {
|
||||
if status.InReplyToAccountID != requester.ID {
|
||||
// Status doesn't reply to us,
|
||||
// we can't accept on behalf
|
||||
// of someone else.
|
||||
return false, nil
|
||||
}
|
||||
|
||||
targetPendingApproval := util.PtrOrValue(status.PendingApproval, false)
|
||||
if !targetPendingApproval {
|
||||
// Status isn't pending approval,
|
||||
// nothing to implicitly accept.
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Status is pending approval,
|
||||
// check for an interaction request.
|
||||
intReq, err := p.state.DB.GetInteractionRequestByInteractionURI(ctx, status.URI)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
// Something's gone wrong.
|
||||
err := gtserror.Newf("db error getting interaction request for %s: %w", status.URI, err)
|
||||
return false, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
// No interaction request present
|
||||
// for this status. Race condition?
|
||||
if intReq == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Accept the interaction.
|
||||
if _, errWithCode := p.intReqs.Accept(ctx,
|
||||
requester, intReq.ID,
|
||||
); errWithCode != nil {
|
||||
return false, errWithCode
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
|
@ -384,8 +384,9 @@ func (s *Surface) timelineStatus(
|
|||
) (bool, error) {
|
||||
|
||||
// Ingest status into given timeline using provided function.
|
||||
if inserted, err := ingest(ctx, timelineID, status); err != nil {
|
||||
err = gtserror.Newf("error ingesting status %s: %w", status.ID, err)
|
||||
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.
|
||||
|
|
@ -400,15 +401,19 @@ func (s *Surface) timelineStatus(
|
|||
filters,
|
||||
mutes,
|
||||
)
|
||||
if err != nil {
|
||||
err = gtserror.Newf("error converting status %s to frontend representation: %w", status.ID, err)
|
||||
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
|
||||
}
|
||||
|
||||
// The status was inserted so stream it to the user.
|
||||
s.Stream.Update(ctx, account, apiStatus, streamType)
|
||||
if apiStatus != nil {
|
||||
// The status was inserted so stream it to the user.
|
||||
s.Stream.Update(ctx, account, apiStatus, streamType)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
// Status was hidden.
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// timelineAndNotifyStatusForTagFollowers inserts the status into the
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue