mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 03:52:24 -05:00 
			
		
		
		
	[feature] Allow users to submit interaction_policy on new statuses (#3314)
		
	* [feature] Parse `interaction_policy` on status submission * beep boop * swagger? i barely know er
This commit is contained in:
		
					parent
					
						
							
								f819229988
							
						
					
				
			
			
				commit
				
					
						c378ad2bb3
					
				
			
		
					 6 changed files with 1342 additions and 413 deletions
				
			
		|  | @ -8826,11 +8826,27 @@ paths: | ||||||
|         post: |         post: | ||||||
|             consumes: |             consumes: | ||||||
|                 - application/json |                 - application/json | ||||||
|                 - application/xml |  | ||||||
|                 - application/x-www-form-urlencoded |                 - application/x-www-form-urlencoded | ||||||
|             description: |- |             description: |- | ||||||
|                 The parameters can also be given in the body of the request, as JSON, if the content-type is set to 'application/json'. |                 The parameters can also be given in the body of the request, as JSON, if the content-type is set to 'application/json'. | ||||||
|                 The parameters can also be given in the body of the request, as XML, if the content-type is set to 'application/xml'. | 
 | ||||||
|  |                 The 'interaction_policy' field can be used to set an interaction policy for this status. | ||||||
|  | 
 | ||||||
|  |                 If submitting using form data, use the following pattern to set an interaction policy: | ||||||
|  | 
 | ||||||
|  |                 `interaction_policy[INTERACTION_TYPE][CONDITION][INDEX]=Value` | ||||||
|  | 
 | ||||||
|  |                 For example: `interaction_policy[can_reply][always][0]=author` | ||||||
|  | 
 | ||||||
|  |                 Using `curl` this might look something like: | ||||||
|  | 
 | ||||||
|  |                 `curl -F 'interaction_policy[can_reply][always][0]=author' -F 'interaction_policy[can_reply][always][1]=followers' [... other form fields ...]` | ||||||
|  | 
 | ||||||
|  |                 The JSON equivalent would be: | ||||||
|  | 
 | ||||||
|  |                 `curl -H 'Content-Type: application/json' -d '{"interaction_policy":{"can_reply":{"always":["author","followers"]}} [... other json fields ...]}'` | ||||||
|  | 
 | ||||||
|  |                 The server will perform some normalization on the submitted policy so that you can't submit something totally invalid. | ||||||
|             operationId: statusCreate |             operationId: statusCreate | ||||||
|             parameters: |             parameters: | ||||||
|                 - description: |- |                 - description: |- | ||||||
|  | @ -8944,6 +8960,30 @@ paths: | ||||||
|                   name: content_type |                   name: content_type | ||||||
|                   type: string |                   type: string | ||||||
|                   x-go-name: ContentType |                   x-go-name: ContentType | ||||||
|  |                 - description: Nth entry for interaction_policy.can_favourite.always. | ||||||
|  |                   in: formData | ||||||
|  |                   name: interaction_policy[can_favourite][always][0] | ||||||
|  |                   type: string | ||||||
|  |                 - description: Nth entry for interaction_policy.can_favourite.with_approval. | ||||||
|  |                   in: formData | ||||||
|  |                   name: interaction_policy[can_favourite][with_approval][0] | ||||||
|  |                   type: string | ||||||
|  |                 - description: Nth entry for interaction_policy.can_reply.always. | ||||||
|  |                   in: formData | ||||||
|  |                   name: interaction_policy[can_reply][always][0] | ||||||
|  |                   type: string | ||||||
|  |                 - description: Nth entry for interaction_policy.can_reply.with_approval. | ||||||
|  |                   in: formData | ||||||
|  |                   name: interaction_policy[can_reply][with_approval][0] | ||||||
|  |                   type: string | ||||||
|  |                 - description: Nth entry for interaction_policy.can_reblog.always. | ||||||
|  |                   in: formData | ||||||
|  |                   name: interaction_policy[can_reblog][always][0] | ||||||
|  |                   type: string | ||||||
|  |                 - description: Nth entry for interaction_policy.can_reblog.with_approval. | ||||||
|  |                   in: formData | ||||||
|  |                   name: interaction_policy[can_reblog][with_approval][0] | ||||||
|  |                   type: string | ||||||
|             produces: |             produces: | ||||||
|                 - application/json |                 - application/json | ||||||
|             responses: |             responses: | ||||||
|  | @ -8966,7 +9006,7 @@ paths: | ||||||
|             security: |             security: | ||||||
|                 - OAuth2 Bearer: |                 - OAuth2 Bearer: | ||||||
|                     - write:statuses |                     - write:statuses | ||||||
|             summary: Create a new status. |             summary: Create a new status using the given form field parameters. | ||||||
|             tags: |             tags: | ||||||
|                 - statuses |                 - statuses | ||||||
|     /api/v1/statuses/{id}: |     /api/v1/statuses/{id}: | ||||||
|  |  | ||||||
|  | @ -222,7 +222,7 @@ func (m *Module) PoliciesDefaultsPATCHHandler(c *gin.Context) { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	form, err := parseUpdateAccountForm(c) | 	form, err := parseUpdatePoliciesForm(c) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1) | 		apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1) | ||||||
| 		return | 		return | ||||||
|  | @ -290,7 +290,7 @@ func customBind( | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func parseUpdateAccountForm(c *gin.Context) (*apimodel.UpdateInteractionPoliciesRequest, error) { | func parseUpdatePoliciesForm(c *gin.Context) (*apimodel.UpdateInteractionPoliciesRequest, error) { | ||||||
| 	form := new(apimodel.UpdateInteractionPoliciesRequest) | 	form := new(apimodel.UpdateInteractionPoliciesRequest) | ||||||
| 
 | 
 | ||||||
| 	switch ct := c.ContentType(); ct { | 	switch ct := c.ContentType(); ct { | ||||||
|  |  | ||||||
|  | @ -24,6 +24,8 @@ import ( | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 
 | 
 | ||||||
| 	"github.com/gin-gonic/gin" | 	"github.com/gin-gonic/gin" | ||||||
|  | 	"github.com/gin-gonic/gin/binding" | ||||||
|  | 	"github.com/go-playground/form/v4" | ||||||
| 	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" | 	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" | ||||||
| 	apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util" | 	apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/config" | 	"github.com/superseriousbusiness/gotosocial/internal/config" | ||||||
|  | @ -35,10 +37,27 @@ import ( | ||||||
| 
 | 
 | ||||||
| // StatusCreatePOSTHandler swagger:operation POST /api/v1/statuses statusCreate | // StatusCreatePOSTHandler swagger:operation POST /api/v1/statuses statusCreate | ||||||
| // | // | ||||||
| // Create a new status. | // Create a new status using the given form field parameters. | ||||||
| // | // | ||||||
| // The parameters can also be given in the body of the request, as JSON, if the content-type is set to 'application/json'. | // The parameters can also be given in the body of the request, as JSON, if the content-type is set to 'application/json'. | ||||||
| // The parameters can also be given in the body of the request, as XML, if the content-type is set to 'application/xml'. | // | ||||||
|  | // The 'interaction_policy' field can be used to set an interaction policy for this status. | ||||||
|  | // | ||||||
|  | // If submitting using form data, use the following pattern to set an interaction policy: | ||||||
|  | // | ||||||
|  | // `interaction_policy[INTERACTION_TYPE][CONDITION][INDEX]=Value` | ||||||
|  | // | ||||||
|  | // For example: `interaction_policy[can_reply][always][0]=author` | ||||||
|  | // | ||||||
|  | // Using `curl` this might look something like: | ||||||
|  | // | ||||||
|  | // `curl -F 'interaction_policy[can_reply][always][0]=author' -F 'interaction_policy[can_reply][always][1]=followers' [... other form fields ...]` | ||||||
|  | // | ||||||
|  | // The JSON equivalent would be: | ||||||
|  | // | ||||||
|  | // `curl -H 'Content-Type: application/json' -d '{"interaction_policy":{"can_reply":{"always":["author","followers"]}} [... other json fields ...]}'` | ||||||
|  | // | ||||||
|  | // The server will perform some normalization on the submitted policy so that you can't submit something totally invalid. | ||||||
| // | // | ||||||
| //	--- | //	--- | ||||||
| //	tags: | //	tags: | ||||||
|  | @ -46,7 +65,6 @@ import ( | ||||||
| // | // | ||||||
| //	consumes: | //	consumes: | ||||||
| //	- application/json | //	- application/json | ||||||
| //	- application/xml |  | ||||||
| //	- application/x-www-form-urlencoded | //	- application/x-www-form-urlencoded | ||||||
| // | // | ||||||
| //	parameters: | //	parameters: | ||||||
|  | @ -181,6 +199,36 @@ import ( | ||||||
| //			- text/plain | //			- text/plain | ||||||
| //			- text/markdown | //			- text/markdown | ||||||
| //		in: formData | //		in: formData | ||||||
|  | //	- | ||||||
|  | //		name: interaction_policy[can_favourite][always][0] | ||||||
|  | //		in: formData | ||||||
|  | //		description: Nth entry for interaction_policy.can_favourite.always. | ||||||
|  | //		type: string | ||||||
|  | //	- | ||||||
|  | //		name: interaction_policy[can_favourite][with_approval][0] | ||||||
|  | //		in: formData | ||||||
|  | //		description: Nth entry for interaction_policy.can_favourite.with_approval. | ||||||
|  | //		type: string | ||||||
|  | //	- | ||||||
|  | //		name: interaction_policy[can_reply][always][0] | ||||||
|  | //		in: formData | ||||||
|  | //		description: Nth entry for interaction_policy.can_reply.always. | ||||||
|  | //		type: string | ||||||
|  | //	- | ||||||
|  | //		name: interaction_policy[can_reply][with_approval][0] | ||||||
|  | //		in: formData | ||||||
|  | //		description: Nth entry for interaction_policy.can_reply.with_approval. | ||||||
|  | //		type: string | ||||||
|  | //	- | ||||||
|  | //		name: interaction_policy[can_reblog][always][0] | ||||||
|  | //		in: formData | ||||||
|  | //		description: Nth entry for interaction_policy.can_reblog.always. | ||||||
|  | //		type: string | ||||||
|  | //	- | ||||||
|  | //		name: interaction_policy[can_reblog][with_approval][0] | ||||||
|  | //		in: formData | ||||||
|  | //		description: Nth entry for interaction_policy.can_reblog.with_approval. | ||||||
|  | //		type: string | ||||||
| // | // | ||||||
| //	produces: | //	produces: | ||||||
| //	- application/json | //	- application/json | ||||||
|  | @ -223,8 +271,8 @@ func (m *Module) StatusCreatePOSTHandler(c *gin.Context) { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	form := &apimodel.StatusCreateRequest{} | 	form, err := parseStatusCreateForm(c) | ||||||
| 	if err := c.ShouldBind(form); err != nil { | 	if err != nil { | ||||||
| 		apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1) | 		apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  | @ -257,6 +305,75 @@ func (m *Module) StatusCreatePOSTHandler(c *gin.Context) { | ||||||
| 	c.JSON(http.StatusOK, apiStatus) | 	c.JSON(http.StatusOK, apiStatus) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // intPolicyFormBinding satisfies gin's binding.Binding interface. | ||||||
|  | // Should only be used specifically for multipart/form-data MIME type. | ||||||
|  | type intPolicyFormBinding struct{} | ||||||
|  | 
 | ||||||
|  | func (i intPolicyFormBinding) Name() string { | ||||||
|  | 	return "InteractionPolicy" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (intPolicyFormBinding) Bind(req *http.Request, obj any) error { | ||||||
|  | 	if err := req.ParseForm(); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Change default namespace prefix and suffix to | ||||||
|  | 	// allow correct parsing of the field attributes. | ||||||
|  | 	decoder := form.NewDecoder() | ||||||
|  | 	decoder.SetNamespacePrefix("[") | ||||||
|  | 	decoder.SetNamespaceSuffix("]") | ||||||
|  | 
 | ||||||
|  | 	return decoder.Decode(obj, req.Form) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func parseStatusCreateForm(c *gin.Context) (*apimodel.StatusCreateRequest, error) { | ||||||
|  | 	form := new(apimodel.StatusCreateRequest) | ||||||
|  | 
 | ||||||
|  | 	switch ct := c.ContentType(); ct { | ||||||
|  | 	case binding.MIMEJSON: | ||||||
|  | 		// Just bind with default json binding. | ||||||
|  | 		if err := c.ShouldBindWith(form, binding.JSON); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 	case binding.MIMEPOSTForm: | ||||||
|  | 		// Bind with default form binding first. | ||||||
|  | 		if err := c.ShouldBindWith(form, binding.FormPost); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// Now do custom binding. | ||||||
|  | 		intReqForm := new(apimodel.StatusInteractionPolicyForm) | ||||||
|  | 		if err := c.ShouldBindWith(intReqForm, intPolicyFormBinding{}); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		form.InteractionPolicy = intReqForm.InteractionPolicy | ||||||
|  | 
 | ||||||
|  | 	case binding.MIMEMultipartPOSTForm: | ||||||
|  | 		// Bind with default form binding first. | ||||||
|  | 		if err := c.ShouldBindWith(form, binding.FormMultipart); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// Now do custom binding. | ||||||
|  | 		intReqForm := new(apimodel.StatusInteractionPolicyForm) | ||||||
|  | 		if err := c.ShouldBindWith(intReqForm, intPolicyFormBinding{}); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		form.InteractionPolicy = intReqForm.InteractionPolicy | ||||||
|  | 
 | ||||||
|  | 	default: | ||||||
|  | 		err := fmt.Errorf( | ||||||
|  | 			"content-type %s not supported for this endpoint; supported content-types are %s, %s, %s", | ||||||
|  | 			ct, binding.MIMEJSON, binding.MIMEPOSTForm, binding.MIMEMultipartPOSTForm, | ||||||
|  | 		) | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return form, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // validateNormalizeCreateStatus checks the form | // validateNormalizeCreateStatus checks the form | ||||||
| // for disallowed combinations of attachments and | // for disallowed combinations of attachments and | ||||||
| // overlength inputs. | // overlength inputs. | ||||||
|  |  | ||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -196,33 +196,44 @@ type StatusCreateRequest struct { | ||||||
| 	// Text content of the status. | 	// Text content of the status. | ||||||
| 	// If media_ids is provided, this becomes optional. | 	// If media_ids is provided, this becomes optional. | ||||||
| 	// Attaching a poll is optional while status is provided. | 	// Attaching a poll is optional while status is provided. | ||||||
| 	Status string `form:"status" json:"status" xml:"status"` | 	Status string `form:"status" json:"status"` | ||||||
| 	// Array of Attachment ids to be attached as media. | 	// Array of Attachment ids to be attached as media. | ||||||
| 	// If provided, status becomes optional, and poll cannot be used. | 	// If provided, status becomes optional, and poll cannot be used. | ||||||
| 	MediaIDs []string `form:"media_ids[]" json:"media_ids" xml:"media_ids"` | 	MediaIDs []string `form:"media_ids[]" json:"media_ids"` | ||||||
| 	// Poll to include with this status. | 	// Poll to include with this status. | ||||||
| 	Poll *PollRequest `form:"poll" json:"poll" xml:"poll"` | 	Poll *PollRequest `form:"poll" json:"poll"` | ||||||
| 	// ID of the status being replied to, if status is a reply. | 	// ID of the status being replied to, if status is a reply. | ||||||
| 	InReplyToID string `form:"in_reply_to_id" json:"in_reply_to_id" xml:"in_reply_to_id"` | 	InReplyToID string `form:"in_reply_to_id" json:"in_reply_to_id"` | ||||||
| 	// Status and attached media should be marked as sensitive. | 	// Status and attached media should be marked as sensitive. | ||||||
| 	Sensitive bool `form:"sensitive" json:"sensitive" xml:"sensitive"` | 	Sensitive bool `form:"sensitive" json:"sensitive"` | ||||||
| 	// Text to be shown as a warning or subject before the actual content. | 	// Text to be shown as a warning or subject before the actual content. | ||||||
| 	// Statuses are generally collapsed behind this field. | 	// Statuses are generally collapsed behind this field. | ||||||
| 	SpoilerText string `form:"spoiler_text" json:"spoiler_text" xml:"spoiler_text"` | 	SpoilerText string `form:"spoiler_text" json:"spoiler_text"` | ||||||
| 	// Visibility of the posted status. | 	// Visibility of the posted status. | ||||||
| 	Visibility Visibility `form:"visibility" json:"visibility" xml:"visibility"` | 	Visibility Visibility `form:"visibility" json:"visibility"` | ||||||
| 	// Set to "true" if this status should not be federated, ie. it should be a "local only" status. | 	// Set to "true" if this status should not be federated, ie. it should be a "local only" status. | ||||||
| 	LocalOnly *bool `form:"local_only"` | 	LocalOnly *bool `form:"local_only" json:"local_only"` | ||||||
| 	// Deprecated: Only used if LocalOnly is not set. | 	// Deprecated: Only used if LocalOnly is not set. | ||||||
| 	Federated *bool `form:"federated"` | 	Federated *bool `form:"federated" json:"federated"` | ||||||
| 	// ISO 8601 Datetime at which to schedule a status. | 	// ISO 8601 Datetime at which to schedule a status. | ||||||
| 	// Providing this parameter will cause ScheduledStatus to be returned instead of Status. | 	// Providing this parameter will cause ScheduledStatus to be returned instead of Status. | ||||||
| 	// Must be at least 5 minutes in the future. | 	// Must be at least 5 minutes in the future. | ||||||
| 	ScheduledAt string `form:"scheduled_at" json:"scheduled_at" xml:"scheduled_at"` | 	ScheduledAt string `form:"scheduled_at" json:"scheduled_at"` | ||||||
| 	// ISO 639 language code for this status. | 	// ISO 639 language code for this status. | ||||||
| 	Language string `form:"language" json:"language" xml:"language"` | 	Language string `form:"language" json:"language"` | ||||||
| 	// Content type to use when parsing this status. | 	// Content type to use when parsing this status. | ||||||
| 	ContentType StatusContentType `form:"content_type" json:"content_type" xml:"content_type"` | 	ContentType StatusContentType `form:"content_type" json:"content_type"` | ||||||
|  | 	// Interaction policy to use for this status. | ||||||
|  | 	InteractionPolicy *InteractionPolicy `form:"-" json:"interaction_policy"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Separate form for parsing interaction | ||||||
|  | // policy on status create requests. | ||||||
|  | // | ||||||
|  | // swagger:ignore | ||||||
|  | type StatusInteractionPolicyForm struct { | ||||||
|  | 	// Interaction policy to use for this status. | ||||||
|  | 	InteractionPolicy *InteractionPolicy `form:"interaction_policy" json:"-"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Visibility models the visibility of a status. | // Visibility models the visibility of a status. | ||||||
|  |  | ||||||
|  | @ -117,14 +117,14 @@ func (p *Processor) Create( | ||||||
| 		return nil, errWithCode | 		return nil, errWithCode | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err := processVisibility(form, requester.Settings.Privacy, status); err != nil { | 	if err := p.processVisibility(ctx, form, requester.Settings.Privacy, status); err != nil { | ||||||
| 		return nil, gtserror.NewErrorInternalError(err) | 		return nil, gtserror.NewErrorInternalError(err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Process policy AFTER visibility as it | 	// Process policy AFTER visibility as it relies | ||||||
| 	// relies on status.Visibility being set. | 	// on status.Visibility and form.Visibility being set. | ||||||
| 	if err := processInteractionPolicy(form, requester.Settings, status); err != nil { | 	if errWithCode := processInteractionPolicy(form, requester.Settings, status); errWithCode != nil { | ||||||
| 		return nil, gtserror.NewErrorInternalError(err) | 		return nil, errWithCode | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err := processLanguage(form, requester.Settings.Language, status); err != nil { | 	if err := processLanguage(form, requester.Settings.Language, status); err != nil { | ||||||
|  | @ -337,7 +337,8 @@ func (p *Processor) processMediaIDs(ctx context.Context, form *apimodel.StatusCr | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func processVisibility( | func (p *Processor) processVisibility( | ||||||
|  | 	ctx context.Context, | ||||||
| 	form *apimodel.StatusCreateRequest, | 	form *apimodel.StatusCreateRequest, | ||||||
| 	accountDefaultVis gtsmodel.Visibility, | 	accountDefaultVis gtsmodel.Visibility, | ||||||
| 	status *gtsmodel.Status, | 	status *gtsmodel.Status, | ||||||
|  | @ -347,13 +348,17 @@ func processVisibility( | ||||||
| 	case form.Visibility != "": | 	case form.Visibility != "": | ||||||
| 		status.Visibility = typeutils.APIVisToVis(form.Visibility) | 		status.Visibility = typeutils.APIVisToVis(form.Visibility) | ||||||
| 
 | 
 | ||||||
| 	// Fall back to account default. | 	// Fall back to account default, set | ||||||
|  | 	// this back on the form for later use. | ||||||
| 	case accountDefaultVis != "": | 	case accountDefaultVis != "": | ||||||
| 		status.Visibility = accountDefaultVis | 		status.Visibility = accountDefaultVis | ||||||
|  | 		form.Visibility = p.converter.VisToAPIVis(ctx, accountDefaultVis) | ||||||
| 
 | 
 | ||||||
| 	// What? Fall back to global default. | 	// What? Fall back to global default, set | ||||||
|  | 	// this back on the form for later use. | ||||||
| 	default: | 	default: | ||||||
| 		status.Visibility = gtsmodel.VisibilityDefault | 		status.Visibility = gtsmodel.VisibilityDefault | ||||||
|  | 		form.Visibility = p.converter.VisToAPIVis(ctx, gtsmodel.VisibilityDefault) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Set federated according to "local_only" field, | 	// Set federated according to "local_only" field, | ||||||
|  | @ -365,17 +370,32 @@ func processVisibility( | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func processInteractionPolicy( | func processInteractionPolicy( | ||||||
| 	_ *apimodel.StatusCreateRequest, | 	form *apimodel.StatusCreateRequest, | ||||||
| 	settings *gtsmodel.AccountSettings, | 	settings *gtsmodel.AccountSettings, | ||||||
| 	status *gtsmodel.Status, | 	status *gtsmodel.Status, | ||||||
| ) error { | ) gtserror.WithCode { | ||||||
| 	// TODO: parse policy for this |  | ||||||
| 	// status from form and prefer this. |  | ||||||
| 
 | 
 | ||||||
|  | 	// If policy is set on the | ||||||
|  | 	// form then prefer this. | ||||||
|  | 	// | ||||||
| 	// TODO: prevent scope widening by | 	// TODO: prevent scope widening by | ||||||
| 	// limiting interaction policy if | 	// limiting interaction policy if | ||||||
| 	// inReplyTo status has a stricter | 	// inReplyTo status has a stricter | ||||||
| 	// interaction policy than this one. | 	// interaction policy than this one. | ||||||
|  | 	if form.InteractionPolicy != nil { | ||||||
|  | 		p, err := typeutils.APIInteractionPolicyToInteractionPolicy( | ||||||
|  | 			form.InteractionPolicy, | ||||||
|  | 			form.Visibility, | ||||||
|  | 		) | ||||||
|  | 
 | ||||||
|  | 		if err != nil { | ||||||
|  | 			errWithCode := gtserror.NewErrorBadRequest(err, err.Error()) | ||||||
|  | 			return errWithCode | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		status.InteractionPolicy = p | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	switch status.Visibility { | 	switch status.Visibility { | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue