mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-29 19:52:24 -05:00 
			
		
		
		
	[chore] Update interactionPolicy sub-policy parsing in line with documented defaults (#4229)
> If this is a code change, please include a summary of what you've coded, and link to the issue(s) it closes/implements. > > If this is a documentation change, please briefly describe what you've changed and why. Brings our parsing of unset sub-policies in line with the defaults documented here: https://docs.gotosocial.org/en/v0.19.1/federation/interaction_policy/#defaults-per-sub-policy Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4146 Part of https://codeberg.org/superseriousbusiness/gotosocial/issues/4026 Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]` If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want). - [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md). - [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat. - [x] I/we have not leveraged AI to create the proposed changes. - [x] I/we have performed a self-review of added code. - [x] I/we have written code that is legible and maintainable by others. - [x] I/we have commented the added code, particularly in hard-to-understand areas. - [ ] I/we have made any necessary changes to documentation. - [x] I/we have added tests that cover new code. - [x] I/we have run tests and they pass locally with the changes. - [x] I/we have run `go fmt ./...` and `golangci-lint run`. Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4229 Co-authored-by: tobi <tobi.smethurst@protonmail.com> Co-committed-by: tobi <tobi.smethurst@protonmail.com>
This commit is contained in:
		
					parent
					
						
							
								6574dc8a09
							
						
					
				
			
			
				commit
				
					
						56f98dc3b9
					
				
			
		
					 10 changed files with 507 additions and 155 deletions
				
			
		|  | @ -1074,6 +1074,9 @@ func ExtractVisibility(addressable Addressable, actorFollowersURI string) (gtsmo | ||||||
| // Will be nil (default policy) for Statusables that have no policy | // Will be nil (default policy) for Statusables that have no policy | ||||||
| // set on them, or have a null policy. In such a case, the caller | // set on them, or have a null policy. In such a case, the caller | ||||||
| // should assume the default policy for the status's visibility level. | // should assume the default policy for the status's visibility level. | ||||||
|  | // | ||||||
|  | // Sub-policies of the returned policy, eg., CanLike, CanReply, may | ||||||
|  | // each be nil if they were not set on the interaction policy. | ||||||
| func ExtractInteractionPolicy( | func ExtractInteractionPolicy( | ||||||
| 	statusable Statusable, | 	statusable Statusable, | ||||||
| 	owner *gtsmodel.Account, | 	owner *gtsmodel.Account, | ||||||
|  | @ -1100,6 +1103,8 @@ func ExtractInteractionPolicy( | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	// There's a policy key/value | ||||||
|  | 	// set, extract sub-policies. | ||||||
| 	return >smodel.InteractionPolicy{ | 	return >smodel.InteractionPolicy{ | ||||||
| 		CanLike:     extractCanLike(policy.GetGoToSocialCanLike(), owner), | 		CanLike:     extractCanLike(policy.GetGoToSocialCanLike(), owner), | ||||||
| 		CanReply:    extractCanReply(policy.GetGoToSocialCanReply(), owner), | 		CanReply:    extractCanReply(policy.GetGoToSocialCanReply(), owner), | ||||||
|  | @ -1107,73 +1112,82 @@ func ExtractInteractionPolicy( | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // Returns either a parsed CanLike sub-policy, or nil | ||||||
|  | // if canLike is not set, ie., if this post is from an | ||||||
|  | // instance that doesn't know / care about canLike. | ||||||
| func extractCanLike( | func extractCanLike( | ||||||
| 	prop vocab.GoToSocialCanLikeProperty, | 	prop vocab.GoToSocialCanLikeProperty, | ||||||
| 	owner *gtsmodel.Account, | 	owner *gtsmodel.Account, | ||||||
| ) gtsmodel.PolicyRules { | ) *gtsmodel.PolicyRules { | ||||||
| 	if prop == nil || prop.Len() != 1 { | 	if prop == nil || prop.Len() != 1 { | ||||||
| 		return gtsmodel.PolicyRules{} | 		return nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	propIter := prop.At(0) | 	propIter := prop.At(0) | ||||||
| 	if !propIter.IsGoToSocialCanLike() { | 	if !propIter.IsGoToSocialCanLike() { | ||||||
| 		return gtsmodel.PolicyRules{} | 		return nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	withRules := propIter.Get() | 	withRules := propIter.Get() | ||||||
| 	if withRules == nil { | 	if withRules == nil { | ||||||
| 		return gtsmodel.PolicyRules{} | 		return nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return gtsmodel.PolicyRules{ | 	return >smodel.PolicyRules{ | ||||||
| 		Always:       extractPolicyValues(withRules.GetGoToSocialAlways(), owner), | 		Always:       extractPolicyValues(withRules.GetGoToSocialAlways(), owner), | ||||||
| 		WithApproval: extractPolicyValues(withRules.GetGoToSocialApprovalRequired(), owner), | 		WithApproval: extractPolicyValues(withRules.GetGoToSocialApprovalRequired(), owner), | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // Returns either a parsed CanReply sub-policy, or nil | ||||||
|  | // if canReply is not set, ie., if this post is from an | ||||||
|  | // instance that doesn't know / care about canReply. | ||||||
| func extractCanReply( | func extractCanReply( | ||||||
| 	prop vocab.GoToSocialCanReplyProperty, | 	prop vocab.GoToSocialCanReplyProperty, | ||||||
| 	owner *gtsmodel.Account, | 	owner *gtsmodel.Account, | ||||||
| ) gtsmodel.PolicyRules { | ) *gtsmodel.PolicyRules { | ||||||
| 	if prop == nil || prop.Len() != 1 { | 	if prop == nil || prop.Len() != 1 { | ||||||
| 		return gtsmodel.PolicyRules{} | 		return nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	propIter := prop.At(0) | 	propIter := prop.At(0) | ||||||
| 	if !propIter.IsGoToSocialCanReply() { | 	if !propIter.IsGoToSocialCanReply() { | ||||||
| 		return gtsmodel.PolicyRules{} | 		return nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	withRules := propIter.Get() | 	withRules := propIter.Get() | ||||||
| 	if withRules == nil { | 	if withRules == nil { | ||||||
| 		return gtsmodel.PolicyRules{} | 		return nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return gtsmodel.PolicyRules{ | 	return >smodel.PolicyRules{ | ||||||
| 		Always:       extractPolicyValues(withRules.GetGoToSocialAlways(), owner), | 		Always:       extractPolicyValues(withRules.GetGoToSocialAlways(), owner), | ||||||
| 		WithApproval: extractPolicyValues(withRules.GetGoToSocialApprovalRequired(), owner), | 		WithApproval: extractPolicyValues(withRules.GetGoToSocialApprovalRequired(), owner), | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // Returns either a parsed CanAnnounce sub-policy, or nil | ||||||
|  | // if canAnnounce is not set, ie., if this post is from an | ||||||
|  | // instance that doesn't know / care about canAnnounce. | ||||||
| func extractCanAnnounce( | func extractCanAnnounce( | ||||||
| 	prop vocab.GoToSocialCanAnnounceProperty, | 	prop vocab.GoToSocialCanAnnounceProperty, | ||||||
| 	owner *gtsmodel.Account, | 	owner *gtsmodel.Account, | ||||||
| ) gtsmodel.PolicyRules { | ) *gtsmodel.PolicyRules { | ||||||
| 	if prop == nil || prop.Len() != 1 { | 	if prop == nil || prop.Len() != 1 { | ||||||
| 		return gtsmodel.PolicyRules{} | 		return nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	propIter := prop.At(0) | 	propIter := prop.At(0) | ||||||
| 	if !propIter.IsGoToSocialCanAnnounce() { | 	if !propIter.IsGoToSocialCanAnnounce() { | ||||||
| 		return gtsmodel.PolicyRules{} | 		return nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	withRules := propIter.Get() | 	withRules := propIter.Get() | ||||||
| 	if withRules == nil { | 	if withRules == nil { | ||||||
| 		return gtsmodel.PolicyRules{} | 		return nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return gtsmodel.PolicyRules{ | 	return >smodel.PolicyRules{ | ||||||
| 		Always:       extractPolicyValues(withRules.GetGoToSocialAlways(), owner), | 		Always:       extractPolicyValues(withRules.GetGoToSocialAlways(), owner), | ||||||
| 		WithApproval: extractPolicyValues(withRules.GetGoToSocialApprovalRequired(), owner), | 		WithApproval: extractPolicyValues(withRules.GetGoToSocialApprovalRequired(), owner), | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -103,13 +103,13 @@ func (suite *ExtractPolicyTestSuite) TestExtractPolicy() { | ||||||
| 	) | 	) | ||||||
| 
 | 
 | ||||||
| 	expectedPolicy := >smodel.InteractionPolicy{ | 	expectedPolicy := >smodel.InteractionPolicy{ | ||||||
| 		CanLike: gtsmodel.PolicyRules{ | 		CanLike: >smodel.PolicyRules{ | ||||||
| 			Always: gtsmodel.PolicyValues{ | 			Always: gtsmodel.PolicyValues{ | ||||||
| 				gtsmodel.PolicyValuePublic, | 				gtsmodel.PolicyValuePublic, | ||||||
| 			}, | 			}, | ||||||
| 			WithApproval: gtsmodel.PolicyValues{}, | 			WithApproval: gtsmodel.PolicyValues{}, | ||||||
| 		}, | 		}, | ||||||
| 		CanReply: gtsmodel.PolicyRules{ | 		CanReply: >smodel.PolicyRules{ | ||||||
| 			Always: gtsmodel.PolicyValues{ | 			Always: gtsmodel.PolicyValues{ | ||||||
| 				gtsmodel.PolicyValueAuthor, | 				gtsmodel.PolicyValueAuthor, | ||||||
| 				gtsmodel.PolicyValueFollowers, | 				gtsmodel.PolicyValueFollowers, | ||||||
|  | @ -120,7 +120,7 @@ func (suite *ExtractPolicyTestSuite) TestExtractPolicy() { | ||||||
| 				gtsmodel.PolicyValuePublic, | 				gtsmodel.PolicyValuePublic, | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 		CanAnnounce: gtsmodel.PolicyRules{ | 		CanAnnounce: >smodel.PolicyRules{ | ||||||
| 			Always: gtsmodel.PolicyValues{ | 			Always: gtsmodel.PolicyValues{ | ||||||
| 				gtsmodel.PolicyValueAuthor, | 				gtsmodel.PolicyValueAuthor, | ||||||
| 			}, | 			}, | ||||||
|  |  | ||||||
|  | @ -84,8 +84,8 @@ func (f *Filter) StatusLikeable( | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	switch { | 	switch { | ||||||
| 	// If status has policy set, check against that. | 	// If status has canLike sub-policy set, check against that. | ||||||
| 	case status.InteractionPolicy != nil: | 	case status.InteractionPolicy != nil && status.InteractionPolicy.CanLike != nil: | ||||||
| 		return f.checkPolicy( | 		return f.checkPolicy( | ||||||
| 			ctx, | 			ctx, | ||||||
| 			requester, | 			requester, | ||||||
|  | @ -95,19 +95,18 @@ func (f *Filter) StatusLikeable( | ||||||
| 
 | 
 | ||||||
| 	// If status is local and has no policy set, | 	// If status is local and has no policy set, | ||||||
| 	// check against the default policy for this | 	// 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: | 	case *status.Local: | ||||||
| 		policy := gtsmodel.DefaultInteractionPolicyFor(status.Visibility) |  | ||||||
| 		return f.checkPolicy( | 		return f.checkPolicy( | ||||||
| 			ctx, | 			ctx, | ||||||
| 			requester, | 			requester, | ||||||
| 			status, | 			status, | ||||||
| 			policy.CanLike, | 			gtsmodel.DefaultCanLikeFor(status.Visibility), | ||||||
| 		) | 		) | ||||||
| 
 | 
 | ||||||
| 	// Otherwise, assume the status is from an | 	// Otherwise, assume the status is from an | ||||||
| 	// instance that does not use / does not care | 	// instance that does not use / does not care | ||||||
| 	// about interaction policies, and just return OK. | 	// about canLike sub-policy, and just return OK. | ||||||
| 	default: | 	default: | ||||||
| 		return >smodel.PolicyCheckResult{ | 		return >smodel.PolicyCheckResult{ | ||||||
| 			Permission: gtsmodel.PolicyPermissionPermitted, | 			Permission: gtsmodel.PolicyPermissionPermitted, | ||||||
|  | @ -235,8 +234,8 @@ func (f *Filter) StatusReplyable( | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	switch { | 	switch { | ||||||
| 	// If status has policy set, check against that. | 	// If status has canReply sub-policy set, check against that. | ||||||
| 	case status.InteractionPolicy != nil: | 	case status.InteractionPolicy != nil && status.InteractionPolicy.CanReply != nil: | ||||||
| 		return f.checkPolicy( | 		return f.checkPolicy( | ||||||
| 			ctx, | 			ctx, | ||||||
| 			requester, | 			requester, | ||||||
|  | @ -245,20 +244,19 @@ func (f *Filter) StatusReplyable( | ||||||
| 		) | 		) | ||||||
| 
 | 
 | ||||||
| 	// If status is local and has no policy set, | 	// If status is local and has no policy set, | ||||||
| 	// check against the default policy for this | 	// check against the default canReply for this | ||||||
| 	// visibility, as we're interaction-policy aware. | 	// visibility, as we're canReply sub-policy aware. | ||||||
| 	case *status.Local: | 	case *status.Local: | ||||||
| 		policy := gtsmodel.DefaultInteractionPolicyFor(status.Visibility) |  | ||||||
| 		return f.checkPolicy( | 		return f.checkPolicy( | ||||||
| 			ctx, | 			ctx, | ||||||
| 			requester, | 			requester, | ||||||
| 			status, | 			status, | ||||||
| 			policy.CanReply, | 			gtsmodel.DefaultCanReplyFor(status.Visibility), | ||||||
| 		) | 		) | ||||||
| 
 | 
 | ||||||
| 	// Otherwise, assume the status is from an | 	// Otherwise, assume the status is from an | ||||||
| 	// instance that does not use / does not care | 	// instance that does not use / does not care | ||||||
| 	// about interaction policies, and just return OK. | 	// about canReply sub-policy, and just return OK. | ||||||
| 	default: | 	default: | ||||||
| 		return >smodel.PolicyCheckResult{ | 		return >smodel.PolicyCheckResult{ | ||||||
| 			Permission: gtsmodel.PolicyPermissionPermitted, | 			Permission: gtsmodel.PolicyPermissionPermitted, | ||||||
|  | @ -297,8 +295,8 @@ func (f *Filter) StatusBoostable( | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	switch { | 	switch { | ||||||
| 	// If status has policy set, check against that. | 	// If status has canAnnounce sub-policy set, check against that. | ||||||
| 	case status.InteractionPolicy != nil: | 	case status.InteractionPolicy != nil && status.InteractionPolicy.CanAnnounce != nil: | ||||||
| 		return f.checkPolicy( | 		return f.checkPolicy( | ||||||
| 			ctx, | 			ctx, | ||||||
| 			requester, | 			requester, | ||||||
|  | @ -319,7 +317,7 @@ func (f *Filter) StatusBoostable( | ||||||
| 		) | 		) | ||||||
| 
 | 
 | ||||||
| 	// Status is from an instance that does not use | 	// 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. | 	// We can boost it if it's unlisted or public. | ||||||
| 	case status.Visibility == gtsmodel.VisibilityPublic || | 	case status.Visibility == gtsmodel.VisibilityPublic || | ||||||
| 		status.Visibility == gtsmodel.VisibilityUnlocked: | 		status.Visibility == gtsmodel.VisibilityUnlocked: | ||||||
|  | @ -340,7 +338,7 @@ func (f *Filter) checkPolicy( | ||||||
| 	ctx context.Context, | 	ctx context.Context, | ||||||
| 	requester *gtsmodel.Account, | 	requester *gtsmodel.Account, | ||||||
| 	status *gtsmodel.Status, | 	status *gtsmodel.Status, | ||||||
| 	rules gtsmodel.PolicyRules, | 	rules *gtsmodel.PolicyRules, | ||||||
| ) (*gtsmodel.PolicyCheckResult, error) { | ) (*gtsmodel.PolicyCheckResult, error) { | ||||||
| 
 | 
 | ||||||
| 	// Wrap context to be able to | 	// Wrap context to be able to | ||||||
|  | @ -349,8 +347,8 @@ func (f *Filter) checkPolicy( | ||||||
| 	fctx.Context = ctx | 	fctx.Context = ctx | ||||||
| 
 | 
 | ||||||
| 	// Check if requester matches a PolicyValue | 	// Check if requester matches a PolicyValue | ||||||
| 	// to be always allowed to do this. | 	// to be automatically approved for this. | ||||||
| 	matchAlways, matchAlwaysValue, err := f.matchPolicy(fctx, | 	matchAutomatic, matchAutomaticValue, err := f.matchPolicy(fctx, | ||||||
| 		requester, | 		requester, | ||||||
| 		status, | 		status, | ||||||
| 		rules.Always, | 		rules.Always, | ||||||
|  | @ -360,40 +358,40 @@ func (f *Filter) checkPolicy( | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Check if requester matches a PolicyValue | 	// Check if requester matches a PolicyValue | ||||||
| 	// to be allowed to do this pending approval. | 	// to be manually approved for this. | ||||||
| 	matchWithApproval, _, err := f.matchPolicy(fctx, | 	matchManual, _, err := f.matchPolicy(fctx, | ||||||
| 		requester, | 		requester, | ||||||
| 		status, | 		status, | ||||||
| 		rules.WithApproval, | 		rules.WithApproval, | ||||||
| 	) | 	) | ||||||
| 	if err != nil { | 	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 { | 	switch { | ||||||
| 
 | 
 | ||||||
| 	// Prefer explicit match, | 	// Prefer explicit match, | ||||||
| 	// prioritizing "always". | 	// prioritizing automatic. | ||||||
| 	case matchAlways == explicit: | 	case matchAutomatic == explicit: | ||||||
| 		return >smodel.PolicyCheckResult{ | 		return >smodel.PolicyCheckResult{ | ||||||
| 			Permission:         gtsmodel.PolicyPermissionPermitted, | 			Permission:         gtsmodel.PolicyPermissionPermitted, | ||||||
| 			PermittedMatchedOn: &matchAlwaysValue, | 			PermittedMatchedOn: &matchAutomaticValue, | ||||||
| 		}, nil | 		}, nil | ||||||
| 
 | 
 | ||||||
| 	case matchWithApproval == explicit: | 	case matchManual == explicit: | ||||||
| 		return >smodel.PolicyCheckResult{ | 		return >smodel.PolicyCheckResult{ | ||||||
| 			Permission: gtsmodel.PolicyPermissionWithApproval, | 			Permission: gtsmodel.PolicyPermissionWithApproval, | ||||||
| 		}, nil | 		}, nil | ||||||
| 
 | 
 | ||||||
| 	// Then try implicit match, | 	// Then try implicit match, | ||||||
| 	// prioritizing "always". | 	// prioritizing automatic. | ||||||
| 	case matchAlways == implicit: | 	case matchAutomatic == implicit: | ||||||
| 		return >smodel.PolicyCheckResult{ | 		return >smodel.PolicyCheckResult{ | ||||||
| 			Permission:         gtsmodel.PolicyPermissionPermitted, | 			Permission:         gtsmodel.PolicyPermissionPermitted, | ||||||
| 			PermittedMatchedOn: &matchAlwaysValue, | 			PermittedMatchedOn: &matchAutomaticValue, | ||||||
| 		}, nil | 		}, nil | ||||||
| 
 | 
 | ||||||
| 	case matchWithApproval == implicit: | 	case matchManual == implicit: | ||||||
| 		return >smodel.PolicyCheckResult{ | 		return >smodel.PolicyCheckResult{ | ||||||
| 			Permission: gtsmodel.PolicyPermissionWithApproval, | 			Permission: gtsmodel.PolicyPermissionWithApproval, | ||||||
| 		}, nil | 		}, nil | ||||||
|  |  | ||||||
							
								
								
									
										207
									
								
								internal/filter/interaction/interactable_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										207
									
								
								internal/filter/interaction/interactable_test.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -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)) | ||||||
|  | } | ||||||
|  | @ -129,6 +129,19 @@ const ( | ||||||
| 	PolicyPermissionPermitted | 	PolicyPermissionPermitted | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | func (p PolicyPermission) String() string { | ||||||
|  | 	switch p { | ||||||
|  | 	case PolicyPermissionForbidden: | ||||||
|  | 		return "forbidden" | ||||||
|  | 	case PolicyPermissionWithApproval: | ||||||
|  | 		return "withApproval" | ||||||
|  | 	case PolicyPermissionPermitted: | ||||||
|  | 		return "always" | ||||||
|  | 	default: | ||||||
|  | 		return "unknown" | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // PolicyCheckResult encapsulates the results | // PolicyCheckResult encapsulates the results | ||||||
| // of checking a certain Actor URI + type | // of checking a certain Actor URI + type | ||||||
| // of interaction against an interaction policy. | // of interaction against an interaction policy. | ||||||
|  | @ -186,15 +199,15 @@ type InteractionPolicy struct { | ||||||
| 	// Conditions in which a Like | 	// Conditions in which a Like | ||||||
| 	// interaction will be accepted | 	// interaction will be accepted | ||||||
| 	// for an item with this policy. | 	// for an item with this policy. | ||||||
| 	CanLike PolicyRules | 	CanLike *PolicyRules | ||||||
| 	// Conditions in which a Reply | 	// Conditions in which a Reply | ||||||
| 	// interaction will be accepted | 	// interaction will be accepted | ||||||
| 	// for an item with this policy. | 	// for an item with this policy. | ||||||
| 	CanReply PolicyRules | 	CanReply *PolicyRules | ||||||
| 	// Conditions in which an Announce | 	// Conditions in which an Announce | ||||||
| 	// interaction will be accepted | 	// interaction will be accepted | ||||||
| 	// for an item with this policy. | 	// for an item with this policy. | ||||||
| 	CanAnnounce PolicyRules | 	CanAnnounce *PolicyRules | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // PolicyRules represents the rules according | // PolicyRules represents the rules according | ||||||
|  | @ -228,37 +241,144 @@ func DefaultInteractionPolicyFor(v Visibility) *InteractionPolicy { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var defaultPolicyPublic = &InteractionPolicy{ | // DefaultCanLikeFor returns the default | ||||||
| 	CanLike: PolicyRules{ | // policy rules for the canLike sub-policy. | ||||||
|  | func DefaultCanLikeFor(v Visibility) *PolicyRules { | ||||||
|  | 	switch v { | ||||||
|  | 
 | ||||||
| 	// Anyone can like. | 	// Anyone can like. | ||||||
|  | 	case VisibilityPublic, VisibilityUnlocked: | ||||||
|  | 		return &PolicyRules{ | ||||||
| 			Always: PolicyValues{ | 			Always: PolicyValues{ | ||||||
| 				PolicyValuePublic, | 				PolicyValuePublic, | ||||||
| 			}, | 			}, | ||||||
| 			WithApproval: make(PolicyValues, 0), | 			WithApproval: make(PolicyValues, 0), | ||||||
| 	}, |  | ||||||
| 	CanReply: PolicyRules{ |  | ||||||
| 		// Anyone can reply. |  | ||||||
| 		Always: PolicyValues{ |  | ||||||
| 			PolicyValuePublic, |  | ||||||
| 		}, |  | ||||||
| 		WithApproval: make(PolicyValues, 0), |  | ||||||
| 	}, |  | ||||||
| 	CanAnnounce: PolicyRules{ |  | ||||||
| 		// Anyone can announce. |  | ||||||
| 		Always: PolicyValues{ |  | ||||||
| 			PolicyValuePublic, |  | ||||||
| 		}, |  | ||||||
| 		WithApproval: make(PolicyValues, 0), |  | ||||||
| 	}, |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| // Returns the default interaction policy | 	// Self, followers and | ||||||
|  | 	// mentioned can like. | ||||||
|  | 	case VisibilityFollowersOnly, VisibilityMutualsOnly: | ||||||
|  | 		return &PolicyRules{ | ||||||
|  | 			Always: PolicyValues{ | ||||||
|  | 				PolicyValueAuthor, | ||||||
|  | 				PolicyValueFollowers, | ||||||
|  | 				PolicyValueMentioned, | ||||||
|  | 			}, | ||||||
|  | 			WithApproval: make(PolicyValues, 0), | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 	// Mentioned and self | ||||||
|  | 	// can always like. | ||||||
|  | 	case VisibilityDirect: | ||||||
|  | 		return &PolicyRules{ | ||||||
|  | 			Always: PolicyValues{ | ||||||
|  | 				PolicyValueAuthor, | ||||||
|  | 				PolicyValueMentioned, | ||||||
|  | 			}, | ||||||
|  | 			WithApproval: make(PolicyValues, 0), | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 	default: | ||||||
|  | 		panic("invalid visibility") | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DefaultCanReplyFor returns the default | ||||||
|  | // policy rules for the canReply sub-policy. | ||||||
|  | func DefaultCanReplyFor(v Visibility) *PolicyRules { | ||||||
|  | 	switch v { | ||||||
|  | 
 | ||||||
|  | 	// Anyone can reply. | ||||||
|  | 	case VisibilityPublic, VisibilityUnlocked: | ||||||
|  | 		return &PolicyRules{ | ||||||
|  | 			Always: PolicyValues{ | ||||||
|  | 				PolicyValuePublic, | ||||||
|  | 			}, | ||||||
|  | 			WithApproval: make(PolicyValues, 0), | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 	// Self, followers and | ||||||
|  | 	// mentioned can reply. | ||||||
|  | 	case VisibilityFollowersOnly, VisibilityMutualsOnly: | ||||||
|  | 		return &PolicyRules{ | ||||||
|  | 
 | ||||||
|  | 			Always: PolicyValues{ | ||||||
|  | 				PolicyValueAuthor, | ||||||
|  | 				PolicyValueFollowers, | ||||||
|  | 				PolicyValueMentioned, | ||||||
|  | 			}, | ||||||
|  | 			WithApproval: make(PolicyValues, 0), | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 	// Mentioned and self | ||||||
|  | 	// can always reply. | ||||||
|  | 	case VisibilityDirect: | ||||||
|  | 		return &PolicyRules{ | ||||||
|  | 			Always: PolicyValues{ | ||||||
|  | 				PolicyValueAuthor, | ||||||
|  | 				PolicyValueMentioned, | ||||||
|  | 			}, | ||||||
|  | 			WithApproval: make(PolicyValues, 0), | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 	default: | ||||||
|  | 		panic("invalid visibility") | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DefaultCanAnnounceFor returns the default | ||||||
|  | // policy rules for the canAnnounce sub-policy. | ||||||
|  | func DefaultCanAnnounceFor(v Visibility) *PolicyRules { | ||||||
|  | 	switch v { | ||||||
|  | 
 | ||||||
|  | 	// Anyone can announce. | ||||||
|  | 	case VisibilityPublic, VisibilityUnlocked: | ||||||
|  | 		return &PolicyRules{ | ||||||
|  | 			Always: PolicyValues{ | ||||||
|  | 				PolicyValuePublic, | ||||||
|  | 			}, | ||||||
|  | 			WithApproval: make(PolicyValues, 0), | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 	// Only self can announce. | ||||||
|  | 	case VisibilityFollowersOnly, VisibilityMutualsOnly: | ||||||
|  | 		return &PolicyRules{ | ||||||
|  | 			Always: PolicyValues{ | ||||||
|  | 				PolicyValueAuthor, | ||||||
|  | 			}, | ||||||
|  | 			WithApproval: make(PolicyValues, 0), | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 	// Only self can announce. | ||||||
|  | 	case VisibilityDirect: | ||||||
|  | 		return &PolicyRules{ | ||||||
|  | 			Always: PolicyValues{ | ||||||
|  | 				PolicyValueAuthor, | ||||||
|  | 			}, | ||||||
|  | 			WithApproval: make(PolicyValues, 0), | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 	default: | ||||||
|  | 		panic("invalid visibility") | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | var defaultPolicyPublic = &InteractionPolicy{ | ||||||
|  | 	CanLike:     DefaultCanLikeFor(VisibilityPublic), | ||||||
|  | 	CanReply:    DefaultCanReplyFor(VisibilityPublic), | ||||||
|  | 	CanAnnounce: DefaultCanAnnounceFor(VisibilityPublic), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Returns a default interaction policy | ||||||
| // for a post with visibility of public. | // for a post with visibility of public. | ||||||
| func DefaultInteractionPolicyPublic() *InteractionPolicy { | func DefaultInteractionPolicyPublic() *InteractionPolicy { | ||||||
| 	return defaultPolicyPublic | 	// Copy global. | ||||||
|  | 	c := new(InteractionPolicy) | ||||||
|  | 	*c = *defaultPolicyPublic | ||||||
|  | 	return c | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Returns the default interaction policy | // Returns a default interaction policy | ||||||
| // for a post with visibility of unlocked. | // for a post with visibility of unlocked. | ||||||
| func DefaultInteractionPolicyUnlocked() *InteractionPolicy { | func DefaultInteractionPolicyUnlocked() *InteractionPolicy { | ||||||
| 	// Same as public (for now). | 	// Same as public (for now). | ||||||
|  | @ -266,71 +386,31 @@ func DefaultInteractionPolicyUnlocked() *InteractionPolicy { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var defaultPolicyFollowersOnly = &InteractionPolicy{ | var defaultPolicyFollowersOnly = &InteractionPolicy{ | ||||||
| 	CanLike: PolicyRules{ | 	CanLike:     DefaultCanLikeFor(VisibilityFollowersOnly), | ||||||
| 		// Self, followers and | 	CanReply:    DefaultCanReplyFor(VisibilityFollowersOnly), | ||||||
| 		// mentioned can like. | 	CanAnnounce: DefaultCanAnnounceFor(VisibilityFollowersOnly), | ||||||
| 		Always: PolicyValues{ |  | ||||||
| 			PolicyValueAuthor, |  | ||||||
| 			PolicyValueFollowers, |  | ||||||
| 			PolicyValueMentioned, |  | ||||||
| 		}, |  | ||||||
| 		WithApproval: make(PolicyValues, 0), |  | ||||||
| 	}, |  | ||||||
| 	CanReply: PolicyRules{ |  | ||||||
| 		// Self, followers and |  | ||||||
| 		// mentioned can reply. |  | ||||||
| 		Always: PolicyValues{ |  | ||||||
| 			PolicyValueAuthor, |  | ||||||
| 			PolicyValueFollowers, |  | ||||||
| 			PolicyValueMentioned, |  | ||||||
| 		}, |  | ||||||
| 		WithApproval: make(PolicyValues, 0), |  | ||||||
| 	}, |  | ||||||
| 	CanAnnounce: PolicyRules{ |  | ||||||
| 		// Only self can announce. |  | ||||||
| 		Always: PolicyValues{ |  | ||||||
| 			PolicyValueAuthor, |  | ||||||
| 		}, |  | ||||||
| 		WithApproval: make(PolicyValues, 0), |  | ||||||
| 	}, |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Returns the default interaction policy for | // Returns a default interaction policy for | ||||||
| // a post with visibility of followers only. | // a post with visibility of followers only. | ||||||
| func DefaultInteractionPolicyFollowersOnly() *InteractionPolicy { | func DefaultInteractionPolicyFollowersOnly() *InteractionPolicy { | ||||||
| 	return defaultPolicyFollowersOnly | 	// Copy global. | ||||||
|  | 	c := new(InteractionPolicy) | ||||||
|  | 	*c = *defaultPolicyFollowersOnly | ||||||
|  | 	return c | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var defaultPolicyDirect = &InteractionPolicy{ | var defaultPolicyDirect = &InteractionPolicy{ | ||||||
| 	CanLike: PolicyRules{ | 	CanLike:     DefaultCanLikeFor(VisibilityDirect), | ||||||
| 		// Mentioned and self | 	CanReply:    DefaultCanReplyFor(VisibilityDirect), | ||||||
| 		// can always like. | 	CanAnnounce: DefaultCanAnnounceFor(VisibilityDirect), | ||||||
| 		Always: PolicyValues{ |  | ||||||
| 			PolicyValueAuthor, |  | ||||||
| 			PolicyValueMentioned, |  | ||||||
| 		}, |  | ||||||
| 		WithApproval: make(PolicyValues, 0), |  | ||||||
| 	}, |  | ||||||
| 	CanReply: PolicyRules{ |  | ||||||
| 		// Mentioned and self |  | ||||||
| 		// can always reply. |  | ||||||
| 		Always: PolicyValues{ |  | ||||||
| 			PolicyValueAuthor, |  | ||||||
| 			PolicyValueMentioned, |  | ||||||
| 		}, |  | ||||||
| 		WithApproval: make(PolicyValues, 0), |  | ||||||
| 	}, |  | ||||||
| 	CanAnnounce: PolicyRules{ |  | ||||||
| 		// Only self can announce. |  | ||||||
| 		Always: PolicyValues{ |  | ||||||
| 			PolicyValueAuthor, |  | ||||||
| 		}, |  | ||||||
| 		WithApproval: make(PolicyValues, 0), |  | ||||||
| 	}, |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Returns the default interaction policy | // Returns a default interaction policy | ||||||
| // for a post with visibility of direct. | // for a post with visibility of direct. | ||||||
| func DefaultInteractionPolicyDirect() *InteractionPolicy { | func DefaultInteractionPolicyDirect() *InteractionPolicy { | ||||||
| 	return defaultPolicyDirect | 	// Copy global. | ||||||
|  | 	c := new(InteractionPolicy) | ||||||
|  | 	*c = *defaultPolicyDirect | ||||||
|  | 	return c | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -227,15 +227,15 @@ func APIInteractionPolicyToInteractionPolicy( | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return >smodel.InteractionPolicy{ | 	return >smodel.InteractionPolicy{ | ||||||
| 		CanLike: gtsmodel.PolicyRules{ | 		CanLike: >smodel.PolicyRules{ | ||||||
| 			Always:       canLikeAlways, | 			Always:       canLikeAlways, | ||||||
| 			WithApproval: canLikeWithApproval, | 			WithApproval: canLikeWithApproval, | ||||||
| 		}, | 		}, | ||||||
| 		CanReply: gtsmodel.PolicyRules{ | 		CanReply: >smodel.PolicyRules{ | ||||||
| 			Always:       canReplyAlways, | 			Always:       canReplyAlways, | ||||||
| 			WithApproval: canReplyWithApproval, | 			WithApproval: canReplyWithApproval, | ||||||
| 		}, | 		}, | ||||||
| 		CanAnnounce: gtsmodel.PolicyRules{ | 		CanAnnounce: >smodel.PolicyRules{ | ||||||
| 			Always:       canAnnounceAlways, | 			Always:       canAnnounceAlways, | ||||||
| 			WithApproval: canAnnounceWithApproval, | 			WithApproval: canAnnounceWithApproval, | ||||||
| 		}, | 		}, | ||||||
|  |  | ||||||
|  | @ -1893,6 +1893,19 @@ func (c *Converter) InteractionPolicyToASInteractionPolicy( | ||||||
| ) (vocab.GoToSocialInteractionPolicy, error) { | ) (vocab.GoToSocialInteractionPolicy, error) { | ||||||
| 	policy := streams.NewGoToSocialInteractionPolicy() | 	policy := streams.NewGoToSocialInteractionPolicy() | ||||||
| 
 | 
 | ||||||
|  | 	/* | ||||||
|  | 		Implementation note for the below: | ||||||
|  | 		While it's possible for remote instances to set | ||||||
|  | 		sub-policies like canLike, canReply, etc to null | ||||||
|  | 		values, or omit them entirely, GtS always falls | ||||||
|  | 		back to default non-nil sub-policies when storing | ||||||
|  | 		policies created for local statuses. Therefore, | ||||||
|  | 		since we only ever serialize our *own* statuses | ||||||
|  | 		to AS format using this function, it's safe to | ||||||
|  | 		assume that the values will always be set, rather | ||||||
|  | 		than checking for nil ptrs. | ||||||
|  | 	*/ | ||||||
|  | 
 | ||||||
| 	/* | 	/* | ||||||
| 		CAN LIKE | 		CAN LIKE | ||||||
| 	*/ | 	*/ | ||||||
|  |  | ||||||
|  | @ -2867,7 +2867,10 @@ func (c *Converter) ThemesToAPIThemes(themes []*gtsmodel.Theme) []apimodel.Theme | ||||||
| // into an apimodel interaction policy. | // into an apimodel interaction policy. | ||||||
| // | // | ||||||
| // Provided status can be nil to convert a | // Provided status can be nil to convert a | ||||||
| // policy without a particular status in mind. | // policy without a particular status in mind, | ||||||
|  | // but ***if status is nil then sub-policies | ||||||
|  | // CanLike, CanReply, and CanAnnounce on | ||||||
|  | // the given policy must *not* be nil.*** | ||||||
| // | // | ||||||
| // RequestingAccount can also be nil for | // RequestingAccount can also be nil for | ||||||
| // unauthorized requests (web, public api etc). | // unauthorized requests (web, public api etc). | ||||||
|  | @ -2877,19 +2880,54 @@ func (c *Converter) InteractionPolicyToAPIInteractionPolicy( | ||||||
| 	status *gtsmodel.Status, | 	status *gtsmodel.Status, | ||||||
| 	requester *gtsmodel.Account, | 	requester *gtsmodel.Account, | ||||||
| ) (*apimodel.InteractionPolicy, error) { | ) (*apimodel.InteractionPolicy, error) { | ||||||
| 	apiPolicy := &apimodel.InteractionPolicy{ | 	apiPolicy := new(apimodel.InteractionPolicy) | ||||||
| 		CanFavourite: apimodel.PolicyRules{ | 
 | ||||||
|  | 	// gtsmodel CanLike -> apimodel CanFavourite | ||||||
|  | 	if policy.CanLike != nil { | ||||||
|  | 		// Use the set CanLike value. | ||||||
|  | 		apiPolicy.CanFavourite = apimodel.PolicyRules{ | ||||||
| 			Always:       policyValsToAPIPolicyVals(policy.CanLike.Always), | 			Always:       policyValsToAPIPolicyVals(policy.CanLike.Always), | ||||||
| 			WithApproval: policyValsToAPIPolicyVals(policy.CanLike.WithApproval), | 			WithApproval: policyValsToAPIPolicyVals(policy.CanLike.WithApproval), | ||||||
| 		}, | 		} | ||||||
| 		CanReply: apimodel.PolicyRules{ | 	} else { | ||||||
|  | 		// Use default CanLike value for this vis. | ||||||
|  | 		pCanLike := gtsmodel.DefaultCanLikeFor(status.Visibility) | ||||||
|  | 		apiPolicy.CanFavourite = apimodel.PolicyRules{ | ||||||
|  | 			Always:       policyValsToAPIPolicyVals(pCanLike.Always), | ||||||
|  | 			WithApproval: policyValsToAPIPolicyVals(pCanLike.WithApproval), | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// gtsmodel CanReply -> apimodel CanReply | ||||||
|  | 	if policy.CanReply != nil { | ||||||
|  | 		// Use the set CanReply value. | ||||||
|  | 		apiPolicy.CanReply = apimodel.PolicyRules{ | ||||||
| 			Always:       policyValsToAPIPolicyVals(policy.CanReply.Always), | 			Always:       policyValsToAPIPolicyVals(policy.CanReply.Always), | ||||||
| 			WithApproval: policyValsToAPIPolicyVals(policy.CanReply.WithApproval), | 			WithApproval: policyValsToAPIPolicyVals(policy.CanReply.WithApproval), | ||||||
| 		}, | 		} | ||||||
| 		CanReblog: apimodel.PolicyRules{ | 	} else { | ||||||
|  | 		// Use default CanReply value for this vis. | ||||||
|  | 		pCanReply := gtsmodel.DefaultCanReplyFor(status.Visibility) | ||||||
|  | 		apiPolicy.CanReply = apimodel.PolicyRules{ | ||||||
|  | 			Always:       policyValsToAPIPolicyVals(pCanReply.Always), | ||||||
|  | 			WithApproval: policyValsToAPIPolicyVals(pCanReply.WithApproval), | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// gtsmodel CanAnnounce -> apimodel CanReblog | ||||||
|  | 	if policy.CanAnnounce != nil { | ||||||
|  | 		// Use the set CanAnnounce value. | ||||||
|  | 		apiPolicy.CanReblog = apimodel.PolicyRules{ | ||||||
| 			Always:       policyValsToAPIPolicyVals(policy.CanAnnounce.Always), | 			Always:       policyValsToAPIPolicyVals(policy.CanAnnounce.Always), | ||||||
| 			WithApproval: policyValsToAPIPolicyVals(policy.CanAnnounce.WithApproval), | 			WithApproval: policyValsToAPIPolicyVals(policy.CanAnnounce.WithApproval), | ||||||
| 		}, | 		} | ||||||
|  | 	} else { | ||||||
|  | 		// Use default CanAnnounce value for this vis. | ||||||
|  | 		pCanAnnounce := gtsmodel.DefaultCanAnnounceFor(status.Visibility) | ||||||
|  | 		apiPolicy.CanReblog = apimodel.PolicyRules{ | ||||||
|  | 			Always:       policyValsToAPIPolicyVals(pCanAnnounce.Always), | ||||||
|  | 			WithApproval: policyValsToAPIPolicyVals(pCanAnnounce.WithApproval), | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if status == nil || requester == nil { | 	if status == nil || requester == nil { | ||||||
|  |  | ||||||
|  | @ -2238,13 +2238,13 @@ func NewTestStatuses() map[string]*gtsmodel.Status { | ||||||
| 			CreatedWithApplicationID: "01F8MGY43H3N2C8EWPR2FPYEXG", | 			CreatedWithApplicationID: "01F8MGY43H3N2C8EWPR2FPYEXG", | ||||||
| 			Federated:                util.Ptr(true), | 			Federated:                util.Ptr(true), | ||||||
| 			InteractionPolicy: >smodel.InteractionPolicy{ | 			InteractionPolicy: >smodel.InteractionPolicy{ | ||||||
| 				CanLike: gtsmodel.PolicyRules{ | 				CanLike: >smodel.PolicyRules{ | ||||||
| 					Always: gtsmodel.PolicyValues{gtsmodel.PolicyValueAuthor}, | 					Always: gtsmodel.PolicyValues{gtsmodel.PolicyValueAuthor}, | ||||||
| 				}, | 				}, | ||||||
| 				CanReply: gtsmodel.PolicyRules{ | 				CanReply: >smodel.PolicyRules{ | ||||||
| 					Always: gtsmodel.PolicyValues{gtsmodel.PolicyValueAuthor}, | 					Always: gtsmodel.PolicyValues{gtsmodel.PolicyValueAuthor}, | ||||||
| 				}, | 				}, | ||||||
| 				CanAnnounce: gtsmodel.PolicyRules{ | 				CanAnnounce: >smodel.PolicyRules{ | ||||||
| 					Always: gtsmodel.PolicyValues{gtsmodel.PolicyValueAuthor}, | 					Always: gtsmodel.PolicyValues{gtsmodel.PolicyValueAuthor}, | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
|  | @ -2419,13 +2419,13 @@ func NewTestStatuses() map[string]*gtsmodel.Status { | ||||||
| 			CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ", | 			CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ", | ||||||
| 			Federated:                util.Ptr(true), | 			Federated:                util.Ptr(true), | ||||||
| 			InteractionPolicy: >smodel.InteractionPolicy{ | 			InteractionPolicy: >smodel.InteractionPolicy{ | ||||||
| 				CanLike: gtsmodel.PolicyRules{ | 				CanLike: >smodel.PolicyRules{ | ||||||
| 					Always: gtsmodel.PolicyValues{gtsmodel.PolicyValuePublic}, | 					Always: gtsmodel.PolicyValues{gtsmodel.PolicyValuePublic}, | ||||||
| 				}, | 				}, | ||||||
| 				CanReply: gtsmodel.PolicyRules{ | 				CanReply: >smodel.PolicyRules{ | ||||||
| 					Always: gtsmodel.PolicyValues{gtsmodel.PolicyValueAuthor}, | 					Always: gtsmodel.PolicyValues{gtsmodel.PolicyValueAuthor}, | ||||||
| 				}, | 				}, | ||||||
| 				CanAnnounce: gtsmodel.PolicyRules{ | 				CanAnnounce: >smodel.PolicyRules{ | ||||||
| 					Always: gtsmodel.PolicyValues{gtsmodel.PolicyValuePublic}, | 					Always: gtsmodel.PolicyValues{gtsmodel.PolicyValuePublic}, | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
|  | @ -2451,14 +2451,14 @@ func NewTestStatuses() map[string]*gtsmodel.Status { | ||||||
| 			CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ", | 			CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ", | ||||||
| 			Federated:                util.Ptr(true), | 			Federated:                util.Ptr(true), | ||||||
| 			InteractionPolicy: >smodel.InteractionPolicy{ | 			InteractionPolicy: >smodel.InteractionPolicy{ | ||||||
| 				CanLike: gtsmodel.PolicyRules{ | 				CanLike: >smodel.PolicyRules{ | ||||||
| 					Always: gtsmodel.PolicyValues{gtsmodel.PolicyValuePublic}, | 					Always: gtsmodel.PolicyValues{gtsmodel.PolicyValuePublic}, | ||||||
| 				}, | 				}, | ||||||
| 				CanReply: gtsmodel.PolicyRules{ | 				CanReply: >smodel.PolicyRules{ | ||||||
| 					Always:       gtsmodel.PolicyValues{gtsmodel.PolicyValueAuthor}, | 					Always:       gtsmodel.PolicyValues{gtsmodel.PolicyValueAuthor}, | ||||||
| 					WithApproval: gtsmodel.PolicyValues{gtsmodel.PolicyValuePublic}, | 					WithApproval: gtsmodel.PolicyValues{gtsmodel.PolicyValuePublic}, | ||||||
| 				}, | 				}, | ||||||
| 				CanAnnounce: gtsmodel.PolicyRules{ | 				CanAnnounce: >smodel.PolicyRules{ | ||||||
| 					Always: gtsmodel.PolicyValues{gtsmodel.PolicyValuePublic}, | 					Always: gtsmodel.PolicyValues{gtsmodel.PolicyValuePublic}, | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
|  | @ -2483,13 +2483,13 @@ func NewTestStatuses() map[string]*gtsmodel.Status { | ||||||
| 			CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ", | 			CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ", | ||||||
| 			Federated:                util.Ptr(false), | 			Federated:                util.Ptr(false), | ||||||
| 			InteractionPolicy: >smodel.InteractionPolicy{ | 			InteractionPolicy: >smodel.InteractionPolicy{ | ||||||
| 				CanLike: gtsmodel.PolicyRules{ | 				CanLike: >smodel.PolicyRules{ | ||||||
| 					Always: gtsmodel.PolicyValues{gtsmodel.PolicyValuePublic}, | 					Always: gtsmodel.PolicyValues{gtsmodel.PolicyValuePublic}, | ||||||
| 				}, | 				}, | ||||||
| 				CanReply: gtsmodel.PolicyRules{ | 				CanReply: >smodel.PolicyRules{ | ||||||
| 					Always: gtsmodel.PolicyValues{gtsmodel.PolicyValuePublic}, | 					Always: gtsmodel.PolicyValues{gtsmodel.PolicyValuePublic}, | ||||||
| 				}, | 				}, | ||||||
| 				CanAnnounce: gtsmodel.PolicyRules{ | 				CanAnnounce: >smodel.PolicyRules{ | ||||||
| 					Always: gtsmodel.PolicyValues{gtsmodel.PolicyValueAuthor}, | 					Always: gtsmodel.PolicyValues{gtsmodel.PolicyValueAuthor}, | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
|  |  | ||||||
|  | @ -49,6 +49,7 @@ type TestStructs struct { | ||||||
| 	EmailSender         email.Sender | 	EmailSender         email.Sender | ||||||
| 	WebPushSender       *WebPushMockSender | 	WebPushSender       *WebPushMockSender | ||||||
| 	TransportController transport.Controller | 	TransportController transport.Controller | ||||||
|  | 	InteractionFilter   *interaction.Filter | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func SetupTestStructs( | func SetupTestStructs( | ||||||
|  | @ -122,6 +123,7 @@ func SetupTestStructs( | ||||||
| 		EmailSender:         emailSender, | 		EmailSender:         emailSender, | ||||||
| 		WebPushSender:       webPushSender, | 		WebPushSender:       webPushSender, | ||||||
| 		TransportController: transportController, | 		TransportController: transportController, | ||||||
|  | 		InteractionFilter:   intFilter, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue