mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 16:12:24 -05:00 
			
		
		
		
	* convert statuses.visibility and notifications.notification_type columns from type string -> int for performance / space savings * fix test trying to compare string to int * fix instance count query using string literal instead of gtsmodel const type * ensure a default value is always set * also migrate the account settings and sin bin status tables * initialize maps outside loops and place into singular enum mapping creation func * use int16 for enum types * update sinbinstatus creation to be from a snapshot at initial creation * add snapshot of poll type at creation time
		
			
				
	
	
		
			336 lines
		
	
	
	
		
			9.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			336 lines
		
	
	
	
		
			9.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // 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 gtsmodel
 | |
| 
 | |
| // A policy URI is GoToSocial's internal representation of
 | |
| // one ActivityPub URI for an Actor or a Collection of Actors,
 | |
| // specific to the domain of enforcing interaction policies.
 | |
| //
 | |
| // A PolicyValue can be stored in the database either as one
 | |
| // of the Value constants defined below (to save space), OR as
 | |
| // a full-fledged ActivityPub URI.
 | |
| //
 | |
| // A PolicyValue should be translated to the canonical string
 | |
| // value of the represented URI when federating an item, or
 | |
| // from the canonical string value of the URI when receiving
 | |
| // or retrieving an item.
 | |
| //
 | |
| // For example, if the PolicyValue `followers` was being
 | |
| // federated outwards in an interaction policy attached to an
 | |
| // item created by the actor `https://example.org/users/someone`,
 | |
| // then it should be translated to their followers URI when sent,
 | |
| // eg., `https://example.org/users/someone/followers`.
 | |
| //
 | |
| // Likewise, if GoToSocial receives an item with an interaction
 | |
| // policy containing `https://example.org/users/someone/followers`,
 | |
| // and the item was created by `https://example.org/users/someone`,
 | |
| // then the followers URI would be converted to `followers`
 | |
| // for internal storage.
 | |
| type PolicyValue string
 | |
| 
 | |
| const (
 | |
| 	// Stand-in for ActivityPub magic public URI,
 | |
| 	// which encompasses every possible Actor URI.
 | |
| 	PolicyValuePublic PolicyValue = "public"
 | |
| 	// Stand-in for the Followers Collection of
 | |
| 	// the item owner's Actor.
 | |
| 	PolicyValueFollowers PolicyValue = "followers"
 | |
| 	// Stand-in for the Following Collection of
 | |
| 	// the item owner's Actor.
 | |
| 	PolicyValueFollowing PolicyValue = "following"
 | |
| 	// Stand-in for the Mutuals Collection of
 | |
| 	// the item owner's Actor.
 | |
| 	//
 | |
| 	// (TODO: Reserved, currently unused).
 | |
| 	PolicyValueMutuals PolicyValue = "mutuals"
 | |
| 	// Stand-in for Actor URIs tagged in the item.
 | |
| 	PolicyValueMentioned PolicyValue = "mentioned"
 | |
| 	// Stand-in for the Actor URI of the item owner.
 | |
| 	PolicyValueAuthor PolicyValue = "author"
 | |
| )
 | |
| 
 | |
| // FeasibleForVisibility returns true if the PolicyValue could feasibly
 | |
| // be set in a policy for an item with the given visibility, otherwise
 | |
| // returns false.
 | |
| //
 | |
| // For example, PolicyValuePublic could not be set in a policy for an
 | |
| // item with visibility FollowersOnly, but could be set in a policy
 | |
| // for an item with visibility Public or Unlocked.
 | |
| //
 | |
| // This is not prescriptive, and should be used only to guide policy
 | |
| // choices. Eg., if a remote instance wants to do something wacky like
 | |
| // set "anyone can interact with this status" for a Direct visibility
 | |
| // status, that's their business; our normal visibility filtering will
 | |
| // prevent users on our instance from actually being able to interact
 | |
| // unless they can see the status anyway.
 | |
| func (p PolicyValue) FeasibleForVisibility(v Visibility) bool {
 | |
| 	switch p {
 | |
| 
 | |
| 	// Mentioned and self Values are
 | |
| 	// feasible for any visibility.
 | |
| 	case PolicyValueAuthor,
 | |
| 		PolicyValueMentioned:
 | |
| 		return true
 | |
| 
 | |
| 	// Followers/following/mutual Values
 | |
| 	// are only feasible for items with
 | |
| 	// followers visibility and higher.
 | |
| 	case PolicyValueFollowers,
 | |
| 		PolicyValueFollowing:
 | |
| 		return v == VisibilityFollowersOnly ||
 | |
| 			v == VisibilityPublic ||
 | |
| 			v == VisibilityUnlocked
 | |
| 
 | |
| 	// Public policy Value only feasible
 | |
| 	// for items that are To or CC public.
 | |
| 	case PolicyValuePublic:
 | |
| 		return v == VisibilityUnlocked ||
 | |
| 			v == VisibilityPublic
 | |
| 
 | |
| 	// Any other combo
 | |
| 	// is probably fine.
 | |
| 	default:
 | |
| 		return true
 | |
| 	}
 | |
| }
 | |
| 
 | |
| type PolicyValues []PolicyValue
 | |
| 
 | |
| // PolicyPermission represents the permission
 | |
| // state for a certain Actor URI and interaction
 | |
| // type, in relation to a policy.
 | |
| type PolicyPermission int
 | |
| 
 | |
| const (
 | |
| 	// Interaction is forbidden for this
 | |
| 	// PolicyValue + interaction combination.
 | |
| 	PolicyPermissionForbidden PolicyPermission = iota
 | |
| 	// Interaction is conditionally permitted
 | |
| 	// for this PolicyValue + interaction combo,
 | |
| 	// pending approval by the item owner.
 | |
| 	PolicyPermissionWithApproval
 | |
| 	// Interaction is permitted for this
 | |
| 	// PolicyValue + interaction combination.
 | |
| 	PolicyPermissionPermitted
 | |
| )
 | |
| 
 | |
| // PolicyCheckResult encapsulates the results
 | |
| // of checking a certain Actor URI + type
 | |
| // of interaction against an interaction policy.
 | |
| type PolicyCheckResult struct {
 | |
| 	// Permission permitted /
 | |
| 	// with approval / forbidden.
 | |
| 	Permission PolicyPermission
 | |
| 
 | |
| 	// Value that this check matched on.
 | |
| 	// Only set if Permission = permitted.
 | |
| 	PermittedMatchedOn *PolicyValue
 | |
| }
 | |
| 
 | |
| // MatchedOnCollection returns true if this policy check
 | |
| // result turned up Permitted, and matched based on the
 | |
| // requester's presence in a followers or following collection.
 | |
