mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-10-29 06:02:26 -05:00
[chore] move status filtering from type converter (#4306)
This finalizes the moving status filtering out of the type converter, and into its own `./internal/filter/` subpkg :) Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4306 Co-authored-by: kim <grufwub@gmail.com> Co-committed-by: kim <grufwub@gmail.com>
This commit is contained in:
parent
79914bdbf7
commit
66e1ec14aa
38 changed files with 565 additions and 846 deletions
|
|
@ -43,6 +43,7 @@ import (
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/spam"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/spam"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/filter/status"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/httpclient"
|
"code.superseriousbusiness.org/gotosocial/internal/httpclient"
|
||||||
|
|
@ -271,6 +272,7 @@ var Start action.GTSAction = func(ctx context.Context) error {
|
||||||
visFilter := visibility.NewFilter(state)
|
visFilter := visibility.NewFilter(state)
|
||||||
muteFilter := mutes.NewFilter(state)
|
muteFilter := mutes.NewFilter(state)
|
||||||
intFilter := interaction.NewFilter(state)
|
intFilter := interaction.NewFilter(state)
|
||||||
|
statusFilter := status.NewFilter(state)
|
||||||
spamFilter := spam.NewFilter(state)
|
spamFilter := spam.NewFilter(state)
|
||||||
federatingDB := federatingdb.New(state, typeConverter, visFilter, intFilter, spamFilter)
|
federatingDB := federatingdb.New(state, typeConverter, visFilter, intFilter, spamFilter)
|
||||||
transportController := transport.NewController(state, federatingDB, client)
|
transportController := transport.NewController(state, federatingDB, client)
|
||||||
|
|
@ -352,6 +354,7 @@ var Start action.GTSAction = func(ctx context.Context) error {
|
||||||
visFilter,
|
visFilter,
|
||||||
muteFilter,
|
muteFilter,
|
||||||
intFilter,
|
intFilter,
|
||||||
|
statusFilter,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Schedule background cleaning tasks.
|
// Schedule background cleaning tasks.
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ import (
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/config"
|
"code.superseriousbusiness.org/gotosocial/internal/config"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/filter/status"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/processing"
|
"code.superseriousbusiness.org/gotosocial/internal/processing"
|
||||||
|
|
@ -101,6 +102,7 @@ func (suite *WebfingerGetTestSuite) funkifyAccountDomain(host string, accountDom
|
||||||
visibility.NewFilter(&suite.state),
|
visibility.NewFilter(&suite.state),
|
||||||
mutes.NewFilter(&suite.state),
|
mutes.NewFilter(&suite.state),
|
||||||
interaction.NewFilter(&suite.state),
|
interaction.NewFilter(&suite.state),
|
||||||
|
status.NewFilter(&suite.state),
|
||||||
)
|
)
|
||||||
|
|
||||||
suite.webfingerModule = webfinger.New(suite.processor)
|
suite.webfingerModule = webfinger.New(suite.processor)
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
|
|
||||||
apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
|
apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/cache"
|
"code.superseriousbusiness.org/gotosocial/internal/cache"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/gtscontext"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||||
)
|
)
|
||||||
|
|
@ -159,6 +160,31 @@ func (f *Filter) getStatusFilterResults(
|
||||||
return results, nil
|
return results, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if status is boost.
|
||||||
|
if status.BoostOfID != "" {
|
||||||
|
if status.BoostOf == nil {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// Ensure original status is loaded on boost.
|
||||||
|
status.BoostOf, err = f.state.DB.GetStatusByID(
|
||||||
|
gtscontext.SetBarebones(ctx),
|
||||||
|
status.BoostOfID,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return results, gtserror.Newf("error getting boosted status of %s: %w", status.URI, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// From here look at details
|
||||||
|
// for original boosted status.
|
||||||
|
status = status.BoostOf
|
||||||
|
}
|
||||||
|
|
||||||
|
// For proper status filtering we need all fields populated.
|
||||||
|
if err := f.state.DB.PopulateStatus(ctx, status); err != nil {
|
||||||
|
return results, gtserror.Newf("error populating status: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Get the string fields status is
|
// Get the string fields status is
|
||||||
// filterable on for keyword matching.
|
// filterable on for keyword matching.
|
||||||
fields := getFilterableFields(status)
|
fields := getFilterableFields(status)
|
||||||
|
|
@ -169,11 +195,6 @@ func (f *Filter) getStatusFilterResults(
|
||||||
return results, gtserror.Newf("error getting account filters: %w", err)
|
return results, gtserror.Newf("error getting account filters: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// For proper status filtering we need all fields populated.
|
|
||||||
if err := f.state.DB.PopulateStatus(ctx, status); err != nil {
|
|
||||||
return results, gtserror.Newf("error populating status: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate result for each filter.
|
// Generate result for each filter.
|
||||||
for _, filter := range filters {
|
for _, filter := range filters {
|
||||||
|
|
||||||
|
|
|
||||||
201
internal/filter/status/status_test.go
Normal file
201
internal/filter/status/status_test.go
Normal file
|
|
@ -0,0 +1,201 @@
|
||||||
|
// 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_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/filter/status"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/id"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/state"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/typeutils"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/testrig"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StatusFilterTestSuite struct {
|
||||||
|
suite.Suite
|
||||||
|
|
||||||
|
state state.State
|
||||||
|
filter *status.Filter
|
||||||
|
converter *typeutils.Converter
|
||||||
|
|
||||||
|
testAccounts map[string]*gtsmodel.Account
|
||||||
|
testFilters map[string]*gtsmodel.Filter
|
||||||
|
testStatuses map[string]*gtsmodel.Status
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *StatusFilterTestSuite) SetupTest() {
|
||||||
|
suite.state.Caches.Init()
|
||||||
|
|
||||||
|
testrig.InitTestConfig()
|
||||||
|
testrig.InitTestLog()
|
||||||
|
|
||||||
|
db := testrig.NewTestDB(&suite.state)
|
||||||
|
suite.state.DB = db
|
||||||
|
|
||||||
|
suite.filter = status.NewFilter(&suite.state)
|
||||||
|
|
||||||
|
suite.converter = typeutils.NewConverter(&suite.state)
|
||||||
|
|
||||||
|
suite.testAccounts = testrig.NewTestAccounts()
|
||||||
|
suite.testFilters = testrig.NewTestFilters()
|
||||||
|
suite.testStatuses = testrig.NewTestStatuses()
|
||||||
|
|
||||||
|
testrig.StandardDBSetup(suite.state.DB, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *StatusFilterTestSuite) TearDownTest() {
|
||||||
|
testrig.StandardDBTeardown(suite.state.DB)
|
||||||
|
testrig.StopWorkers(&suite.state)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *StatusFilterTestSuite) TestHideFilteredStatus() {
|
||||||
|
filtered, hide, err := suite.testFilterStatus(gtsmodel.FilterActionHide, false)
|
||||||
|
suite.NoError(err)
|
||||||
|
suite.True(hide)
|
||||||
|
suite.Empty(filtered)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *StatusFilterTestSuite) TestWarnFilteredStatus() {
|
||||||
|
filtered, hide, err := suite.testFilterStatus(gtsmodel.FilterActionWarn, false)
|
||||||
|
suite.NoError(err)
|
||||||
|
suite.False(hide)
|
||||||
|
suite.NotEmpty(filtered)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *StatusFilterTestSuite) TestHideFilteredBoost() {
|
||||||
|
filtered, hide, err := suite.testFilterStatus(gtsmodel.FilterActionHide, true)
|
||||||
|
suite.NoError(err)
|
||||||
|
suite.True(hide)
|
||||||
|
suite.Empty(filtered)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *StatusFilterTestSuite) TestWarnFilteredBoost() {
|
||||||
|
filtered, hide, err := suite.testFilterStatus(gtsmodel.FilterActionWarn, true)
|
||||||
|
suite.NoError(err)
|
||||||
|
suite.False(hide)
|
||||||
|
suite.NotEmpty(filtered)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *StatusFilterTestSuite) TestHashtagWholewordStatusFiltered() {
|
||||||
|
suite.testFilteredStatusWithHashtag(true, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *StatusFilterTestSuite) TestHashtagWholewordBoostFiltered() {
|
||||||
|
suite.testFilteredStatusWithHashtag(true, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *StatusFilterTestSuite) TestHashtagAnywhereStatusFiltered() {
|
||||||
|
suite.testFilteredStatusWithHashtag(false, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *StatusFilterTestSuite) TestHashtagAnywhereBoostFiltered() {
|
||||||
|
suite.testFilteredStatusWithHashtag(false, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *StatusFilterTestSuite) testFilterStatus(action gtsmodel.FilterAction, boost bool) ([]apimodel.FilterResult, bool, error) {
|
||||||
|
ctx := suite.T().Context()
|
||||||
|
|
||||||
|
status := suite.testStatuses["admin_account_status_1"]
|
||||||
|
status.Content += " fnord"
|
||||||
|
status.Text += " fnord"
|
||||||
|
|
||||||
|
if boost {
|
||||||
|
// Modify a fixture boost into a boost of the above status.
|
||||||
|
boost := suite.testStatuses["admin_account_status_4"]
|
||||||
|
boost.BoostOf = status
|
||||||
|
boost.BoostOfID = status.ID
|
||||||
|
status = boost
|
||||||
|
}
|
||||||
|
|
||||||
|
requester := suite.testAccounts["local_account_1"]
|
||||||
|
|
||||||
|
filter := suite.testFilters["local_account_1_filter_1"]
|
||||||
|
filter.Action = action
|
||||||
|
|
||||||
|
err := suite.state.DB.UpdateFilter(ctx, filter, "action")
|
||||||
|
suite.NoError(err)
|
||||||
|
|
||||||
|
return suite.filter.StatusFilterResultsInContext(ctx,
|
||||||
|
requester,
|
||||||
|
status,
|
||||||
|
gtsmodel.FilterContextHome,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *StatusFilterTestSuite) testFilteredStatusWithHashtag(wholeword, boost bool) {
|
||||||
|
ctx := suite.T().Context()
|
||||||
|
|
||||||
|
status := new(gtsmodel.Status)
|
||||||
|
*status = *suite.testStatuses["admin_account_status_1"]
|
||||||
|
status.Content = `<p>doggo doggin' it</p><p><a href="https://example.test/tags/dogsofmastodon" class="mention hashtag" rel="tag nofollow noreferrer noopener" target="_blank">#<span>dogsofmastodon</span></a></p>`
|
||||||
|
|
||||||
|
if boost {
|
||||||
|
boost, err := suite.converter.StatusToBoost(
|
||||||
|
suite.T().Context(),
|
||||||
|
status,
|
||||||
|
suite.testAccounts["admin_account"],
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
suite.NoError(err)
|
||||||
|
status = boost
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
requester := suite.testAccounts["local_account_1"]
|
||||||
|
|
||||||
|
filter := >smodel.Filter{
|
||||||
|
ID: id.NewULID(),
|
||||||
|
Title: id.NewULID(),
|
||||||
|
AccountID: requester.ID,
|
||||||
|
Action: gtsmodel.FilterActionWarn,
|
||||||
|
Contexts: gtsmodel.FilterContexts(gtsmodel.FilterContextHome),
|
||||||
|
}
|
||||||
|
|
||||||
|
filterKeyword := >smodel.FilterKeyword{
|
||||||
|
ID: id.NewULID(),
|
||||||
|
FilterID: filter.ID,
|
||||||
|
Keyword: "#dogsofmastodon",
|
||||||
|
WholeWord: &wholeword,
|
||||||
|
}
|
||||||
|
|
||||||
|
filter.KeywordIDs = []string{filterKeyword.ID}
|
||||||
|
|
||||||
|
err = suite.state.DB.PutFilterKeyword(ctx, filterKeyword)
|
||||||
|
suite.NoError(err)
|
||||||
|
|
||||||
|
err = suite.state.DB.PutFilter(ctx, filter)
|
||||||
|
suite.NoError(err)
|
||||||
|
|
||||||
|
filtered, hide, err := suite.filter.StatusFilterResultsInContext(ctx,
|
||||||
|
requester,
|
||||||
|
status,
|
||||||
|
gtsmodel.FilterContextHome,
|
||||||
|
)
|
||||||
|
suite.NoError(err)
|
||||||
|
suite.False(hide)
|
||||||
|
suite.NotEmpty(filtered)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStatusFilterTestSuite(t *testing.T) {
|
||||||
|
suite.Run(t, new(StatusFilterTestSuite))
|
||||||
|
}
|
||||||
|
|
@ -19,6 +19,7 @@ package account
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/federation"
|
"code.superseriousbusiness.org/gotosocial/internal/federation"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/filter/status"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/media"
|
"code.superseriousbusiness.org/gotosocial/internal/media"
|
||||||
|
|
@ -39,6 +40,7 @@ type Processor struct {
|
||||||
converter *typeutils.Converter
|
converter *typeutils.Converter
|
||||||
mediaManager *media.Manager
|
mediaManager *media.Manager
|
||||||
visFilter *visibility.Filter
|
visFilter *visibility.Filter
|
||||||
|
statusFilter *status.Filter
|
||||||
formatter *text.Formatter
|
formatter *text.Formatter
|
||||||
federator *federation.Federator
|
federator *federation.Federator
|
||||||
parseMention gtsmodel.ParseMentionFunc
|
parseMention gtsmodel.ParseMentionFunc
|
||||||
|
|
@ -53,6 +55,7 @@ func New(
|
||||||
mediaManager *media.Manager,
|
mediaManager *media.Manager,
|
||||||
federator *federation.Federator,
|
federator *federation.Federator,
|
||||||
visFilter *visibility.Filter,
|
visFilter *visibility.Filter,
|
||||||
|
statusFilter *status.Filter,
|
||||||
parseMention gtsmodel.ParseMentionFunc,
|
parseMention gtsmodel.ParseMentionFunc,
|
||||||
) Processor {
|
) Processor {
|
||||||
return Processor{
|
return Processor{
|
||||||
|
|
@ -61,6 +64,7 @@ func New(
|
||||||
converter: converter,
|
converter: converter,
|
||||||
mediaManager: mediaManager,
|
mediaManager: mediaManager,
|
||||||
visFilter: visFilter,
|
visFilter: visFilter,
|
||||||
|
statusFilter: statusFilter,
|
||||||
formatter: text.NewFormatter(state.DB),
|
formatter: text.NewFormatter(state.DB),
|
||||||
federator: federator,
|
federator: federator,
|
||||||
parseMention: parseMention,
|
parseMention: parseMention,
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/email"
|
"code.superseriousbusiness.org/gotosocial/internal/email"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/federation"
|
"code.superseriousbusiness.org/gotosocial/internal/federation"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/filter/status"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/media"
|
"code.superseriousbusiness.org/gotosocial/internal/media"
|
||||||
|
|
@ -107,8 +108,9 @@ func (suite *AccountStandardTestSuite) SetupTest() {
|
||||||
|
|
||||||
visFilter := visibility.NewFilter(&suite.state)
|
visFilter := visibility.NewFilter(&suite.state)
|
||||||
mutesFilter := mutes.NewFilter(&suite.state)
|
mutesFilter := mutes.NewFilter(&suite.state)
|
||||||
common := common.New(&suite.state, suite.mediaManager, suite.tc, suite.federator, visFilter, mutesFilter)
|
statusFilter := status.NewFilter(&suite.state)
|
||||||
suite.accountProcessor = account.New(&common, &suite.state, suite.tc, suite.mediaManager, suite.federator, visFilter, processing.GetParseMentionFunc(&suite.state, suite.federator))
|
common := common.New(&suite.state, suite.mediaManager, suite.tc, suite.federator, visFilter, mutesFilter, statusFilter)
|
||||||
|
suite.accountProcessor = account.New(&common, &suite.state, suite.tc, suite.mediaManager, suite.federator, visFilter, statusFilter, processing.GetParseMentionFunc(&suite.state, suite.federator))
|
||||||
testrig.StandardDBSetup(suite.db, nil)
|
testrig.StandardDBSetup(suite.db, nil)
|
||||||
testrig.StandardStorageSetup(suite.storage, "../../../testrig/media")
|
testrig.StandardStorageSetup(suite.storage, "../../../testrig/media")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ func (p *Processor) BookmarksGet(ctx context.Context, requestingAccount *gtsmode
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert the status.
|
// Convert the status.
|
||||||
item, err := p.converter.StatusToAPIStatus(ctx, status, requestingAccount, gtsmodel.FilterContextNone)
|
item, err := p.converter.StatusToAPIStatus(ctx, status, requestingAccount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf(ctx, "error converting bookmarked status to api: %s", err)
|
log.Errorf(ctx, "error converting bookmarked status to api: %s", err)
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -96,13 +96,33 @@ func (p *Processor) StatusesGet(
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range filtered {
|
for _, status := range filtered {
|
||||||
|
// ...
|
||||||
|
filtered, hide, err := p.statusFilter.StatusFilterResultsInContext(ctx,
|
||||||
|
requestingAccount,
|
||||||
|
status,
|
||||||
|
gtsmodel.FilterContextAccount,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf(ctx, "error filtering status: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if hide {
|
||||||
|
// Don't show.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Convert filtered statuses to API statuses.
|
// Convert filtered statuses to API statuses.
|
||||||
item, err := p.converter.StatusToAPIStatus(ctx, s, requestingAccount, gtsmodel.FilterContextAccount)
|
item, err := p.converter.StatusToAPIStatus(ctx, status, requestingAccount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf(ctx, "error convering to api status: %v", err)
|
log.Errorf(ctx, "error convering to api status: %v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set any filter results.
|
||||||
|
item.Filtered = filtered
|
||||||
|
|
||||||
items = append(items, item)
|
items = append(items, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/federation"
|
"code.superseriousbusiness.org/gotosocial/internal/federation"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/filter/status"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/media"
|
"code.superseriousbusiness.org/gotosocial/internal/media"
|
||||||
|
|
@ -116,6 +117,7 @@ func (suite *AdminStandardTestSuite) SetupTest() {
|
||||||
visibility.NewFilter(&suite.state),
|
visibility.NewFilter(&suite.state),
|
||||||
mutes.NewFilter(&suite.state),
|
mutes.NewFilter(&suite.state),
|
||||||
interaction.NewFilter(&suite.state),
|
interaction.NewFilter(&suite.state),
|
||||||
|
status.NewFilter(&suite.state),
|
||||||
)
|
)
|
||||||
|
|
||||||
testrig.StartWorkers(&suite.state, suite.processor.Workers())
|
testrig.StartWorkers(&suite.state, suite.processor.Workers())
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ package common
|
||||||
import (
|
import (
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/federation"
|
"code.superseriousbusiness.org/gotosocial/internal/federation"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/filter/status"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/media"
|
"code.superseriousbusiness.org/gotosocial/internal/media"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/state"
|
"code.superseriousbusiness.org/gotosocial/internal/state"
|
||||||
|
|
@ -36,6 +37,7 @@ type Processor struct {
|
||||||
federator *federation.Federator
|
federator *federation.Federator
|
||||||
visFilter *visibility.Filter
|
visFilter *visibility.Filter
|
||||||
muteFilter *mutes.Filter
|
muteFilter *mutes.Filter
|
||||||
|
statusFilter *status.Filter
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new Processor instance.
|
// New returns a new Processor instance.
|
||||||
|
|
@ -46,6 +48,7 @@ func New(
|
||||||
federator *federation.Federator,
|
federator *federation.Federator,
|
||||||
visFilter *visibility.Filter,
|
visFilter *visibility.Filter,
|
||||||
muteFilter *mutes.Filter,
|
muteFilter *mutes.Filter,
|
||||||
|
statusFilter *status.Filter,
|
||||||
) Processor {
|
) Processor {
|
||||||
return Processor{
|
return Processor{
|
||||||
state: state,
|
state: state,
|
||||||
|
|
@ -54,5 +57,6 @@ func New(
|
||||||
federator: federator,
|
federator: federator,
|
||||||
visFilter: visFilter,
|
visFilter: visFilter,
|
||||||
muteFilter: muteFilter,
|
muteFilter: muteFilter,
|
||||||
|
statusFilter: statusFilter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ import (
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/log"
|
"code.superseriousbusiness.org/gotosocial/internal/log"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/typeutils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetOwnStatus fetches the given status with ID,
|
// GetOwnStatus fetches the given status with ID,
|
||||||
|
|
@ -213,7 +212,6 @@ func (p *Processor) GetAPIStatus(
|
||||||
apiStatus, err := p.converter.StatusToAPIStatus(ctx,
|
apiStatus, err := p.converter.StatusToAPIStatus(ctx,
|
||||||
target,
|
target,
|
||||||
requester,
|
requester,
|
||||||
gtsmodel.FilterContextNone,
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := gtserror.Newf("error converting: %w", err)
|
err := gtserror.Newf("error converting: %w", err)
|
||||||
|
|
@ -271,22 +269,33 @@ func (p *Processor) GetVisibleAPIStatuses(
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check whether status is filtered in context by requesting account.
|
||||||
|
filtered, hide, err := p.statusFilter.StatusFilterResultsInContext(ctx,
|
||||||
|
requester,
|
||||||
|
status,
|
||||||
|
filterCtx,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
l.Errorf("error filtering: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if hide {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Convert to API status, taking mute / filter into account.
|
// Convert to API status, taking mute / filter into account.
|
||||||
apiStatus, err := p.converter.StatusToAPIStatus(ctx,
|
apiStatus, err := p.converter.StatusToAPIStatus(ctx,
|
||||||
status,
|
status,
|
||||||
requester,
|
requester,
|
||||||
filterCtx,
|
|
||||||
)
|
)
|
||||||
if err != nil && !errors.Is(err, typeutils.ErrHideStatus) {
|
if err != nil {
|
||||||
l.Errorf("error converting: %v", err)
|
l.Errorf("error converting: %v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if apiStatus == nil {
|
// Set filter results on status.
|
||||||
// Status was
|
apiStatus.Filtered = filtered
|
||||||
// filtered out.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append converted status to return slice.
|
// Append converted status to return slice.
|
||||||
apiStatuses = append(apiStatuses, *apiStatus)
|
apiStatuses = append(apiStatuses, *apiStatus)
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
|
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/db"
|
"code.superseriousbusiness.org/gotosocial/internal/db"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/filter/status"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||||
|
|
@ -35,6 +36,7 @@ type Processor struct {
|
||||||
converter *typeutils.Converter
|
converter *typeutils.Converter
|
||||||
visFilter *visibility.Filter
|
visFilter *visibility.Filter
|
||||||
muteFilter *mutes.Filter
|
muteFilter *mutes.Filter
|
||||||
|
statusFilter *status.Filter
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(
|
func New(
|
||||||
|
|
@ -42,12 +44,14 @@ func New(
|
||||||
converter *typeutils.Converter,
|
converter *typeutils.Converter,
|
||||||
visFilter *visibility.Filter,
|
visFilter *visibility.Filter,
|
||||||
muteFilter *mutes.Filter,
|
muteFilter *mutes.Filter,
|
||||||
|
statusFilter *status.Filter,
|
||||||
) Processor {
|
) Processor {
|
||||||
return Processor{
|
return Processor{
|
||||||
state: state,
|
state: state,
|
||||||
converter: converter,
|
converter: converter,
|
||||||
visFilter: visFilter,
|
visFilter: visFilter,
|
||||||
muteFilter: muteFilter,
|
muteFilter: muteFilter,
|
||||||
|
statusFilter: statusFilter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,21 +99,3 @@ func (p *Processor) getConversationOwnedBy(
|
||||||
|
|
||||||
return conversation, nil
|
return conversation, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getFiltersAndMutes gets the given account's filters and compiled mute list.
|
|
||||||
func (p *Processor) getFilters(
|
|
||||||
ctx context.Context,
|
|
||||||
requestingAccount *gtsmodel.Account,
|
|
||||||
) ([]*gtsmodel.Filter, gtserror.WithCode) {
|
|
||||||
filters, err := p.state.DB.GetFiltersByAccountID(ctx, requestingAccount.ID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, gtserror.NewErrorInternalError(
|
|
||||||
gtserror.Newf(
|
|
||||||
"DB error getting filters for account %s: %w",
|
|
||||||
requestingAccount.ID,
|
|
||||||
err,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return filters, nil
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/email"
|
"code.superseriousbusiness.org/gotosocial/internal/email"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/federation"
|
"code.superseriousbusiness.org/gotosocial/internal/federation"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/filter/status"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/log"
|
"code.superseriousbusiness.org/gotosocial/internal/log"
|
||||||
|
|
@ -118,7 +119,7 @@ func (suite *ConversationsTestSuite) SetupTest() {
|
||||||
suite.sentEmails = make(map[string]string)
|
suite.sentEmails = make(map[string]string)
|
||||||
suite.emailSender = testrig.NewEmailSender("../../../web/template/", suite.sentEmails)
|
suite.emailSender = testrig.NewEmailSender("../../../web/template/", suite.sentEmails)
|
||||||
|
|
||||||
suite.conversationsProcessor = conversations.New(&suite.state, suite.tc, suite.visFilter, suite.muteFilter)
|
suite.conversationsProcessor = conversations.New(&suite.state, suite.tc, suite.visFilter, suite.muteFilter, status.NewFilter(&suite.state))
|
||||||
testrig.StandardDBSetup(suite.db, nil)
|
testrig.StandardDBSetup(suite.db, nil)
|
||||||
testrig.StandardStorageSetup(suite.storage, "../../../testrig/media")
|
testrig.StandardStorageSetup(suite.storage, "../../../testrig/media")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,17 +64,26 @@ func (p *Processor) GetAll(
|
||||||
|
|
||||||
items := make([]interface{}, 0, count)
|
items := make([]interface{}, 0, count)
|
||||||
|
|
||||||
filters, errWithCode := p.getFilters(ctx, requestingAccount)
|
for _, conversation := range conversations {
|
||||||
if errWithCode != nil {
|
// Check whether status if filtered by local participant in context.
|
||||||
return nil, errWithCode
|
filtered, hide, err := p.statusFilter.StatusFilterResultsInContext(ctx,
|
||||||
|
requestingAccount,
|
||||||
|
conversation.LastStatus,
|
||||||
|
gtsmodel.FilterContextNotifications,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf(ctx, "error filtering status: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if hide {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, conversation := range conversations {
|
|
||||||
// Convert conversation to frontend API model.
|
// Convert conversation to frontend API model.
|
||||||
apiConversation, err := p.converter.ConversationToAPIConversation(ctx,
|
apiConversation, err := p.converter.ConversationToAPIConversation(ctx,
|
||||||
conversation,
|
conversation,
|
||||||
requestingAccount,
|
requestingAccount,
|
||||||
filters,
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf(ctx,
|
log.Errorf(ctx,
|
||||||
|
|
@ -85,6 +94,9 @@ func (p *Processor) GetAll(
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set filter results on attached status model.
|
||||||
|
apiConversation.LastStatus.Filtered = filtered
|
||||||
|
|
||||||
// Append conversation to return items.
|
// Append conversation to return items.
|
||||||
items = append(items, apiConversation)
|
items = append(items, apiConversation)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
|
apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/log"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/util"
|
"code.superseriousbusiness.org/gotosocial/internal/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -44,20 +45,27 @@ func (p *Processor) Read(
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
filters, errWithCode := p.getFilters(ctx, requestingAccount)
|
// Check whether status if filtered by local participant in context.
|
||||||
if errWithCode != nil {
|
filtered, _, err := p.statusFilter.StatusFilterResultsInContext(ctx,
|
||||||
return nil, errWithCode
|
requestingAccount,
|
||||||
|
conversation.LastStatus,
|
||||||
|
gtsmodel.FilterContextNotifications,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf(ctx, "error filtering status: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
apiConversation, err := p.converter.ConversationToAPIConversation(ctx,
|
apiConversation, err := p.converter.ConversationToAPIConversation(ctx,
|
||||||
conversation,
|
conversation,
|
||||||
requestingAccount,
|
requestingAccount,
|
||||||
filters,
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = gtserror.Newf("error converting conversation %s to API representation: %w", id, err)
|
err = gtserror.Newf("error converting conversation %s to API representation: %w", id, err)
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set filter results on attached status model.
|
||||||
|
apiConversation.LastStatus.Filtered = filtered
|
||||||
|
|
||||||
return apiConversation, nil
|
return apiConversation, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ import (
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/id"
|
"code.superseriousbusiness.org/gotosocial/internal/id"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/log"
|
"code.superseriousbusiness.org/gotosocial/internal/log"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/typeutils"
|
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/util"
|
"code.superseriousbusiness.org/gotosocial/internal/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -158,26 +157,6 @@ func (p *Processor) UpdateConversationsForStatus(ctx context.Context, status *gt
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert the conversation to API representation.
|
|
||||||
apiConversation, err := p.converter.ConversationToAPIConversation(ctx,
|
|
||||||
conversation,
|
|
||||||
localAccount,
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
// If the conversation's last status matched a hide filter, skip it.
|
|
||||||
// If there was another kind of error, log that and skip it anyway.
|
|
||||||
if !errors.Is(err, typeutils.ErrHideStatus) {
|
|
||||||
log.Errorf(ctx,
|
|
||||||
"error converting conversation %s to API representation for account %s: %v",
|
|
||||||
status.ID,
|
|
||||||
localAccount.ID,
|
|
||||||
err,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// If status was authored by this participant,
|
// If status was authored by this participant,
|
||||||
// don't bother notifying, they already know!
|
// don't bother notifying, they already know!
|
||||||
if status.AccountID == localAccount.ID {
|
if status.AccountID == localAccount.ID {
|
||||||
|
|
@ -198,6 +177,38 @@ func (p *Processor) UpdateConversationsForStatus(ctx context.Context, status *gt
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check whether status if filtered by local participant in context.
|
||||||
|
filtered, hide, err := p.statusFilter.StatusFilterResultsInContext(ctx,
|
||||||
|
localAccount,
|
||||||
|
status,
|
||||||
|
gtsmodel.FilterContextNotifications,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf(ctx, "error filtering status: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if hide {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the conversation to API representation.
|
||||||
|
apiConversation, err := p.converter.ConversationToAPIConversation(ctx,
|
||||||
|
conversation,
|
||||||
|
localAccount,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf(ctx, "error converting conversation %s to API representation for account %s: %v",
|
||||||
|
status.ID,
|
||||||
|
localAccount.ID,
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set filter results on attached status model.
|
||||||
|
apiConversation.LastStatus.Filtered = filtered
|
||||||
|
|
||||||
// Generate a notification,
|
// Generate a notification,
|
||||||
notifications = append(notifications, ConversationNotification{
|
notifications = append(notifications, ConversationNotification{
|
||||||
AccountID: localAccount.ID,
|
AccountID: localAccount.ID,
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/admin"
|
"code.superseriousbusiness.org/gotosocial/internal/admin"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/db"
|
"code.superseriousbusiness.org/gotosocial/internal/db"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/filter/status"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/media"
|
"code.superseriousbusiness.org/gotosocial/internal/media"
|
||||||
|
|
@ -85,7 +86,8 @@ func (suite *MediaStandardTestSuite) SetupTest() {
|
||||||
federator := testrig.NewTestFederator(&suite.state, suite.transportController, suite.mediaManager)
|
federator := testrig.NewTestFederator(&suite.state, suite.transportController, suite.mediaManager)
|
||||||
visFilter := visibility.NewFilter(&suite.state)
|
visFilter := visibility.NewFilter(&suite.state)
|
||||||
muteFilter := mutes.NewFilter(&suite.state)
|
muteFilter := mutes.NewFilter(&suite.state)
|
||||||
common := common.New(&suite.state, suite.mediaManager, suite.tc, federator, visFilter, muteFilter)
|
statusFilter := status.NewFilter(&suite.state)
|
||||||
|
common := common.New(&suite.state, suite.mediaManager, suite.tc, federator, visFilter, muteFilter, statusFilter)
|
||||||
|
|
||||||
suite.mediaProcessor = mediaprocessing.New(&common, &suite.state, suite.tc, federator, suite.mediaManager, suite.transportController)
|
suite.mediaProcessor = mediaprocessing.New(&common, &suite.state, suite.tc, federator, suite.mediaManager, suite.transportController)
|
||||||
testrig.StandardDBSetup(suite.db, nil)
|
testrig.StandardDBSetup(suite.db, nil)
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
|
|
||||||
apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
|
apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/filter/status"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||||
|
|
@ -60,7 +61,8 @@ func (suite *PollTestSuite) SetupTest() {
|
||||||
federator := testrig.NewTestFederator(&suite.state, controller, mediaMgr)
|
federator := testrig.NewTestFederator(&suite.state, controller, mediaMgr)
|
||||||
suite.visFilter = visibility.NewFilter(&suite.state)
|
suite.visFilter = visibility.NewFilter(&suite.state)
|
||||||
suite.muteFilter = mutes.NewFilter(&suite.state)
|
suite.muteFilter = mutes.NewFilter(&suite.state)
|
||||||
common := common.New(&suite.state, mediaMgr, converter, federator, suite.visFilter, suite.muteFilter)
|
statusFilter := status.NewFilter(&suite.state)
|
||||||
|
common := common.New(&suite.state, mediaMgr, converter, federator, suite.visFilter, suite.muteFilter, statusFilter)
|
||||||
suite.polls = polls.New(&common, &suite.state, converter)
|
suite.polls = polls.New(&common, &suite.state, converter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/federation"
|
"code.superseriousbusiness.org/gotosocial/internal/federation"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
||||||
|
statusfilter "code.superseriousbusiness.org/gotosocial/internal/filter/status"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||||
mm "code.superseriousbusiness.org/gotosocial/internal/media"
|
mm "code.superseriousbusiness.org/gotosocial/internal/media"
|
||||||
|
|
@ -193,7 +194,8 @@ func (p *Processor) Workers() *workers.Processor {
|
||||||
return &p.workers
|
return &p.workers
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewProcessor returns a new Processor.
|
// NewProcessor returns
|
||||||
|
// a new Processor.
|
||||||
func NewProcessor(
|
func NewProcessor(
|
||||||
cleaner *cleaner.Cleaner,
|
cleaner *cleaner.Cleaner,
|
||||||
subscriptions *subscriptions.Subscriptions,
|
subscriptions *subscriptions.Subscriptions,
|
||||||
|
|
@ -207,6 +209,7 @@ func NewProcessor(
|
||||||
visFilter *visibility.Filter,
|
visFilter *visibility.Filter,
|
||||||
muteFilter *mutes.Filter,
|
muteFilter *mutes.Filter,
|
||||||
intFilter *interaction.Filter,
|
intFilter *interaction.Filter,
|
||||||
|
statusFilter *statusfilter.Filter,
|
||||||
) *Processor {
|
) *Processor {
|
||||||
parseMentionFunc := GetParseMentionFunc(state, federator)
|
parseMentionFunc := GetParseMentionFunc(state, federator)
|
||||||
processor := &Processor{
|
processor := &Processor{
|
||||||
|
|
@ -221,18 +224,18 @@ func NewProcessor(
|
||||||
//
|
//
|
||||||
// Start with sub processors that will
|
// Start with sub processors that will
|
||||||
// be required by the workers processor.
|
// be required by the workers processor.
|
||||||
common := common.New(state, mediaManager, converter, federator, visFilter, muteFilter)
|
common := common.New(state, mediaManager, converter, federator, visFilter, muteFilter, statusFilter)
|
||||||
processor.account = account.New(&common, state, converter, mediaManager, federator, visFilter, parseMentionFunc)
|
processor.account = account.New(&common, state, converter, mediaManager, federator, visFilter, statusFilter, parseMentionFunc)
|
||||||
processor.media = media.New(&common, state, converter, federator, mediaManager, federator.TransportController())
|
processor.media = media.New(&common, state, converter, federator, mediaManager, federator.TransportController())
|
||||||
processor.stream = stream.New(state, oauthServer)
|
processor.stream = stream.New(state, oauthServer)
|
||||||
filterCommon := filterCommon.New(state, &processor.stream)
|
filterCommon := filterCommon.New(state, &processor.stream)
|
||||||
|
|
||||||
// Instantiate the rest of the sub
|
// Instantiate the rest of the sub
|
||||||
// processors + pin them to this struct.
|
// processors + pin them to this struct.
|
||||||
processor.account = account.New(&common, state, converter, mediaManager, federator, visFilter, parseMentionFunc)
|
processor.account = account.New(&common, state, converter, mediaManager, federator, visFilter, statusFilter, parseMentionFunc)
|
||||||
processor.admin = admin.New(&common, state, cleaner, subscriptions, federator, converter, mediaManager, federator.TransportController(), emailSender)
|
processor.admin = admin.New(&common, state, cleaner, subscriptions, federator, converter, mediaManager, federator.TransportController(), emailSender)
|
||||||
processor.application = application.New(state, converter)
|
processor.application = application.New(state, converter)
|
||||||
processor.conversations = conversations.New(state, converter, visFilter, muteFilter)
|
processor.conversations = conversations.New(state, converter, visFilter, muteFilter, statusFilter)
|
||||||
processor.fedi = fedi.New(state, &common, converter, federator, visFilter)
|
processor.fedi = fedi.New(state, &common, converter, federator, visFilter)
|
||||||
processor.filtersv1 = filtersv1.New(state, converter, filterCommon)
|
processor.filtersv1 = filtersv1.New(state, converter, filterCommon)
|
||||||
processor.filtersv2 = filtersv2.New(state, converter, filterCommon)
|
processor.filtersv2 = filtersv2.New(state, converter, filterCommon)
|
||||||
|
|
@ -243,7 +246,7 @@ func NewProcessor(
|
||||||
processor.push = push.New(state, converter)
|
processor.push = push.New(state, converter)
|
||||||
processor.report = report.New(state, converter)
|
processor.report = report.New(state, converter)
|
||||||
processor.tags = tags.New(state, converter)
|
processor.tags = tags.New(state, converter)
|
||||||
processor.timeline = timeline.New(state, converter, visFilter, muteFilter)
|
processor.timeline = timeline.New(state, converter, visFilter, muteFilter, statusFilter)
|
||||||
processor.search = search.New(state, federator, converter, visFilter)
|
processor.search = search.New(state, federator, converter, visFilter)
|
||||||
processor.status = status.New(state, &common, &processor.polls, &processor.interactionRequests, 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)
|
processor.user = user.New(state, converter, oauthServer, emailSender)
|
||||||
|
|
@ -261,6 +264,7 @@ func NewProcessor(
|
||||||
converter,
|
converter,
|
||||||
visFilter,
|
visFilter,
|
||||||
muteFilter,
|
muteFilter,
|
||||||
|
statusFilter,
|
||||||
emailSender,
|
emailSender,
|
||||||
webPushSender,
|
webPushSender,
|
||||||
&processor.account,
|
&processor.account,
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/federation"
|
"code.superseriousbusiness.org/gotosocial/internal/federation"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/filter/status"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/media"
|
"code.superseriousbusiness.org/gotosocial/internal/media"
|
||||||
|
|
@ -133,6 +134,7 @@ func (suite *ProcessingStandardTestSuite) SetupTest() {
|
||||||
visibility.NewFilter(&suite.state),
|
visibility.NewFilter(&suite.state),
|
||||||
mutes.NewFilter(&suite.state),
|
mutes.NewFilter(&suite.state),
|
||||||
interaction.NewFilter(&suite.state),
|
interaction.NewFilter(&suite.state),
|
||||||
|
status.NewFilter(&suite.state),
|
||||||
)
|
)
|
||||||
testrig.StartWorkers(&suite.state, suite.processor.Workers())
|
testrig.StartWorkers(&suite.state, suite.processor.Workers())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ func (p *Processor) packageStatuses(
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
apiStatus, err := p.converter.StatusToAPIStatus(ctx, status, requestingAccount, gtsmodel.FilterContextNone)
|
apiStatus, err := p.converter.StatusToAPIStatus(ctx, status, requestingAccount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf(ctx, "skipping status %s because it couldn't be converted to its api representation: %s", status.ID, err)
|
log.Debugf(ctx, "skipping status %s because it couldn't be converted to its api representation: %s", status.ID, err)
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/federation"
|
"code.superseriousbusiness.org/gotosocial/internal/federation"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
||||||
|
statusfilter "code.superseriousbusiness.org/gotosocial/internal/filter/status"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/media"
|
"code.superseriousbusiness.org/gotosocial/internal/media"
|
||||||
|
|
@ -95,8 +96,9 @@ func (suite *StatusStandardTestSuite) SetupTest() {
|
||||||
visFilter := visibility.NewFilter(&suite.state)
|
visFilter := visibility.NewFilter(&suite.state)
|
||||||
muteFilter := mutes.NewFilter(&suite.state)
|
muteFilter := mutes.NewFilter(&suite.state)
|
||||||
intFilter := interaction.NewFilter(&suite.state)
|
intFilter := interaction.NewFilter(&suite.state)
|
||||||
|
statusFilter := statusfilter.NewFilter(&suite.state)
|
||||||
|
|
||||||
common := common.New(&suite.state, suite.mediaManager, suite.typeConverter, suite.federator, visFilter, muteFilter)
|
common := common.New(&suite.state, suite.mediaManager, suite.typeConverter, suite.federator, visFilter, muteFilter, statusFilter)
|
||||||
polls := polls.New(&common, &suite.state, suite.typeConverter)
|
polls := polls.New(&common, &suite.state, suite.typeConverter)
|
||||||
intReqs := interactionrequests.New(&common, &suite.state, suite.typeConverter)
|
intReqs := interactionrequests.New(&common, &suite.state, suite.typeConverter)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/stream"
|
"code.superseriousbusiness.org/gotosocial/internal/stream"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/typeutils"
|
"code.superseriousbusiness.org/gotosocial/internal/typeutils"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
@ -39,7 +38,7 @@ func (suite *StatusUpdateTestSuite) TestStreamNotification() {
|
||||||
suite.NoError(errWithCode)
|
suite.NoError(errWithCode)
|
||||||
|
|
||||||
editedStatus := suite.testStatuses["remote_account_1_status_1"]
|
editedStatus := suite.testStatuses["remote_account_1_status_1"]
|
||||||
apiStatus, err := typeutils.NewConverter(&suite.state).StatusToAPIStatus(suite.T().Context(), editedStatus, account, gtsmodel.FilterContextNotifications)
|
apiStatus, err := typeutils.NewConverter(&suite.state).StatusToAPIStatus(suite.T().Context(), editedStatus, account)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
suite.streamProcessor.StatusUpdate(suite.T().Context(), account, apiStatus, stream.TimelineHome)
|
suite.streamProcessor.StatusUpdate(suite.T().Context(), account, apiStatus, stream.TimelineHome)
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ import (
|
||||||
apiutil "code.superseriousbusiness.org/gotosocial/internal/api/util"
|
apiutil "code.superseriousbusiness.org/gotosocial/internal/api/util"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/db"
|
"code.superseriousbusiness.org/gotosocial/internal/db"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/log"
|
"code.superseriousbusiness.org/gotosocial/internal/log"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/util"
|
"code.superseriousbusiness.org/gotosocial/internal/util"
|
||||||
)
|
)
|
||||||
|
|
@ -56,7 +55,7 @@ func (p *Processor) FavedTimelineGet(ctx context.Context, authed *apiutil.Auth,
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
apiStatus, err := p.converter.StatusToAPIStatus(ctx, s, authed.Account, gtsmodel.FilterContextNone)
|
apiStatus, err := p.converter.StatusToAPIStatus(ctx, s, authed.Account)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf(ctx, "error convering to api status: %v", err)
|
log.Errorf(ctx, "error convering to api status: %v", err)
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@ import (
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/log"
|
"code.superseriousbusiness.org/gotosocial/internal/log"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/paging"
|
"code.superseriousbusiness.org/gotosocial/internal/paging"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/typeutils"
|
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/util"
|
"code.superseriousbusiness.org/gotosocial/internal/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -93,8 +92,12 @@ func (p *Processor) NotificationsGet(
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var filtered []apimodel.FilterResult
|
||||||
|
|
||||||
if n.Status != nil {
|
if n.Status != nil {
|
||||||
// A status is attached, check whether status muted.
|
var hide bool
|
||||||
|
|
||||||
|
// Check whether notification status is muted by requester.
|
||||||
muted, err = p.muteFilter.StatusNotificationsMuted(ctx,
|
muted, err = p.muteFilter.StatusNotificationsMuted(ctx,
|
||||||
requester,
|
requester,
|
||||||
n.Status,
|
n.Status,
|
||||||
|
|
@ -107,15 +110,33 @@ func (p *Processor) NotificationsGet(
|
||||||
if muted {
|
if muted {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check whether notification status is filtered by requester in notifs.
|
||||||
|
filtered, hide, err = p.statusFilter.StatusFilterResultsInContext(ctx,
|
||||||
|
requester,
|
||||||
|
n.Status,
|
||||||
|
gtsmodel.FilterContextNotifications,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf(ctx, "error checking status filtering: %v", err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
item, err := p.converter.NotificationToAPINotification(ctx, n, true)
|
if hide {
|
||||||
if err != nil {
|
|
||||||
if !errors.Is(err, typeutils.ErrHideStatus) {
|
|
||||||
log.Debugf(ctx, "skipping notification %s because it couldn't be converted to its api representation: %s", n.ID, err)
|
|
||||||
}
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
item, err := p.converter.NotificationToAPINotification(ctx, n)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if item.Status != nil {
|
||||||
|
// Set filter results on status,
|
||||||
|
// in case any were set above.
|
||||||
|
item.Status.Filtered = filtered
|
||||||
|
}
|
||||||
|
|
||||||
items = append(items, item)
|
items = append(items, item)
|
||||||
}
|
}
|
||||||
|
|
@ -154,7 +175,7 @@ func (p *Processor) NotificationGet(ctx context.Context, account *gtsmodel.Accou
|
||||||
// or mute checking for a notification directly
|
// or mute checking for a notification directly
|
||||||
// fetched by ID. only from timelines etc.
|
// fetched by ID. only from timelines etc.
|
||||||
|
|
||||||
apiNotif, err := p.converter.NotificationToAPINotification(ctx, notif, false)
|
apiNotif, err := p.converter.NotificationToAPINotification(ctx, notif)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := gtserror.Newf("error converting to api model: %w", err)
|
err := gtserror.Newf("error converting to api model: %w", err)
|
||||||
return nil, gtserror.WrapWithCode(http.StatusInternalServerError, err)
|
return nil, gtserror.WrapWithCode(http.StatusInternalServerError, err)
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,13 @@ package timeline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
|
apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
|
||||||
timelinepkg "code.superseriousbusiness.org/gotosocial/internal/cache/timeline"
|
timelinepkg "code.superseriousbusiness.org/gotosocial/internal/cache/timeline"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/filter/status"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||||
|
|
@ -50,14 +50,22 @@ type Processor struct {
|
||||||
converter *typeutils.Converter
|
converter *typeutils.Converter
|
||||||
visFilter *visibility.Filter
|
visFilter *visibility.Filter
|
||||||
muteFilter *mutes.Filter
|
muteFilter *mutes.Filter
|
||||||
|
statusFilter *status.Filter
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(state *state.State, converter *typeutils.Converter, visFilter *visibility.Filter, muteFilter *mutes.Filter) Processor {
|
func New(
|
||||||
|
state *state.State,
|
||||||
|
converter *typeutils.Converter,
|
||||||
|
visFilter *visibility.Filter,
|
||||||
|
muteFilter *mutes.Filter,
|
||||||
|
statusFilter *status.Filter,
|
||||||
|
) Processor {
|
||||||
return Processor{
|
return Processor{
|
||||||
state: state,
|
state: state,
|
||||||
converter: converter,
|
converter: converter,
|
||||||
visFilter: visFilter,
|
visFilter: visFilter,
|
||||||
muteFilter: muteFilter,
|
muteFilter: muteFilter,
|
||||||
|
statusFilter: statusFilter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,15 +124,30 @@ func (p *Processor) getStatusTimeline(
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check whether this status is filtered by requester in this context.
|
||||||
|
filters, hide, err := p.statusFilter.StatusFilterResultsInContext(ctx,
|
||||||
|
requester,
|
||||||
|
status,
|
||||||
|
filterCtx,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if hide {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Finally, pass status to get converted to API model.
|
// Finally, pass status to get converted to API model.
|
||||||
apiStatus, err := p.converter.StatusToAPIStatus(ctx,
|
apiStatus, err := p.converter.StatusToAPIStatus(ctx,
|
||||||
status,
|
status,
|
||||||
requester,
|
requester,
|
||||||
filterCtx,
|
|
||||||
)
|
)
|
||||||
if err != nil && !errors.Is(err, typeutils.ErrHideStatus) {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set any filters on status.
|
||||||
|
apiStatus.Filtered = filters
|
||||||
|
|
||||||
return apiStatus, nil
|
return apiStatus, nil
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/admin"
|
"code.superseriousbusiness.org/gotosocial/internal/admin"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/db"
|
"code.superseriousbusiness.org/gotosocial/internal/db"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/filter/status"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/processing/timeline"
|
"code.superseriousbusiness.org/gotosocial/internal/processing/timeline"
|
||||||
|
|
@ -64,6 +65,7 @@ func (suite *TimelineStandardTestSuite) SetupTest() {
|
||||||
typeutils.NewConverter(&suite.state),
|
typeutils.NewConverter(&suite.state),
|
||||||
visibility.NewFilter(&suite.state),
|
visibility.NewFilter(&suite.state),
|
||||||
mutes.NewFilter(&suite.state),
|
mutes.NewFilter(&suite.state),
|
||||||
|
status.NewFilter(&suite.state),
|
||||||
)
|
)
|
||||||
|
|
||||||
testrig.StandardDBSetup(suite.db, suite.testAccounts)
|
testrig.StandardDBSetup(suite.db, suite.testAccounts)
|
||||||
|
|
|
||||||
|
|
@ -212,7 +212,6 @@ func (suite *FromClientAPITestSuite) statusJSON(
|
||||||
ctx,
|
ctx,
|
||||||
status,
|
status,
|
||||||
requestingAccount,
|
requestingAccount,
|
||||||
gtsmodel.FilterContextNone,
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
suite.FailNow(err.Error())
|
suite.FailNow(err.Error())
|
||||||
|
|
@ -236,7 +235,6 @@ func (suite *FromClientAPITestSuite) conversationJSON(
|
||||||
ctx,
|
ctx,
|
||||||
conversation,
|
conversation,
|
||||||
requestingAccount,
|
requestingAccount,
|
||||||
nil,
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
suite.FailNow(err.Error())
|
suite.FailNow(err.Error())
|
||||||
|
|
@ -344,7 +342,7 @@ func (suite *FromClientAPITestSuite) TestProcessCreateStatusWithNotification() {
|
||||||
suite.FailNow("timed out waiting for new status notification")
|
suite.FailNow("timed out waiting for new status notification")
|
||||||
}
|
}
|
||||||
|
|
||||||
apiNotif, err := testStructs.TypeConverter.NotificationToAPINotification(ctx, notif, false)
|
apiNotif, err := testStructs.TypeConverter.NotificationToAPINotification(ctx, notif)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
suite.FailNow(err.Error())
|
suite.FailNow(err.Error())
|
||||||
}
|
}
|
||||||
|
|
@ -2031,7 +2029,7 @@ func (suite *FromClientAPITestSuite) TestProcessCreateStatusWithAuthorOnExclusiv
|
||||||
suite.FailNow("timed out waiting for new status notification")
|
suite.FailNow("timed out waiting for new status notification")
|
||||||
}
|
}
|
||||||
|
|
||||||
apiNotif, err := testStructs.TypeConverter.NotificationToAPINotification(ctx, notif, false)
|
apiNotif, err := testStructs.TypeConverter.NotificationToAPINotification(ctx, notif)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
suite.FailNow(err.Error())
|
suite.FailNow(err.Error())
|
||||||
}
|
}
|
||||||
|
|
@ -2216,7 +2214,7 @@ func (suite *FromClientAPITestSuite) TestProcessUpdateStatusInteractedWith() {
|
||||||
suite.FailNow("timed out waiting for edited status notification")
|
suite.FailNow("timed out waiting for edited status notification")
|
||||||
}
|
}
|
||||||
|
|
||||||
apiNotif, err := testStructs.TypeConverter.NotificationToAPINotification(ctx, notif, false)
|
apiNotif, err := testStructs.TypeConverter.NotificationToAPINotification(ctx, notif)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
suite.FailNow(err.Error())
|
suite.FailNow(err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ package workers
|
||||||
import (
|
import (
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/email"
|
"code.superseriousbusiness.org/gotosocial/internal/email"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/filter/status"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/processing/conversations"
|
"code.superseriousbusiness.org/gotosocial/internal/processing/conversations"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/processing/stream"
|
"code.superseriousbusiness.org/gotosocial/internal/processing/stream"
|
||||||
|
|
@ -40,6 +41,7 @@ type Surface struct {
|
||||||
Stream *stream.Processor
|
Stream *stream.Processor
|
||||||
VisFilter *visibility.Filter
|
VisFilter *visibility.Filter
|
||||||
MuteFilter *mutes.Filter
|
MuteFilter *mutes.Filter
|
||||||
|
StatusFilter *status.Filter
|
||||||
EmailSender email.Sender
|
EmailSender email.Sender
|
||||||
WebPushSender webpush.Sender
|
WebPushSender webpush.Sender
|
||||||
Conversations *conversations.Processor
|
Conversations *conversations.Processor
|
||||||
|
|
|
||||||
|
|
@ -22,12 +22,12 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/db"
|
"code.superseriousbusiness.org/gotosocial/internal/db"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtscontext"
|
"code.superseriousbusiness.org/gotosocial/internal/gtscontext"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/id"
|
"code.superseriousbusiness.org/gotosocial/internal/id"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/typeutils"
|
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/util"
|
"code.superseriousbusiness.org/gotosocial/internal/util"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/util/xslices"
|
"code.superseriousbusiness.org/gotosocial/internal/util/xslices"
|
||||||
)
|
)
|
||||||
|
|
@ -727,6 +727,8 @@ func (s *Surface) Notify(
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var filtered []apimodel.FilterResult
|
||||||
|
|
||||||
if status != nil {
|
if status != nil {
|
||||||
// Check whether status is muted by the target account.
|
// Check whether status is muted by the target account.
|
||||||
muted, err := s.MuteFilter.StatusNotificationsMuted(ctx,
|
muted, err := s.MuteFilter.StatusNotificationsMuted(ctx,
|
||||||
|
|
@ -741,17 +743,35 @@ func (s *Surface) Notify(
|
||||||
// Don't notify.
|
// Don't notify.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var hide bool
|
||||||
|
|
||||||
|
// Check whether notification status is filtered by requester in notifs.
|
||||||
|
filtered, hide, err = s.StatusFilter.StatusFilterResultsInContext(ctx,
|
||||||
|
targetAccount,
|
||||||
|
status,
|
||||||
|
gtsmodel.FilterContextNotifications,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return gtserror.Newf("error checking status filtering: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert the notification to frontend API model for streaming / web push.
|
if hide {
|
||||||
apiNotif, err := s.Converter.NotificationToAPINotification(ctx, notif, true)
|
// Don't notify.
|
||||||
if err != nil && !errors.Is(err, typeutils.ErrHideStatus) {
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert notification to frontend API model for streaming / web push.
|
||||||
|
apiNotif, err := s.Converter.NotificationToAPINotification(ctx, notif)
|
||||||
|
if err != nil {
|
||||||
return gtserror.Newf("error converting notification to api representation: %w", err)
|
return gtserror.Newf("error converting notification to api representation: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if apiNotif == nil {
|
if apiNotif.Status != nil {
|
||||||
// Filtered.
|
// Set filter results on status,
|
||||||
return nil
|
// in case any were set above.
|
||||||
|
apiNotif.Status.Filtered = filtered
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stream notification to the user.
|
// Stream notification to the user.
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ package workers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
|
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/cache/timeline"
|
"code.superseriousbusiness.org/gotosocial/internal/cache/timeline"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtscontext"
|
"code.superseriousbusiness.org/gotosocial/internal/gtscontext"
|
||||||
|
|
@ -27,7 +26,6 @@ import (
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/log"
|
"code.superseriousbusiness.org/gotosocial/internal/log"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/stream"
|
"code.superseriousbusiness.org/gotosocial/internal/stream"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/typeutils"
|
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/util"
|
"code.superseriousbusiness.org/gotosocial/internal/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -350,28 +348,40 @@ func (s *Surface) timelineStatus(
|
||||||
streamType string,
|
streamType string,
|
||||||
filterCtx gtsmodel.FilterContext,
|
filterCtx gtsmodel.FilterContext,
|
||||||
) bool {
|
) bool {
|
||||||
|
// Check whether status is filtered in this context by timeline account.
|
||||||
|
filtered, hide, err := s.StatusFilter.StatusFilterResultsInContext(ctx,
|
||||||
|
account,
|
||||||
|
status,
|
||||||
|
filterCtx,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf(ctx, "error filtering status %s: %v", status.URI, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if hide {
|
||||||
|
// Don't even show to
|
||||||
|
// timeline account.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Attempt to convert status to frontend API representation,
|
// Attempt to convert status to frontend API representation,
|
||||||
// this will check whether status is filtered / muted.
|
// this will check whether status is filtered / muted.
|
||||||
apiModel, err := s.Converter.StatusToAPIStatus(ctx,
|
apiModel, err := s.Converter.StatusToAPIStatus(ctx,
|
||||||
status,
|
status,
|
||||||
account,
|
account,
|
||||||
filterCtx,
|
|
||||||
)
|
)
|
||||||
if err != nil && !errors.Is(err, typeutils.ErrHideStatus) {
|
if err != nil {
|
||||||
log.Error(ctx, "error converting status %s to frontend: %v", status.URI, err)
|
log.Error(ctx, "error converting status %s to frontend: %v", status.URI, err)
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Attach any filter results.
|
||||||
|
apiModel.Filtered = filtered
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert status to timeline cache regardless of
|
// Insert status to timeline cache regardless of
|
||||||
// if API model was succesfully prepared or not.
|
// if API model was succesfully prepared or not.
|
||||||
repeatBoost := timeline.InsertOne(status, apiModel)
|
repeatBoost := timeline.InsertOne(status, apiModel)
|
||||||
|
|
||||||
if apiModel == nil {
|
|
||||||
// Status was
|
|
||||||
// filtered.
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if !repeatBoost {
|
if !repeatBoost {
|
||||||
// Only stream if not repeated boost of recent status.
|
// Only stream if not repeated boost of recent status.
|
||||||
s.Stream.Update(ctx, account, apiModel, streamType)
|
s.Stream.Update(ctx, account, apiModel, streamType)
|
||||||
|
|
@ -683,26 +693,34 @@ func (s *Surface) timelineStreamStatusUpdate(
|
||||||
status *gtsmodel.Status,
|
status *gtsmodel.Status,
|
||||||
streamType string,
|
streamType string,
|
||||||
) (bool, error) {
|
) (bool, error) {
|
||||||
|
// Check whether status is filtered in this context by timeline account.
|
||||||
|
filtered, hide, err := s.StatusFilter.StatusFilterResultsInContext(ctx,
|
||||||
|
account,
|
||||||
|
status,
|
||||||
|
gtsmodel.FilterContextHome,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return false, gtserror.Newf("error filtering status: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if hide {
|
||||||
|
// Don't even show to
|
||||||
|
// timeline account.
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Convert updated database model to frontend model.
|
// Convert updated database model to frontend model.
|
||||||
apiStatus, err := s.Converter.StatusToAPIStatus(ctx,
|
apiStatus, err := s.Converter.StatusToAPIStatus(ctx,
|
||||||
status,
|
status,
|
||||||
account,
|
account,
|
||||||
gtsmodel.FilterContextHome,
|
|
||||||
)
|
)
|
||||||
|
if err != nil {
|
||||||
switch {
|
|
||||||
case err == nil:
|
|
||||||
// no issue.
|
|
||||||
|
|
||||||
case errors.Is(err, typeutils.ErrHideStatus):
|
|
||||||
// Don't put this status in the stream.
|
|
||||||
return false, nil
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false, gtserror.Newf("error converting status: %w", err)
|
return false, gtserror.Newf("error converting status: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Attach any filter results.
|
||||||
|
apiStatus.Filtered = filtered
|
||||||
|
|
||||||
// The status was updated so stream it to the user.
|
// The status was updated so stream it to the user.
|
||||||
s.Stream.StatusUpdate(ctx, account, apiStatus, streamType)
|
s.Stream.StatusUpdate(ctx, account, apiStatus, streamType)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/email"
|
"code.superseriousbusiness.org/gotosocial/internal/email"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/federation"
|
"code.superseriousbusiness.org/gotosocial/internal/federation"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/filter/status"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/processing/account"
|
"code.superseriousbusiness.org/gotosocial/internal/processing/account"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/processing/common"
|
"code.superseriousbusiness.org/gotosocial/internal/processing/common"
|
||||||
|
|
@ -46,6 +47,7 @@ func New(
|
||||||
converter *typeutils.Converter,
|
converter *typeutils.Converter,
|
||||||
visFilter *visibility.Filter,
|
visFilter *visibility.Filter,
|
||||||
muteFilter *mutes.Filter,
|
muteFilter *mutes.Filter,
|
||||||
|
statusFilter *status.Filter,
|
||||||
emailSender email.Sender,
|
emailSender email.Sender,
|
||||||
webPushSender webpush.Sender,
|
webPushSender webpush.Sender,
|
||||||
account *account.Processor,
|
account *account.Processor,
|
||||||
|
|
@ -69,6 +71,7 @@ func New(
|
||||||
Stream: stream,
|
Stream: stream,
|
||||||
VisFilter: visFilter,
|
VisFilter: visFilter,
|
||||||
MuteFilter: muteFilter,
|
MuteFilter: muteFilter,
|
||||||
|
StatusFilter: statusFilter,
|
||||||
EmailSender: emailSender,
|
EmailSender: emailSender,
|
||||||
WebPushSender: webPushSender,
|
WebPushSender: webPushSender,
|
||||||
Conversations: conversations,
|
Conversations: conversations,
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ import (
|
||||||
|
|
||||||
apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
|
apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/status"
|
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/log"
|
"code.superseriousbusiness.org/gotosocial/internal/log"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/state"
|
"code.superseriousbusiness.org/gotosocial/internal/state"
|
||||||
|
|
@ -38,7 +37,6 @@ type Converter struct {
|
||||||
defaultAvatars []string
|
defaultAvatars []string
|
||||||
randAvatars sync.Map
|
randAvatars sync.Map
|
||||||
visFilter *visibility.Filter
|
visFilter *visibility.Filter
|
||||||
statusFilter *status.Filter
|
|
||||||
intFilter *interaction.Filter
|
intFilter *interaction.Filter
|
||||||
randStats atomic.Pointer[apimodel.RandomStats]
|
randStats atomic.Pointer[apimodel.RandomStats]
|
||||||
}
|
}
|
||||||
|
|
@ -48,7 +46,6 @@ func NewConverter(state *state.State) *Converter {
|
||||||
state: state,
|
state: state,
|
||||||
defaultAvatars: populateDefaultAvatars(),
|
defaultAvatars: populateDefaultAvatars(),
|
||||||
visFilter: visibility.NewFilter(state),
|
visFilter: visibility.NewFilter(state),
|
||||||
statusFilter: status.NewFilter(state),
|
|
||||||
intFilter: interaction.NewFilter(state),
|
intFilter: interaction.NewFilter(state),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,10 +51,6 @@ const (
|
||||||
instanceMastodonVersion = "3.5.3"
|
instanceMastodonVersion = "3.5.3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrHideStatus indicates that a status has
|
|
||||||
// been filtered and should not be returned at all.
|
|
||||||
var ErrHideStatus = errors.New("hide status")
|
|
||||||
|
|
||||||
var instanceStatusesSupportedMimeTypes = []string{
|
var instanceStatusesSupportedMimeTypes = []string{
|
||||||
string(apimodel.StatusContentTypePlain),
|
string(apimodel.StatusContentTypePlain),
|
||||||
string(apimodel.StatusContentTypeMarkdown),
|
string(apimodel.StatusContentTypeMarkdown),
|
||||||
|
|
@ -850,13 +846,11 @@ func (c *Converter) StatusToAPIStatus(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
status *gtsmodel.Status,
|
status *gtsmodel.Status,
|
||||||
requestingAccount *gtsmodel.Account,
|
requestingAccount *gtsmodel.Account,
|
||||||
filterCtx gtsmodel.FilterContext,
|
|
||||||
) (*apimodel.Status, error) {
|
) (*apimodel.Status, error) {
|
||||||
return c.statusToAPIStatus(
|
return c.statusToAPIStatus(
|
||||||
ctx,
|
ctx,
|
||||||
status,
|
status,
|
||||||
requestingAccount,
|
requestingAccount,
|
||||||
filterCtx,
|
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
|
|
@ -870,7 +864,6 @@ func (c *Converter) statusToAPIStatus(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
status *gtsmodel.Status,
|
status *gtsmodel.Status,
|
||||||
requestingAccount *gtsmodel.Account,
|
requestingAccount *gtsmodel.Account,
|
||||||
filterCtx gtsmodel.FilterContext,
|
|
||||||
placeholdAttachments bool,
|
placeholdAttachments bool,
|
||||||
addPendingNote bool,
|
addPendingNote bool,
|
||||||
) (*apimodel.Status, error) {
|
) (*apimodel.Status, error) {
|
||||||
|
|
@ -878,7 +871,6 @@ func (c *Converter) statusToAPIStatus(
|
||||||
ctx,
|
ctx,
|
||||||
status,
|
status,
|
||||||
requestingAccount, // Can be nil.
|
requestingAccount, // Can be nil.
|
||||||
filterCtx, // Can be empty.
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -946,7 +938,6 @@ func (c *Converter) StatusToWebStatus(
|
||||||
) (*apimodel.WebStatus, error) {
|
) (*apimodel.WebStatus, error) {
|
||||||
apiStatus, err := c.statusToFrontend(ctx, s,
|
apiStatus, err := c.statusToFrontend(ctx, s,
|
||||||
nil, // No authed requester.
|
nil, // No authed requester.
|
||||||
gtsmodel.FilterContextNone, // No filters.
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -1115,7 +1106,6 @@ func (c *Converter) statusToFrontend(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
status *gtsmodel.Status,
|
status *gtsmodel.Status,
|
||||||
requestingAccount *gtsmodel.Account,
|
requestingAccount *gtsmodel.Account,
|
||||||
filterCtx gtsmodel.FilterContext,
|
|
||||||
) (
|
) (
|
||||||
*apimodel.Status,
|
*apimodel.Status,
|
||||||
error,
|
error,
|
||||||
|
|
@ -1123,7 +1113,6 @@ func (c *Converter) statusToFrontend(
|
||||||
apiStatus, err := c.baseStatusToFrontend(ctx,
|
apiStatus, err := c.baseStatusToFrontend(ctx,
|
||||||
status,
|
status,
|
||||||
requestingAccount,
|
requestingAccount,
|
||||||
filterCtx,
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -1133,12 +1122,8 @@ func (c *Converter) statusToFrontend(
|
||||||
reblog, err := c.baseStatusToFrontend(ctx,
|
reblog, err := c.baseStatusToFrontend(ctx,
|
||||||
status.BoostOf,
|
status.BoostOf,
|
||||||
requestingAccount,
|
requestingAccount,
|
||||||
filterCtx,
|
|
||||||
)
|
)
|
||||||
if errors.Is(err, ErrHideStatus) {
|
if err != nil {
|
||||||
// If we'd hide the original status, hide the boost.
|
|
||||||
return nil, err
|
|
||||||
} else if err != nil {
|
|
||||||
return nil, gtserror.Newf("error converting boosted status: %w", err)
|
return nil, gtserror.Newf("error converting boosted status: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1165,7 +1150,6 @@ func (c *Converter) baseStatusToFrontend(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
status *gtsmodel.Status,
|
status *gtsmodel.Status,
|
||||||
requester *gtsmodel.Account,
|
requester *gtsmodel.Account,
|
||||||
filterCtx gtsmodel.FilterContext,
|
|
||||||
) (
|
) (
|
||||||
*apimodel.Status,
|
*apimodel.Status,
|
||||||
error,
|
error,
|
||||||
|
|
@ -1340,20 +1324,6 @@ func (c *Converter) baseStatusToFrontend(
|
||||||
apiStatus.URL = apiStatus.URI
|
apiStatus.URL = apiStatus.URI
|
||||||
}
|
}
|
||||||
|
|
||||||
var hide bool
|
|
||||||
|
|
||||||
// Pass the status through any stored filters of requesting account's, in context.
|
|
||||||
apiStatus.Filtered, hide, err = c.statusFilter.StatusFilterResultsInContext(ctx,
|
|
||||||
requester,
|
|
||||||
status,
|
|
||||||
filterCtx,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, gtserror.Newf("error filtering status %s: %w", status.URI, err)
|
|
||||||
} else if hide {
|
|
||||||
return nil, ErrHideStatus
|
|
||||||
}
|
|
||||||
|
|
||||||
return apiStatus, nil
|
return apiStatus, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1866,7 +1836,6 @@ func (c *Converter) RelationshipToAPIRelationship(ctx context.Context, r *gtsmod
|
||||||
func (c *Converter) NotificationToAPINotification(
|
func (c *Converter) NotificationToAPINotification(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
notif *gtsmodel.Notification,
|
notif *gtsmodel.Notification,
|
||||||
filter bool,
|
|
||||||
) (*apimodel.Notification, error) {
|
) (*apimodel.Notification, error) {
|
||||||
// Ensure notif populated.
|
// Ensure notif populated.
|
||||||
if err := c.state.DB.PopulateNotification(ctx, notif); err != nil {
|
if err := c.state.DB.PopulateNotification(ctx, notif); err != nil {
|
||||||
|
|
@ -1882,27 +1851,14 @@ func (c *Converter) NotificationToAPINotification(
|
||||||
// Get status that triggered this notif, if set.
|
// Get status that triggered this notif, if set.
|
||||||
var apiStatus *apimodel.Status
|
var apiStatus *apimodel.Status
|
||||||
if notif.Status != nil {
|
if notif.Status != nil {
|
||||||
var filterCtx gtsmodel.FilterContext
|
|
||||||
|
|
||||||
if filter {
|
|
||||||
filterCtx = gtsmodel.FilterContextNotifications
|
|
||||||
}
|
|
||||||
|
|
||||||
apiStatus, err = c.StatusToAPIStatus(ctx,
|
apiStatus, err = c.StatusToAPIStatus(ctx,
|
||||||
notif.Status,
|
notif.Status,
|
||||||
notif.TargetAccount,
|
notif.TargetAccount,
|
||||||
filterCtx,
|
|
||||||
)
|
)
|
||||||
if err != nil && !errors.Is(err, ErrHideStatus) {
|
if err != nil {
|
||||||
return nil, gtserror.Newf("error converting status to api: %w", err)
|
return nil, gtserror.Newf("error converting status to api: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if apiStatus == nil {
|
|
||||||
// Notif filtered for this
|
|
||||||
// status, nothing to do.
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if apiStatus.Reblog != nil {
|
if apiStatus.Reblog != nil {
|
||||||
// Use the actual reblog status
|
// Use the actual reblog status
|
||||||
// for the notifications endpoint.
|
// for the notifications endpoint.
|
||||||
|
|
@ -1926,7 +1882,6 @@ func (c *Converter) ConversationToAPIConversation(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conversation *gtsmodel.Conversation,
|
conversation *gtsmodel.Conversation,
|
||||||
requester *gtsmodel.Account,
|
requester *gtsmodel.Account,
|
||||||
filters []*gtsmodel.Filter,
|
|
||||||
) (*apimodel.Conversation, error) {
|
) (*apimodel.Conversation, error) {
|
||||||
apiConversation := &apimodel.Conversation{
|
apiConversation := &apimodel.Conversation{
|
||||||
ID: conversation.ID,
|
ID: conversation.ID,
|
||||||
|
|
@ -1941,9 +1896,8 @@ func (c *Converter) ConversationToAPIConversation(
|
||||||
ctx,
|
ctx,
|
||||||
conversation.LastStatus,
|
conversation.LastStatus,
|
||||||
requester,
|
requester,
|
||||||
gtsmodel.FilterContextNotifications,
|
|
||||||
)
|
)
|
||||||
if err != nil && !errors.Is(err, ErrHideStatus) {
|
if err != nil {
|
||||||
return nil, gtserror.Newf(
|
return nil, gtserror.Newf(
|
||||||
"error converting status %s to API representation: %w",
|
"error converting status %s to API representation: %w",
|
||||||
conversation.LastStatus.ID,
|
conversation.LastStatus.ID,
|
||||||
|
|
@ -2209,7 +2163,6 @@ func (c *Converter) ReportToAdminAPIReport(ctx context.Context, r *gtsmodel.Repo
|
||||||
ctx,
|
ctx,
|
||||||
s,
|
s,
|
||||||
requestingAccount,
|
requestingAccount,
|
||||||
gtsmodel.FilterContextNone,
|
|
||||||
true, // Placehold unknown attachments.
|
true, // Placehold unknown attachments.
|
||||||
|
|
||||||
// Don't add note about
|
// Don't add note about
|
||||||
|
|
@ -2913,7 +2866,6 @@ func (c *Converter) InteractionReqToAPIInteractionReq(
|
||||||
ctx,
|
ctx,
|
||||||
req.Status,
|
req.Status,
|
||||||
requestingAcct,
|
requestingAcct,
|
||||||
gtsmodel.FilterContextNone,
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := gtserror.Newf("error converting interacted status: %w", err)
|
err := gtserror.Newf("error converting interacted status: %w", err)
|
||||||
|
|
@ -2926,7 +2878,6 @@ func (c *Converter) InteractionReqToAPIInteractionReq(
|
||||||
ctx,
|
ctx,
|
||||||
req.Reply,
|
req.Reply,
|
||||||
requestingAcct,
|
requestingAcct,
|
||||||
gtsmodel.FilterContextNone,
|
|
||||||
true, // Placehold unknown attachments.
|
true, // Placehold unknown attachments.
|
||||||
|
|
||||||
// Don't add note about pending;
|
// Don't add note about pending;
|
||||||
|
|
|
||||||
|
|
@ -24,12 +24,9 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
|
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/config"
|
"code.superseriousbusiness.org/gotosocial/internal/config"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/db"
|
"code.superseriousbusiness.org/gotosocial/internal/db"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/id"
|
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/typeutils"
|
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/util"
|
"code.superseriousbusiness.org/gotosocial/internal/util"
|
||||||
"code.superseriousbusiness.org/gotosocial/testrig"
|
"code.superseriousbusiness.org/gotosocial/testrig"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
@ -466,7 +463,7 @@ func (suite *InternalToFrontendTestSuite) TestLocalInstanceAccountToFrontendBloc
|
||||||
func (suite *InternalToFrontendTestSuite) TestStatusToFrontend() {
|
func (suite *InternalToFrontendTestSuite) TestStatusToFrontend() {
|
||||||
testStatus := suite.testStatuses["admin_account_status_1"]
|
testStatus := suite.testStatuses["admin_account_status_1"]
|
||||||
requestingAccount := suite.testAccounts["local_account_1"]
|
requestingAccount := suite.testAccounts["local_account_1"]
|
||||||
apiStatus, err := suite.typeconverter.StatusToAPIStatus(suite.T().Context(), testStatus, requestingAccount, gtsmodel.FilterContextNone)
|
apiStatus, err := suite.typeconverter.StatusToAPIStatus(suite.T().Context(), testStatus, requestingAccount)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
b, err := json.MarshalIndent(apiStatus, "", " ")
|
b, err := json.MarshalIndent(apiStatus, "", " ")
|
||||||
|
|
@ -629,7 +626,7 @@ func (suite *InternalToFrontendTestSuite) TestStatusToFrontendHTMLContentWarning
|
||||||
testStatus.ContentWarning = `<p>First paragraph of content warning</p><h4>Here's the title!</h4><p></p><p>Big boobs<br>Tee hee!<br><br>Some more text<br>And a bunch more<br><br>Hasta la victoria siempre!</p>`
|
testStatus.ContentWarning = `<p>First paragraph of content warning</p><h4>Here's the title!</h4><p></p><p>Big boobs<br>Tee hee!<br><br>Some more text<br>And a bunch more<br><br>Hasta la victoria siempre!</p>`
|
||||||
|
|
||||||
requestingAccount := suite.testAccounts["local_account_1"]
|
requestingAccount := suite.testAccounts["local_account_1"]
|
||||||
apiStatus, err := suite.typeconverter.StatusToAPIStatus(suite.T().Context(), testStatus, requestingAccount, gtsmodel.FilterContextNone)
|
apiStatus, err := suite.typeconverter.StatusToAPIStatus(suite.T().Context(), testStatus, requestingAccount)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
b, err := json.MarshalIndent(apiStatus, "", " ")
|
b, err := json.MarshalIndent(apiStatus, "", " ")
|
||||||
|
|
@ -795,7 +792,7 @@ func (suite *InternalToFrontendTestSuite) TestStatusToFrontendApplicationDeleted
|
||||||
}
|
}
|
||||||
|
|
||||||
requestingAccount := suite.testAccounts["local_account_1"]
|
requestingAccount := suite.testAccounts["local_account_1"]
|
||||||
apiStatus, err := suite.typeconverter.StatusToAPIStatus(ctx, testStatus, requestingAccount, gtsmodel.FilterContextNone)
|
apiStatus, err := suite.typeconverter.StatusToAPIStatus(ctx, testStatus, requestingAccount)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
b, err := json.MarshalIndent(apiStatus, "", " ")
|
b, err := json.MarshalIndent(apiStatus, "", " ")
|
||||||
|
|
@ -950,625 +947,11 @@ func (suite *InternalToFrontendTestSuite) TestStatusToFrontendApplicationDeleted
|
||||||
}`, string(b))
|
}`, string(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modify a fixture status into a status that should be filtered,
|
|
||||||
// and then filter it, returning the API status or any error from converting it.
|
|
||||||
func (suite *InternalToFrontendTestSuite) filteredStatusToFrontend(action gtsmodel.FilterAction, boost bool) (*apimodel.Status, error) {
|
|
||||||
ctx := suite.T().Context()
|
|
||||||
|
|
||||||
testStatus := suite.testStatuses["admin_account_status_1"]
|
|
||||||
testStatus.Content += " fnord"
|
|
||||||
testStatus.Text += " fnord"
|
|
||||||
|
|
||||||
if boost {
|
|
||||||
// Modify a fixture boost into a boost of the above status.
|
|
||||||
boostStatus := suite.testStatuses["admin_account_status_4"]
|
|
||||||
boostStatus.BoostOf = testStatus
|
|
||||||
boostStatus.BoostOfID = testStatus.ID
|
|
||||||
testStatus = boostStatus
|
|
||||||
}
|
|
||||||
|
|
||||||
requestingAccount := suite.testAccounts["local_account_1"]
|
|
||||||
|
|
||||||
expectedMatchingFilter := suite.testFilters["local_account_1_filter_1"]
|
|
||||||
expectedMatchingFilter.Action = action
|
|
||||||
|
|
||||||
err := suite.state.DB.UpdateFilter(ctx, expectedMatchingFilter, "action")
|
|
||||||
suite.NoError(err)
|
|
||||||
|
|
||||||
return suite.typeconverter.StatusToAPIStatus(
|
|
||||||
suite.T().Context(),
|
|
||||||
testStatus,
|
|
||||||
requestingAccount,
|
|
||||||
gtsmodel.FilterContextHome,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that a status which is filtered with a warn filter by the requesting user has `filtered` set correctly.
|
|
||||||
func (suite *InternalToFrontendTestSuite) TestWarnFilteredStatusToFrontend() {
|
|
||||||
apiStatus, err := suite.filteredStatusToFrontend(gtsmodel.FilterActionWarn, false)
|
|
||||||
suite.NoError(err)
|
|
||||||
|
|
||||||
b, err := json.MarshalIndent(apiStatus, "", " ")
|
|
||||||
suite.NoError(err)
|
|
||||||
|
|
||||||
suite.Equal(`{
|
|
||||||
"id": "01F8MH75CBF9JFX4ZAD54N0W0R",
|
|
||||||
"created_at": "2021-10-20T11:36:45.000Z",
|
|
||||||
"edited_at": null,
|
|
||||||
"in_reply_to_id": null,
|
|
||||||
"in_reply_to_account_id": null,
|
|
||||||
"sensitive": false,
|
|
||||||
"spoiler_text": "",
|
|
||||||
"visibility": "public",
|
|
||||||
"language": "en",
|
|
||||||
"uri": "http://localhost:8080/users/admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R",
|
|
||||||
"url": "http://localhost:8080/@admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R",
|
|
||||||
"replies_count": 1,
|
|
||||||
"reblogs_count": 0,
|
|
||||||
"favourites_count": 1,
|
|
||||||
"favourited": true,
|
|
||||||
"reblogged": false,
|
|
||||||
"muted": false,
|
|
||||||
"bookmarked": true,
|
|
||||||
"pinned": false,
|
|
||||||
"content": "\u003cp\u003ehello world! \u003ca href=\"http://localhost:8080/tags/welcome\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\"\u003e#\u003cspan\u003ewelcome\u003c/span\u003e\u003c/a\u003e ! first post on the instance :rainbow: !\u003c/p\u003e fnord",
|
|
||||||
"reblog": null,
|
|
||||||
"application": {
|
|
||||||
"name": "superseriousbusiness",
|
|
||||||
"website": "https://superserious.business"
|
|
||||||
},
|
|
||||||
"account": {
|
|
||||||
"id": "01F8MH17FWEB39HZJ76B6VXSKF",
|
|
||||||
"username": "admin",
|
|
||||||
"acct": "admin",
|
|
||||||
"display_name": "",
|
|
||||||
"locked": false,
|
|
||||||
"discoverable": true,
|
|
||||||
"bot": false,
|
|
||||||
"created_at": "2022-05-17T13:10:59.000Z",
|
|
||||||
"note": "",
|
|
||||||
"url": "http://localhost:8080/@admin",
|
|
||||||
"avatar": "",
|
|
||||||
"avatar_static": "",
|
|
||||||
"header": "http://localhost:8080/assets/default_header.webp",
|
|
||||||
"header_static": "http://localhost:8080/assets/default_header.webp",
|
|
||||||
"header_description": "Flat gray background (default header).",
|
|
||||||
"followers_count": 1,
|
|
||||||
"following_count": 1,
|
|
||||||
"statuses_count": 4,
|
|
||||||
"last_status_at": "2021-10-20",
|
|
||||||
"emojis": [],
|
|
||||||
"fields": [],
|
|
||||||
"enable_rss": true,
|
|
||||||
"roles": [
|
|
||||||
{
|
|
||||||
"id": "admin",
|
|
||||||
"name": "admin",
|
|
||||||
"color": ""
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"group": false
|
|
||||||
},
|
|
||||||
"media_attachments": [
|
|
||||||
{
|
|
||||||
"id": "01F8MH6NEM8D7527KZAECTCR76",
|
|
||||||
"type": "image",
|
|
||||||
"url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.jpg",
|
|
||||||
"text_url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.jpg",
|
|
||||||
"preview_url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/small/01F8MH6NEM8D7527KZAECTCR76.webp",
|
|
||||||
"remote_url": null,
|
|
||||||
"preview_remote_url": null,
|
|
||||||
"meta": {
|
|
||||||
"original": {
|
|
||||||
"width": 1200,
|
|
||||||
"height": 630,
|
|
||||||
"size": "1200x630",
|
|
||||||
"aspect": 1.9047619
|
|
||||||
},
|
|
||||||
"small": {
|
|
||||||
"width": 512,
|
|
||||||
"height": 268,
|
|
||||||
"size": "512x268",
|
|
||||||
"aspect": 1.9104477
|
|
||||||
},
|
|
||||||
"focus": {
|
|
||||||
"x": -0.5,
|
|
||||||
"y": 0.5
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"description": "Black and white image of some 50's style text saying: Welcome On Board",
|
|
||||||
"blurhash": "LIIE|gRj00WB-;j[t7j[4nWBj[Rj"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"mentions": [],
|
|
||||||
"tags": [
|
|
||||||
{
|
|
||||||
"name": "welcome",
|
|
||||||
"url": "http://localhost:8080/tags/welcome"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"emojis": [
|
|
||||||
{
|
|
||||||
"shortcode": "rainbow",
|
|
||||||
"url": "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/emoji/original/01F8MH9H8E4VG3KDYJR9EGPXCQ.png",
|
|
||||||
"static_url": "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/emoji/static/01F8MH9H8E4VG3KDYJR9EGPXCQ.png",
|
|
||||||
"visible_in_picker": true,
|
|
||||||
"category": "reactions"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"card": null,
|
|
||||||
"poll": null,
|
|
||||||
"text": "hello world! #welcome ! first post on the instance :rainbow: ! fnord",
|
|
||||||
"content_type": "text/plain",
|
|
||||||
"filtered": [
|
|
||||||
{
|
|
||||||
"filter": {
|
|
||||||
"id": "01HN26VM6KZTW1ANNRVSBMA461",
|
|
||||||
"title": "fnord",
|
|
||||||
"context": [
|
|
||||||
"home",
|
|
||||||
"public"
|
|
||||||
],
|
|
||||||
"expires_at": null,
|
|
||||||
"filter_action": "warn",
|
|
||||||
"keywords": [
|
|
||||||
{
|
|
||||||
"id": "01HN272TAVWAXX72ZX4M8JZ0PS",
|
|
||||||
"keyword": "fnord",
|
|
||||||
"whole_word": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"statuses": []
|
|
||||||
},
|
|
||||||
"keyword_matches": [
|
|
||||||
"fnord"
|
|
||||||
],
|
|
||||||
"status_matches": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"interaction_policy": {
|
|
||||||
"can_favourite": {
|
|
||||||
"automatic_approval": [
|
|
||||||
"public",
|
|
||||||
"me"
|
|
||||||
],
|
|
||||||
"manual_approval": [],
|
|
||||||
"always": [
|
|
||||||
"public",
|
|
||||||
"me"
|
|
||||||
],
|
|
||||||
"with_approval": []
|
|
||||||
},
|
|
||||||
"can_reply": {
|
|
||||||
"automatic_approval": [
|
|
||||||
"public",
|
|
||||||
"me"
|
|
||||||
],
|
|
||||||
"manual_approval": [],
|
|
||||||
"always": [
|
|
||||||
"public",
|
|
||||||
"me"
|
|
||||||
],
|
|
||||||
"with_approval": []
|
|
||||||
},
|
|
||||||
"can_reblog": {
|
|
||||||
"automatic_approval": [
|
|
||||||
"public",
|
|
||||||
"me"
|
|
||||||
],
|
|
||||||
"manual_approval": [],
|
|
||||||
"always": [
|
|
||||||
"public",
|
|
||||||
"me"
|
|
||||||
],
|
|
||||||
"with_approval": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`, string(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that a status which is filtered with a warn filter by the requesting user has `filtered` set correctly when boosted.
|
|
||||||
func (suite *InternalToFrontendTestSuite) TestWarnFilteredBoostToFrontend() {
|
|
||||||
apiStatus, err := suite.filteredStatusToFrontend(gtsmodel.FilterActionWarn, true)
|
|
||||||
suite.NoError(err)
|
|
||||||
|
|
||||||
b, err := json.MarshalIndent(apiStatus, "", " ")
|
|
||||||
suite.NoError(err)
|
|
||||||
|
|
||||||
suite.Equal(`{
|
|
||||||
"id": "01G36SF3V6Y6V5BF9P4R7PQG7G",
|
|
||||||
"created_at": "2021-10-20T10:41:37.000Z",
|
|
||||||
"edited_at": null,
|
|
||||||
"in_reply_to_id": null,
|
|
||||||
"in_reply_to_account_id": null,
|
|
||||||
"sensitive": false,
|
|
||||||
"spoiler_text": "",
|
|
||||||
"visibility": "public",
|
|
||||||
"language": null,
|
|
||||||
"uri": "http://localhost:8080/users/admin/statuses/01G36SF3V6Y6V5BF9P4R7PQG7G",
|
|
||||||
"url": "http://localhost:8080/@admin/statuses/01G36SF3V6Y6V5BF9P4R7PQG7G",
|
|
||||||
"replies_count": 0,
|
|
||||||
"reblogs_count": 0,
|
|
||||||
"favourites_count": 0,
|
|
||||||
"favourited": true,
|
|
||||||
"reblogged": false,
|
|
||||||
"muted": false,
|
|
||||||
"bookmarked": true,
|
|
||||||
"pinned": false,
|
|
||||||
"content": "",
|
|
||||||
"reblog": {
|
|
||||||
"id": "01F8MH75CBF9JFX4ZAD54N0W0R",
|
|
||||||
"created_at": "2021-10-20T11:36:45.000Z",
|
|
||||||
"edited_at": null,
|
|
||||||
"in_reply_to_id": null,
|
|
||||||
"in_reply_to_account_id": null,
|
|
||||||
"sensitive": false,
|
|
||||||
"spoiler_text": "",
|
|
||||||
"visibility": "public",
|
|
||||||
"language": "en",
|
|
||||||
"uri": "http://localhost:8080/users/admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R",
|
|
||||||
"url": "http://localhost:8080/@admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R",
|
|
||||||
"replies_count": 1,
|
|
||||||
"reblogs_count": 0,
|
|
||||||
"favourites_count": 1,
|
|
||||||
"favourited": true,
|
|
||||||
"reblogged": false,
|
|
||||||
"muted": false,
|
|
||||||
"bookmarked": true,
|
|
||||||
"pinned": false,
|
|
||||||
"content": "\u003cp\u003ehello world! \u003ca href=\"http://localhost:8080/tags/welcome\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\"\u003e#\u003cspan\u003ewelcome\u003c/span\u003e\u003c/a\u003e ! first post on the instance :rainbow: !\u003c/p\u003e fnord",
|
|
||||||
"reblog": null,
|
|
||||||
"application": {
|
|
||||||
"name": "superseriousbusiness",
|
|
||||||
"website": "https://superserious.business"
|
|
||||||
},
|
|
||||||
"account": {
|
|
||||||
"id": "01F8MH1H7YV1Z7D2C8K2730QBF",
|
|
||||||
"username": "the_mighty_zork",
|
|
||||||
"acct": "the_mighty_zork",
|
|
||||||
"display_name": "original zork (he/they)",
|
|
||||||
"locked": false,
|
|
||||||
"discoverable": true,
|
|
||||||
"bot": false,
|
|
||||||
"created_at": "2022-05-20T11:09:18.000Z",
|
|
||||||
"note": "\u003cp\u003ehey yo this is my profile!\u003c/p\u003e",
|
|
||||||
"url": "http://localhost:8080/@the_mighty_zork",
|
|
||||||
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
|
|
||||||
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
|
|
||||||
"avatar_description": "a green goblin looking nasty",
|
|
||||||
"avatar_media_id": "01F8MH58A357CV5K7R7TJMSH6S",
|
|
||||||
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
|
|
||||||
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
|
|
||||||
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
|
|
||||||
"header_media_id": "01PFPMWK2FF0D9WMHEJHR07C3Q",
|
|
||||||
"followers_count": 2,
|
|
||||||
"following_count": 2,
|
|
||||||
"statuses_count": 9,
|
|
||||||
"last_status_at": "2024-11-01",
|
|
||||||
"emojis": [],
|
|
||||||
"fields": [],
|
|
||||||
"enable_rss": true,
|
|
||||||
"group": false
|
|
||||||
},
|
|
||||||
"media_attachments": [
|
|
||||||
{
|
|
||||||
"id": "01F8MH6NEM8D7527KZAECTCR76",
|
|
||||||
"type": "image",
|
|
||||||
"url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.jpg",
|
|
||||||
"text_url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.jpg",
|
|
||||||
"preview_url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/small/01F8MH6NEM8D7527KZAECTCR76.webp",
|
|
||||||
"remote_url": null,
|
|
||||||
"preview_remote_url": null,
|
|
||||||
"meta": {
|
|
||||||
"original": {
|
|
||||||
"width": 1200,
|
|
||||||
"height": 630,
|
|
||||||
"size": "1200x630",
|
|
||||||
"aspect": 1.9047619
|
|
||||||
},
|
|
||||||
"small": {
|
|
||||||
"width": 512,
|
|
||||||
"height": 268,
|
|
||||||
"size": "512x268",
|
|
||||||
"aspect": 1.9104477
|
|
||||||
},
|
|
||||||
"focus": {
|
|
||||||
"x": -0.5,
|
|
||||||
"y": 0.5
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"description": "Black and white image of some 50's style text saying: Welcome On Board",
|
|
||||||
"blurhash": "LIIE|gRj00WB-;j[t7j[4nWBj[Rj"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"mentions": [],
|
|
||||||
"tags": [
|
|
||||||
{
|
|
||||||
"name": "welcome",
|
|
||||||
"url": "http://localhost:8080/tags/welcome"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"emojis": [
|
|
||||||
{
|
|
||||||
"shortcode": "rainbow",
|
|
||||||
"url": "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/emoji/original/01F8MH9H8E4VG3KDYJR9EGPXCQ.png",
|
|
||||||
"static_url": "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/emoji/static/01F8MH9H8E4VG3KDYJR9EGPXCQ.png",
|
|
||||||
"visible_in_picker": true,
|
|
||||||
"category": "reactions"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"card": null,
|
|
||||||
"poll": null,
|
|
||||||
"text": "hello world! #welcome ! first post on the instance :rainbow: ! fnord",
|
|
||||||
"content_type": "text/plain",
|
|
||||||
"filtered": [
|
|
||||||
{
|
|
||||||
"filter": {
|
|
||||||
"id": "01HN26VM6KZTW1ANNRVSBMA461",
|
|
||||||
"title": "fnord",
|
|
||||||
"context": [
|
|
||||||
"home",
|
|
||||||
"public"
|
|
||||||
],
|
|
||||||
"expires_at": null,
|
|
||||||
"filter_action": "warn",
|
|
||||||
"keywords": [
|
|
||||||
{
|
|
||||||
"id": "01HN272TAVWAXX72ZX4M8JZ0PS",
|
|
||||||
"keyword": "fnord",
|
|
||||||
"whole_word": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"statuses": []
|
|
||||||
},
|
|
||||||
"keyword_matches": [
|
|
||||||
"fnord"
|
|
||||||
],
|
|
||||||
"status_matches": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"interaction_policy": {
|
|
||||||
"can_favourite": {
|
|
||||||
"automatic_approval": [
|
|
||||||
"public",
|
|
||||||
"me"
|
|
||||||
],
|
|
||||||
"manual_approval": [],
|
|
||||||
"always": [
|
|
||||||
"public",
|
|
||||||
"me"
|
|
||||||
],
|
|
||||||
"with_approval": []
|
|
||||||
},
|
|
||||||
"can_reply": {
|
|
||||||
"automatic_approval": [
|
|
||||||
"public",
|
|
||||||
"me"
|
|
||||||
],
|
|
||||||
"manual_approval": [],
|
|
||||||
"always": [
|
|
||||||
"public",
|
|
||||||
"me"
|
|
||||||
],
|
|
||||||
"with_approval": []
|
|
||||||
},
|
|
||||||
"can_reblog": {
|
|
||||||
"automatic_approval": [
|
|
||||||
"public",
|
|
||||||
"me"
|
|
||||||
],
|
|
||||||
"manual_approval": [],
|
|
||||||
"always": [
|
|
||||||
"public",
|
|
||||||
"me"
|
|
||||||
],
|
|
||||||
"with_approval": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"application": {
|
|
||||||
"name": "superseriousbusiness",
|
|
||||||
"website": "https://superserious.business"
|
|
||||||
},
|
|
||||||
"account": {
|
|
||||||
"id": "01F8MH17FWEB39HZJ76B6VXSKF",
|
|
||||||
"username": "admin",
|
|
||||||
"acct": "admin",
|
|
||||||
"display_name": "",
|
|
||||||
"locked": false,
|
|
||||||
"discoverable": true,
|
|
||||||
"bot": false,
|
|
||||||
"created_at": "2022-05-17T13:10:59.000Z",
|
|
||||||
"note": "",
|
|
||||||
"url": "http://localhost:8080/@admin",
|
|
||||||
"avatar": "",
|
|
||||||
"avatar_static": "",
|
|
||||||
"header": "http://localhost:8080/assets/default_header.webp",
|
|
||||||
"header_static": "http://localhost:8080/assets/default_header.webp",
|
|
||||||
"header_description": "Flat gray background (default header).",
|
|
||||||
"followers_count": 1,
|
|
||||||
"following_count": 1,
|
|
||||||
"statuses_count": 4,
|
|
||||||
"last_status_at": "2021-10-20",
|
|
||||||
"emojis": [],
|
|
||||||
"fields": [],
|
|
||||||
"enable_rss": true,
|
|
||||||
"roles": [
|
|
||||||
{
|
|
||||||
"id": "admin",
|
|
||||||
"name": "admin",
|
|
||||||
"color": ""
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"group": false
|
|
||||||
},
|
|
||||||
"media_attachments": [],
|
|
||||||
"mentions": [],
|
|
||||||
"tags": [],
|
|
||||||
"emojis": [],
|
|
||||||
"card": null,
|
|
||||||
"poll": null,
|
|
||||||
"filtered": [
|
|
||||||
{
|
|
||||||
"filter": {
|
|
||||||
"id": "01HN26VM6KZTW1ANNRVSBMA461",
|
|
||||||
"title": "fnord",
|
|
||||||
"context": [
|
|
||||||
"home",
|
|
||||||
"public"
|
|
||||||
],
|
|
||||||
"expires_at": null,
|
|
||||||
"filter_action": "warn",
|
|
||||||
"keywords": [
|
|
||||||
{
|
|
||||||
"id": "01HN272TAVWAXX72ZX4M8JZ0PS",
|
|
||||||
"keyword": "fnord",
|
|
||||||
"whole_word": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"statuses": []
|
|
||||||
},
|
|
||||||
"keyword_matches": [
|
|
||||||
"fnord"
|
|
||||||
],
|
|
||||||
"status_matches": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"interaction_policy": {
|
|
||||||
"can_favourite": {
|
|
||||||
"automatic_approval": [
|
|
||||||
"public",
|
|
||||||
"me"
|
|
||||||
],
|
|
||||||
"manual_approval": [],
|
|
||||||
"always": [
|
|
||||||
"public",
|
|
||||||
"me"
|
|
||||||
],
|
|
||||||
"with_approval": []
|
|
||||||
},
|
|
||||||
"can_reply": {
|
|
||||||
"automatic_approval": [
|
|
||||||
"public",
|
|
||||||
"me"
|
|
||||||
],
|
|
||||||
"manual_approval": [],
|
|
||||||
"always": [
|
|
||||||
"public",
|
|
||||||
"me"
|
|
||||||
],
|
|
||||||
"with_approval": []
|
|
||||||
},
|
|
||||||
"can_reblog": {
|
|
||||||
"automatic_approval": [
|
|
||||||
"public",
|
|
||||||
"me"
|
|
||||||
],
|
|
||||||
"manual_approval": [],
|
|
||||||
"always": [
|
|
||||||
"public",
|
|
||||||
"me"
|
|
||||||
],
|
|
||||||
"with_approval": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`, string(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that a status which is filtered with a hide filter by the requesting user results in the ErrHideStatus error.
|
|
||||||
func (suite *InternalToFrontendTestSuite) TestHideFilteredStatusToFrontend() {
|
|
||||||
_, err := suite.filteredStatusToFrontend(gtsmodel.FilterActionHide, false)
|
|
||||||
suite.ErrorIs(err, typeutils.ErrHideStatus)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that a status which is filtered with a hide filter by the requesting user results in the ErrHideStatus error for a boost of that status.
|
|
||||||
func (suite *InternalToFrontendTestSuite) TestHideFilteredBoostToFrontend() {
|
|
||||||
_, err := suite.filteredStatusToFrontend(gtsmodel.FilterActionHide, true)
|
|
||||||
suite.ErrorIs(err, typeutils.ErrHideStatus)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that a hashtag filter for a hashtag in Mastodon HTML content works the way most users would expect.
|
|
||||||
func (suite *InternalToFrontendTestSuite) testHashtagFilteredStatusToFrontend(wholeWord bool, boost bool) {
|
|
||||||
ctx := suite.T().Context()
|
|
||||||
|
|
||||||
testStatus := new(gtsmodel.Status)
|
|
||||||
*testStatus = *suite.testStatuses["admin_account_status_1"]
|
|
||||||
testStatus.Content = `<p>doggo doggin' it</p><p><a href="https://example.test/tags/dogsofmastodon" class="mention hashtag" rel="tag nofollow noreferrer noopener" target="_blank">#<span>dogsofmastodon</span></a></p>`
|
|
||||||
|
|
||||||
if boost {
|
|
||||||
boost, err := suite.typeconverter.StatusToBoost(
|
|
||||||
suite.T().Context(),
|
|
||||||
testStatus,
|
|
||||||
suite.testAccounts["admin_account"],
|
|
||||||
"",
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
suite.FailNow(err.Error())
|
|
||||||
}
|
|
||||||
testStatus = boost
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
|
|
||||||
requestingAccount := suite.testAccounts["local_account_1"]
|
|
||||||
|
|
||||||
filter := >smodel.Filter{
|
|
||||||
ID: id.NewULID(),
|
|
||||||
Title: id.NewULID(),
|
|
||||||
AccountID: requestingAccount.ID,
|
|
||||||
Action: gtsmodel.FilterActionWarn,
|
|
||||||
Contexts: gtsmodel.FilterContexts(gtsmodel.FilterContextHome),
|
|
||||||
}
|
|
||||||
|
|
||||||
filterKeyword := >smodel.FilterKeyword{
|
|
||||||
ID: id.NewULID(),
|
|
||||||
FilterID: filter.ID,
|
|
||||||
Keyword: "#dogsofmastodon",
|
|
||||||
WholeWord: &wholeWord,
|
|
||||||
}
|
|
||||||
|
|
||||||
filter.KeywordIDs = []string{filterKeyword.ID}
|
|
||||||
|
|
||||||
err = suite.state.DB.PutFilterKeyword(ctx, filterKeyword)
|
|
||||||
suite.NoError(err)
|
|
||||||
|
|
||||||
err = suite.state.DB.PutFilter(ctx, filter)
|
|
||||||
suite.NoError(err)
|
|
||||||
|
|
||||||
apiStatus, err := suite.typeconverter.StatusToAPIStatus(
|
|
||||||
suite.T().Context(),
|
|
||||||
testStatus,
|
|
||||||
requestingAccount,
|
|
||||||
gtsmodel.FilterContextHome,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
suite.FailNow(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
suite.NotEmpty(apiStatus.Filtered)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (suite *InternalToFrontendTestSuite) TestHashtagWholeWordFilteredStatusToFrontend() {
|
|
||||||
suite.testHashtagFilteredStatusToFrontend(true, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (suite *InternalToFrontendTestSuite) TestHashtagWholeWordFilteredBoostToFrontend() {
|
|
||||||
suite.testHashtagFilteredStatusToFrontend(true, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (suite *InternalToFrontendTestSuite) TestHashtagAnywhereFilteredStatusToFrontend() {
|
|
||||||
suite.testHashtagFilteredStatusToFrontend(false, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (suite *InternalToFrontendTestSuite) TestHashtagAnywhereFilteredBoostToFrontend() {
|
|
||||||
suite.testHashtagFilteredStatusToFrontend(false, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (suite *InternalToFrontendTestSuite) TestStatusToFrontendUnknownAttachments() {
|
func (suite *InternalToFrontendTestSuite) TestStatusToFrontendUnknownAttachments() {
|
||||||
testStatus := suite.testStatuses["remote_account_2_status_1"]
|
testStatus := suite.testStatuses["remote_account_2_status_1"]
|
||||||
requestingAccount := suite.testAccounts["admin_account"]
|
requestingAccount := suite.testAccounts["admin_account"]
|
||||||
|
|
||||||
apiStatus, err := suite.typeconverter.StatusToAPIStatus(suite.T().Context(), testStatus, requestingAccount, gtsmodel.FilterContextNone)
|
apiStatus, err := suite.typeconverter.StatusToAPIStatus(suite.T().Context(), testStatus, requestingAccount)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
b, err := json.MarshalIndent(apiStatus, "", " ")
|
b, err := json.MarshalIndent(apiStatus, "", " ")
|
||||||
|
|
@ -1895,7 +1278,7 @@ func (suite *InternalToFrontendTestSuite) TestStatusToFrontendUnknownLanguage()
|
||||||
*testStatus = *suite.testStatuses["admin_account_status_1"]
|
*testStatus = *suite.testStatuses["admin_account_status_1"]
|
||||||
testStatus.Language = ""
|
testStatus.Language = ""
|
||||||
requestingAccount := suite.testAccounts["local_account_1"]
|
requestingAccount := suite.testAccounts["local_account_1"]
|
||||||
apiStatus, err := suite.typeconverter.StatusToAPIStatus(suite.T().Context(), testStatus, requestingAccount, gtsmodel.FilterContextNone)
|
apiStatus, err := suite.typeconverter.StatusToAPIStatus(suite.T().Context(), testStatus, requestingAccount)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
b, err := json.MarshalIndent(apiStatus, "", " ")
|
b, err := json.MarshalIndent(apiStatus, "", " ")
|
||||||
|
|
@ -2056,7 +1439,7 @@ func (suite *InternalToFrontendTestSuite) TestStatusToFrontendPartialInteraction
|
||||||
*testStatus = *suite.testStatuses["local_account_1_status_3"]
|
*testStatus = *suite.testStatuses["local_account_1_status_3"]
|
||||||
testStatus.Language = ""
|
testStatus.Language = ""
|
||||||
requestingAccount := suite.testAccounts["admin_account"]
|
requestingAccount := suite.testAccounts["admin_account"]
|
||||||
apiStatus, err := suite.typeconverter.StatusToAPIStatus(suite.T().Context(), testStatus, requestingAccount, gtsmodel.FilterContextNone)
|
apiStatus, err := suite.typeconverter.StatusToAPIStatus(suite.T().Context(), testStatus, requestingAccount)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
b, err := json.MarshalIndent(apiStatus, "", " ")
|
b, err := json.MarshalIndent(apiStatus, "", " ")
|
||||||
|
|
@ -2169,7 +1552,6 @@ func (suite *InternalToFrontendTestSuite) TestStatusToAPIStatusPendingApproval()
|
||||||
suite.T().Context(),
|
suite.T().Context(),
|
||||||
testStatus,
|
testStatus,
|
||||||
requestingAccount,
|
requestingAccount,
|
||||||
gtsmodel.FilterContextNone,
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
suite.FailNow(err.Error())
|
suite.FailNow(err.Error())
|
||||||
|
|
@ -3936,7 +3318,6 @@ func (suite *InternalToFrontendTestSuite) TestConversationToAPISelfConvo() {
|
||||||
ctx = suite.T().Context()
|
ctx = suite.T().Context()
|
||||||
requester = suite.testAccounts["local_account_1"]
|
requester = suite.testAccounts["local_account_1"]
|
||||||
lastStatus = suite.testStatuses["local_account_1_status_1"]
|
lastStatus = suite.testStatuses["local_account_1_status_1"]
|
||||||
filters []*gtsmodel.Filter = nil
|
|
||||||
)
|
)
|
||||||
|
|
||||||
convo := >smodel.Conversation{
|
convo := >smodel.Conversation{
|
||||||
|
|
@ -3954,7 +3335,6 @@ func (suite *InternalToFrontendTestSuite) TestConversationToAPISelfConvo() {
|
||||||
ctx,
|
ctx,
|
||||||
convo,
|
convo,
|
||||||
requester,
|
requester,
|
||||||
filters,
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
suite.FailNow(err.Error())
|
suite.FailNow(err.Error())
|
||||||
|
|
@ -4109,7 +3489,6 @@ func (suite *InternalToFrontendTestSuite) TestConversationToAPI() {
|
||||||
ctx = suite.T().Context()
|
ctx = suite.T().Context()
|
||||||
requester = suite.testAccounts["local_account_1"]
|
requester = suite.testAccounts["local_account_1"]
|
||||||
lastStatus = suite.testStatuses["local_account_1_status_1"]
|
lastStatus = suite.testStatuses["local_account_1_status_1"]
|
||||||
filters []*gtsmodel.Filter = nil
|
|
||||||
)
|
)
|
||||||
|
|
||||||
convo := >smodel.Conversation{
|
convo := >smodel.Conversation{
|
||||||
|
|
@ -4129,7 +3508,6 @@ func (suite *InternalToFrontendTestSuite) TestConversationToAPI() {
|
||||||
ctx,
|
ctx,
|
||||||
convo,
|
convo,
|
||||||
requester,
|
requester,
|
||||||
filters,
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
suite.FailNow(err.Error())
|
suite.FailNow(err.Error())
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ import (
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/federation"
|
"code.superseriousbusiness.org/gotosocial/internal/federation"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/filter/status"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/media"
|
"code.superseriousbusiness.org/gotosocial/internal/media"
|
||||||
|
|
@ -126,6 +127,7 @@ func (suite *RealSenderStandardTestSuite) SetupTest() {
|
||||||
visibility.NewFilter(&suite.state),
|
visibility.NewFilter(&suite.state),
|
||||||
mutes.NewFilter(&suite.state),
|
mutes.NewFilter(&suite.state),
|
||||||
interaction.NewFilter(&suite.state),
|
interaction.NewFilter(&suite.state),
|
||||||
|
status.NewFilter(&suite.state),
|
||||||
)
|
)
|
||||||
testrig.StartWorkers(&suite.state, suite.processor.Workers())
|
testrig.StartWorkers(&suite.state, suite.processor.Workers())
|
||||||
|
|
||||||
|
|
@ -190,7 +192,7 @@ func (suite *RealSenderStandardTestSuite) simulatePushNotification(
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
apiNotif, err := suite.typeconverter.NotificationToAPINotification(ctx, notification, false)
|
apiNotif, err := suite.typeconverter.NotificationToAPINotification(ctx, notification)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
// Send the push notification.
|
// Send the push notification.
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/federation"
|
"code.superseriousbusiness.org/gotosocial/internal/federation"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/filter/status"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/media"
|
"code.superseriousbusiness.org/gotosocial/internal/media"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/processing"
|
"code.superseriousbusiness.org/gotosocial/internal/processing"
|
||||||
|
|
@ -59,5 +60,6 @@ func NewTestProcessor(
|
||||||
visibility.NewFilter(state),
|
visibility.NewFilter(state),
|
||||||
mutes.NewFilter(state),
|
mutes.NewFilter(state),
|
||||||
interaction.NewFilter(state),
|
interaction.NewFilter(state),
|
||||||
|
status.NewFilter(state),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/email"
|
"code.superseriousbusiness.org/gotosocial/internal/email"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
|
||||||
|
"code.superseriousbusiness.org/gotosocial/internal/filter/status"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/processing"
|
"code.superseriousbusiness.org/gotosocial/internal/processing"
|
||||||
"code.superseriousbusiness.org/gotosocial/internal/processing/common"
|
"code.superseriousbusiness.org/gotosocial/internal/processing/common"
|
||||||
|
|
@ -51,6 +52,7 @@ type TestStructs struct {
|
||||||
WebPushSender *WebPushMockSender
|
WebPushSender *WebPushMockSender
|
||||||
TransportController transport.Controller
|
TransportController transport.Controller
|
||||||
InteractionFilter *interaction.Filter
|
InteractionFilter *interaction.Filter
|
||||||
|
StatusFilter *status.Filter
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetupTestStructs(
|
func SetupTestStructs(
|
||||||
|
|
@ -71,6 +73,7 @@ func SetupTestStructs(
|
||||||
visFilter := visibility.NewFilter(&state)
|
visFilter := visibility.NewFilter(&state)
|
||||||
muteFilter := mutes.NewFilter(&state)
|
muteFilter := mutes.NewFilter(&state)
|
||||||
intFilter := interaction.NewFilter(&state)
|
intFilter := interaction.NewFilter(&state)
|
||||||
|
statusFilter := status.NewFilter(&state)
|
||||||
|
|
||||||
httpClient := NewMockHTTPClient(nil, rMediaPath)
|
httpClient := NewMockHTTPClient(nil, rMediaPath)
|
||||||
httpClient.TestRemotePeople = NewTestFediPeople()
|
httpClient.TestRemotePeople = NewTestFediPeople()
|
||||||
|
|
@ -90,6 +93,7 @@ func SetupTestStructs(
|
||||||
federator,
|
federator,
|
||||||
visFilter,
|
visFilter,
|
||||||
muteFilter,
|
muteFilter,
|
||||||
|
statusFilter,
|
||||||
)
|
)
|
||||||
|
|
||||||
processor := processing.NewProcessor(
|
processor := processing.NewProcessor(
|
||||||
|
|
@ -105,6 +109,7 @@ func SetupTestStructs(
|
||||||
visFilter,
|
visFilter,
|
||||||
muteFilter,
|
muteFilter,
|
||||||
intFilter,
|
intFilter,
|
||||||
|
statusFilter,
|
||||||
)
|
)
|
||||||
|
|
||||||
StartWorkers(&state, processor.Workers())
|
StartWorkers(&state, processor.Workers())
|
||||||
|
|
@ -122,6 +127,7 @@ func SetupTestStructs(
|
||||||
WebPushSender: webPushSender,
|
WebPushSender: webPushSender,
|
||||||
TransportController: transportController,
|
TransportController: transportController,
|
||||||
InteractionFilter: intFilter,
|
InteractionFilter: intFilter,
|
||||||
|
StatusFilter: statusFilter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue