diff options
Diffstat (limited to 'internal/filter')
| -rw-r--r-- | internal/filter/interaction/interactable.go | 58 | ||||
| -rw-r--r-- | internal/filter/interaction/interactable_test.go | 207 |
2 files changed, 235 insertions, 30 deletions
diff --git a/internal/filter/interaction/interactable.go b/internal/filter/interaction/interactable.go index 2052ac78e..38a43f23d 100644 --- a/internal/filter/interaction/interactable.go +++ b/internal/filter/interaction/interactable.go @@ -84,8 +84,8 @@ func (f *Filter) StatusLikeable( } switch { - // If status has policy set, check against that. - case status.InteractionPolicy != nil: + // If status has canLike sub-policy set, check against that. + case status.InteractionPolicy != nil && status.InteractionPolicy.CanLike != nil: return f.checkPolicy( ctx, requester, @@ -95,19 +95,18 @@ func (f *Filter) StatusLikeable( // If status is local and has no policy set, // check against the default policy for this - // visibility, as we're interaction-policy aware. + // visibility, as we're canLike sub-policy aware. case *status.Local: - policy := gtsmodel.DefaultInteractionPolicyFor(status.Visibility) return f.checkPolicy( ctx, requester, status, - policy.CanLike, + gtsmodel.DefaultCanLikeFor(status.Visibility), ) // Otherwise, assume the status is from an // instance that does not use / does not care - // about interaction policies, and just return OK. + // about canLike sub-policy, and just return OK. default: return >smodel.PolicyCheckResult{ Permission: gtsmodel.PolicyPermissionAutomaticApproval, @@ -235,8 +234,8 @@ func (f *Filter) StatusReplyable( } switch { - // If status has policy set, check against that. - case status.InteractionPolicy != nil: + // If status has canReply sub-policy set, check against that. + case status.InteractionPolicy != nil && status.InteractionPolicy.CanReply != nil: return f.checkPolicy( ctx, requester, @@ -245,20 +244,19 @@ func (f *Filter) StatusReplyable( ) // If status is local and has no policy set, - // check against the default policy for this - // visibility, as we're interaction-policy aware. + // check against the default canReply for this + // visibility, as we're canReply sub-policy aware. case *status.Local: - policy := gtsmodel.DefaultInteractionPolicyFor(status.Visibility) return f.checkPolicy( ctx, requester, status, - policy.CanReply, + gtsmodel.DefaultCanReplyFor(status.Visibility), ) // Otherwise, assume the status is from an // instance that does not use / does not care - // about interaction policies, and just return OK. + // about canReply sub-policy, and just return OK. default: return >smodel.PolicyCheckResult{ Permission: gtsmodel.PolicyPermissionAutomaticApproval, @@ -297,8 +295,8 @@ func (f *Filter) StatusBoostable( } switch { - // If status has policy set, check against that. - case status.InteractionPolicy != nil: + // If status has canAnnounce sub-policy set, check against that. + case status.InteractionPolicy != nil && status.InteractionPolicy.CanAnnounce != nil: return f.checkPolicy( ctx, requester, @@ -319,7 +317,7 @@ func (f *Filter) StatusBoostable( ) // Status is from an instance that does not use - // or does not care about interaction policies. + // or does not care about canAnnounce sub-policy. // We can boost it if it's unlisted or public. case status.Visibility == gtsmodel.VisibilityPublic || status.Visibility == gtsmodel.VisibilityUnlocked: @@ -340,7 +338,7 @@ func (f *Filter) checkPolicy( ctx context.Context, requester *gtsmodel.Account, status *gtsmodel.Status, - rules gtsmodel.PolicyRules, + rules *gtsmodel.PolicyRules, ) (*gtsmodel.PolicyCheckResult, error) { // Wrap context to be able to @@ -349,8 +347,8 @@ func (f *Filter) checkPolicy( fctx.Context = ctx // Check if requester matches a PolicyValue - // to be always allowed to do this. - matchAlways, matchAlwaysValue, err := f.matchPolicy(fctx, + // to be automatically approved for this. + matchAutomatic, matchAutomaticValue, err := f.matchPolicy(fctx, requester, status, rules.AutomaticApproval, @@ -360,40 +358,40 @@ func (f *Filter) checkPolicy( } // Check if requester matches a PolicyValue - // to be allowed to do this pending approval. - matchWithApproval, _, err := f.matchPolicy(fctx, + // to be manually approved for this. + matchManual, _, err := f.matchPolicy(fctx, requester, status, rules.ManualApproval, ) if err != nil { - return nil, gtserror.Newf("error checking policy approval match: %w", err) + return nil, gtserror.Newf("error checking policy match: %w", err) } switch { // Prefer explicit match, - // prioritizing "always". - case matchAlways == explicit: + // prioritizing automatic. + case matchAutomatic == explicit: return >smodel.PolicyCheckResult{ Permission: gtsmodel.PolicyPermissionAutomaticApproval, - PermissionMatchedOn: &matchAlwaysValue, + PermissionMatchedOn: &matchAutomaticValue, }, nil - case matchWithApproval == explicit: + case matchManual == explicit: return >smodel.PolicyCheckResult{ Permission: gtsmodel.PolicyPermissionManualApproval, }, nil // Then try implicit match, - // prioritizing "always". - case matchAlways == implicit: + // prioritizing automatic. + case matchAutomatic == implicit: return >smodel.PolicyCheckResult{ Permission: gtsmodel.PolicyPermissionAutomaticApproval, - PermissionMatchedOn: &matchAlwaysValue, + PermissionMatchedOn: &matchAutomaticValue, }, nil - case matchWithApproval == implicit: + case matchManual == implicit: return >smodel.PolicyCheckResult{ Permission: gtsmodel.PolicyPermissionManualApproval, }, nil diff --git a/internal/filter/interaction/interactable_test.go b/internal/filter/interaction/interactable_test.go new file mode 100644 index 000000000..9eede31c0 --- /dev/null +++ b/internal/filter/interaction/interactable_test.go @@ -0,0 +1,207 @@ +// 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 interaction_test + +import ( + "strconv" + "testing" + + "code.superseriousbusiness.org/gotosocial/internal/gtsmodel" + "code.superseriousbusiness.org/gotosocial/testrig" + "github.com/stretchr/testify/suite" +) + +const ( + rMediaPath = "../../../testrig/media" + rTemplatePath = "../../../web/template" +) + +type InteractionTestSuite struct { + suite.Suite + + testStatuses map[string]*gtsmodel.Status + testAccounts map[string]*gtsmodel.Account +} + +func (suite *InteractionTestSuite) SetupSuite() { + testrig.InitTestConfig() + testrig.InitTestLog() + + suite.testStatuses = testrig.NewTestStatuses() + suite.testAccounts = testrig.NewTestAccounts() +} + +func (suite *InteractionTestSuite) TestInteractable() { + testStructs := testrig.SetupTestStructs(rMediaPath, rTemplatePath) + defer testrig.TearDownTestStructs(testStructs) + + // Take zork's introduction post + // as the base post for these tests. + modelStatus := suite.testStatuses["local_account_1_status_1"] + + ctx := suite.T().Context() + for i, test := range []struct { + policy *gtsmodel.InteractionPolicy + account *gtsmodel.Account + likeable gtsmodel.PolicyPermission + replyable gtsmodel.PolicyPermission + boostable gtsmodel.PolicyPermission + }{ + { + // Nil policy. Should all be fine as + // it will fall back to the default then. + policy: nil, + account: suite.testAccounts["admin_account"], + likeable: gtsmodel.PolicyPermissionAutomaticApproval, + replyable: gtsmodel.PolicyPermissionAutomaticApproval, + boostable: gtsmodel.PolicyPermissionAutomaticApproval, + }, + { + // Nil canLike, everything else + // restricted to author only. + // Only the nil sub-policy should be OK. + policy: >smodel.InteractionPolicy{ + CanLike: nil, + CanReply: >smodel.PolicyRules{ + AutomaticApproval: gtsmodel.PolicyValues{ + gtsmodel.PolicyValueAuthor, + }, + }, + CanAnnounce: >smodel.PolicyRules{ + AutomaticApproval: gtsmodel.PolicyValues{ + gtsmodel.PolicyValueAuthor, + }, + }, + }, + account: suite.testAccounts["admin_account"], + likeable: gtsmodel.PolicyPermissionAutomaticApproval, + replyable: gtsmodel.PolicyPermissionForbidden, + boostable: gtsmodel.PolicyPermissionForbidden, + }, + { + // All restricted it's the author's own + // account checking, so all should be fine. + policy: >smodel.InteractionPolicy{ + CanLike: >smodel.PolicyRules{ + AutomaticApproval: gtsmodel.PolicyValues{ + gtsmodel.PolicyValueAuthor, + }, + }, + CanReply: >smodel.PolicyRules{ + AutomaticApproval: gtsmodel.PolicyValues{ + gtsmodel.PolicyValueAuthor, + }, + }, + CanAnnounce: >smodel.PolicyRules{ + AutomaticApproval: gtsmodel.PolicyValues{ + gtsmodel.PolicyValueAuthor, + }, + }, + }, + account: suite.testAccounts["local_account_1"], + likeable: gtsmodel.PolicyPermissionAutomaticApproval, + replyable: gtsmodel.PolicyPermissionAutomaticApproval, + boostable: gtsmodel.PolicyPermissionAutomaticApproval, + }, + { + // Followers can like automatically, + // everything else requires manual approval. + policy: >smodel.InteractionPolicy{ + CanLike: >smodel.PolicyRules{ + AutomaticApproval: gtsmodel.PolicyValues{ + gtsmodel.PolicyValueAuthor, + gtsmodel.PolicyValueFollowers, + }, + ManualApproval: gtsmodel.PolicyValues{ + gtsmodel.PolicyValuePublic, + }, + }, + CanReply: >smodel.PolicyRules{ + AutomaticApproval: gtsmodel.PolicyValues{ + gtsmodel.PolicyValueAuthor, + }, + ManualApproval: gtsmodel.PolicyValues{ + gtsmodel.PolicyValuePublic, + }, + }, + CanAnnounce: >smodel.PolicyRules{ + AutomaticApproval: gtsmodel.PolicyValues{ + gtsmodel.PolicyValueAuthor, + }, + ManualApproval: gtsmodel.PolicyValues{ + gtsmodel.PolicyValuePublic, + }, + }, + }, + account: suite.testAccounts["admin_account"], + likeable: gtsmodel.PolicyPermissionAutomaticApproval, + replyable: gtsmodel.PolicyPermissionManualApproval, + boostable: gtsmodel.PolicyPermissionManualApproval, + }, + } { + // Copy model status. + status := new(gtsmodel.Status) + *status = *modelStatus + + // Set test policy on it. + status.InteractionPolicy = test.policy + + // Check likeableRes. + likeableRes, err := testStructs.InteractionFilter.StatusLikeable(ctx, test.account, status) + if err != nil { + suite.FailNow(err.Error()) + } + if likeableRes.Permission != test.likeable { + suite.Fail( + "failure in case "+strconv.FormatInt(int64(i), 10), + "expected likeable result \"%s\", got \"%s\"", + likeableRes.Permission, test.likeable, + ) + } + + // Check replable. + replyableRes, err := testStructs.InteractionFilter.StatusReplyable(ctx, test.account, status) + if err != nil { + suite.FailNow(err.Error()) + } + if replyableRes.Permission != test.replyable { + suite.Fail( + "failure in case "+strconv.FormatInt(int64(i), 10), + "expected replyable result \"%s\", got \"%s\"", + replyableRes.Permission, test.replyable, + ) + } + + // Check boostable. + boostableRes, err := testStructs.InteractionFilter.StatusBoostable(ctx, test.account, status) + if err != nil { + suite.FailNow(err.Error()) + } + if boostableRes.Permission != test.boostable { + suite.Fail( + "failure in case "+strconv.FormatInt(int64(i), 10), + "expected boostable result \"%s\", got \"%s\"", + boostableRes.Permission, test.boostable, + ) + } + } +} + +func TestInteractionTestSuite(t *testing.T) { + suite.Run(t, new(InteractionTestSuite)) +} |