| func (pcr *PolicyCheckResult) MatchedOnCollection() bool {
 | |
| 	if !pcr.Permitted() {
 | |
| 		// Not permitted at all
 | |
| 		// so definitely didn't
 | |
| 		// match on collection.
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	if pcr.PermittedMatchedOn == nil {
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	return *pcr.PermittedMatchedOn == PolicyValueFollowers ||
 | |
| 		*pcr.PermittedMatchedOn == PolicyValueFollowing
 | |
| }
 | |
| 
 | |
| // Permitted returns true if this policy
 | |
| // check resulted in Permission = permitted.
 | |
| func (pcr *PolicyCheckResult) Permitted() bool {
 | |
| 	return pcr.Permission == PolicyPermissionPermitted
 | |
| }
 | |
| 
 | |
| // Permitted returns true if this policy
 | |
| // check resulted in Permission = with approval.
 | |
| func (pcr *PolicyCheckResult) WithApproval() bool {
 | |
| 	return pcr.Permission == PolicyPermissionWithApproval
 | |
| }
 | |
| 
 | |
| // Permitted returns true if this policy
 | |
| // check resulted in Permission = forbidden.
 | |
| func (pcr *PolicyCheckResult) Forbidden() bool {
 | |
| 	return pcr.Permission == PolicyPermissionForbidden
 | |
| }
 | |
| 
 | |
| // An InteractionPolicy determines which
 | |
| // interactions will be accepted for an
 | |
| // item, and according to what rules.
 | |
| type InteractionPolicy struct {
 | |
| 	// Conditions in which a Like
 | |
| 	// interaction will be accepted
 | |
| 	// for an item with this policy.
 | |
| 	CanLike PolicyRules
 | |
| 	// Conditions in which a Reply
 | |
| 	// interaction will be accepted
 | |
| 	// for an item with this policy.
 | |
| 	CanReply PolicyRules
 | |
| 	// Conditions in which an Announce
 | |
| 	// interaction will be accepted
 | |
| 	// for an item with this policy.
 | |
| 	CanAnnounce PolicyRules
 | |
| }
 | |
| 
 | |
| // PolicyRules represents the rules according
 | |
| // to which a certain interaction is permitted
 | |
| // to various Actor and Actor Collection URIs.
 | |
| type PolicyRules struct {
 | |
| 	// Always is for PolicyValues who are
 | |
| 	// permitted to do an interaction
 | |
| 	// without requiring approval.
 | |
| 	Always PolicyValues
 | |
| 	// WithApproval is for PolicyValues who
 | |
| 	// are conditionally permitted to do
 | |
| 	// an interaction, pending approval.
 | |
| 	WithApproval PolicyValues
 | |
| }
 | |
| 
 | |
| // Returns the default interaction policy
 | |
| // for the given visibility level.
 | |
| func DefaultInteractionPolicyFor(v Visibility) *InteractionPolicy {
 | |
| 	switch v {
 | |
| 	case VisibilityPublic:
 | |
| 		return DefaultInteractionPolicyPublic()
 | |
| 	case VisibilityUnlocked:
 | |
| 		return DefaultInteractionPolicyUnlocked()
 | |
| 	case VisibilityFollowersOnly, VisibilityMutualsOnly:
 | |
| 		return DefaultInteractionPolicyFollowersOnly()
 | |
| 	case VisibilityDirect:
 | |
| 		return DefaultInteractionPolicyDirect()
 | |
| 	default:
 | |
| 		panic("invalid visibility")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| var defaultPolicyPublic = &InteractionPolicy{
 | |
| 	CanLike: PolicyRules{
 | |
| 		// Anyone can like.
 | |
| 		Always: PolicyValues{
 | |
| 			PolicyValuePublic,
 | |
| 		},
 | |
| 		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
 | |
| // for a post with visibility of public.
 | |
| func DefaultInteractionPolicyPublic() *InteractionPolicy {
 | |
| 	return defaultPolicyPublic
 | |
| }
 | |
| 
 | |
| // Returns the default interaction policy
 | |
| // for a post with visibility of unlocked.
 | |
| func DefaultInteractionPolicyUnlocked() *InteractionPolicy {
 | |
| 	// Same as public (for now).
 | |
| 	return defaultPolicyPublic
 | |
| }
 | |
| 
 | |
| var defaultPolicyFollowersOnly = &InteractionPolicy{
 | |
| 	CanLike: PolicyRules{
 | |
| 		// Self, followers and
 | |
| 		// mentioned can like.
 | |
| 		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
 | |
| // a post with visibility of followers only.
 | |
| func DefaultInteractionPolicyFollowersOnly() *InteractionPolicy {
 | |
| 	return defaultPolicyFollowersOnly
 | |
| }
 | |
| 
 | |
| var defaultPolicyDirect = &InteractionPolicy{
 | |
| 	CanLike: PolicyRules{
 | |
| 		// Mentioned and self
 | |
| 		// can always like.
 | |
| 		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
 | |
| // for a post with visibility of direct.
 | |
| func DefaultInteractionPolicyDirect() *InteractionPolicy {
 | |
| 	return defaultPolicyDirect
 | |
| }
 |