diff options
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/api/client/statuses/statuscreate.go | 37 | ||||
| -rw-r--r-- | internal/api/model/status.go | 24 | ||||
| -rw-r--r-- | internal/db/bundb/account_test.go | 2 | ||||
| -rw-r--r-- | internal/filter/visibility/status.go | 32 | ||||
| -rw-r--r-- | internal/filter/visibility/status_test.go | 37 | ||||
| -rw-r--r-- | internal/gtsmodel/status.go | 6 | ||||
| -rw-r--r-- | internal/processing/fedi/collections.go | 12 | ||||
| -rw-r--r-- | internal/processing/status/create.go | 20 | ||||
| -rw-r--r-- | internal/processing/status/create_test.go | 195 | ||||
| -rw-r--r-- | internal/processing/workers/federate.go | 8 | ||||
| -rw-r--r-- | internal/typeutils/internaltofrontend.go | 1 | 
11 files changed, 211 insertions, 163 deletions
diff --git a/internal/api/client/statuses/statuscreate.go b/internal/api/client/statuses/statuscreate.go index 7b30e0ee6..de1581515 100644 --- a/internal/api/client/statuses/statuscreate.go +++ b/internal/api/client/statuses/statuscreate.go @@ -29,6 +29,7 @@ import (  	"github.com/superseriousbusiness/gotosocial/internal/config"  	"github.com/superseriousbusiness/gotosocial/internal/gtserror"  	"github.com/superseriousbusiness/gotosocial/internal/oauth" +	"github.com/superseriousbusiness/gotosocial/internal/util"  	"github.com/superseriousbusiness/gotosocial/internal/validate"  ) @@ -137,6 +138,24 @@ import (  //			- direct  //		in: formData  //	- +//		name: local_only +//		x-go-name: LocalOnly +//		description: >- +//			If set to true, this status will be "local only" and will NOT be federated beyond the local timeline(s). +//			If set to false (default), this status will be federated to your followers beyond the local timeline(s). +//		type: boolean +//		in: formData +//		default: false +//	- +//		name: federated +//		x-go-name: Federated +//		description: >- +//			***DEPRECATED***. Included for back compat only. Only used if set and local_only is not yet. +//			If set to true, this status will be federated beyond the local timeline(s). +//			If set to false, this status will NOT be federated beyond the local timeline(s). +//		in: formData +//		type: boolean +//	-  //		name: scheduled_at  //		x-go-name: ScheduledAt  //		description: |- @@ -162,12 +181,6 @@ import (  //			- text/plain  //			- text/markdown  //		in: formData -//	- -//		name: federated -//		x-go-name: Federated -//		description: This status will be federated beyond the local timeline(s). -//		in: formData -//		type: boolean  //  //	produces:  //	- application/json @@ -210,7 +223,7 @@ func (m *Module) StatusCreatePOSTHandler(c *gin.Context) {  		return  	} -	form := &apimodel.AdvancedStatusCreateForm{} +	form := &apimodel.StatusCreateRequest{}  	if err := c.ShouldBind(form); err != nil {  		apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)  		return @@ -249,7 +262,7 @@ func (m *Module) StatusCreatePOSTHandler(c *gin.Context) {  // overlength inputs.  //  // Side effect: normalizes the post's language tag. -func validateNormalizeCreateStatus(form *apimodel.AdvancedStatusCreateForm) error { +func validateNormalizeCreateStatus(form *apimodel.StatusCreateRequest) error {  	hasStatus := form.Status != ""  	hasMedia := len(form.MediaIDs) != 0  	hasPoll := form.Poll != nil @@ -286,10 +299,16 @@ func validateNormalizeCreateStatus(form *apimodel.AdvancedStatusCreateForm) erro  		form.Language = language  	} +	// Check if the deprecated "federated" field was +	// set in lieu of "local_only", and use it if so. +	if form.LocalOnly == nil && form.Federated != nil { // nolint:staticcheck +		form.LocalOnly = util.Ptr(!*form.Federated) // nolint:staticcheck +	} +  	return nil  } -func validateNormalizeCreatePoll(form *apimodel.AdvancedStatusCreateForm) error { +func validateNormalizeCreatePoll(form *apimodel.StatusCreateRequest) error {  	maxPollOptions := config.GetStatusesPollMaxOptions()  	maxPollChars := config.GetStatusesPollOptionMaxChars() diff --git a/internal/api/model/status.go b/internal/api/model/status.go index b3ac746d7..d0acafae8 100644 --- a/internal/api/model/status.go +++ b/internal/api/model/status.go @@ -46,6 +46,8 @@ type Status struct {  	// Visibility of this status.  	// example: unlisted  	Visibility Visibility `json:"visibility"` +	// Set to "true" if status is not federated, ie., a "local only" status; omitted from response otherwise. +	LocalOnly bool `json:"local_only,omitempty"`  	// Primary language of this status (ISO 639 Part 1 two-letter language code).  	// Will be null if language is not known.  	// example: en @@ -209,6 +211,10 @@ type StatusCreateRequest struct {  	SpoilerText string `form:"spoiler_text" json:"spoiler_text" xml:"spoiler_text"`  	// Visibility of the posted status.  	Visibility Visibility `form:"visibility" json:"visibility" xml:"visibility"` +	// Set to "true" if this status should not be federated, ie. it should be a "local only" status. +	LocalOnly *bool `form:"local_only"` +	// Deprecated: Only used if LocalOnly is not set. +	Federated *bool `form:"federated"`  	// ISO 8601 Datetime at which to schedule a status.  	// Providing this parameter will cause ScheduledStatus to be returned instead of Status.  	// Must be at least 5 minutes in the future. @@ -238,24 +244,6 @@ const (  	VisibilityDirect Visibility = "direct"  ) -// AdvancedStatusCreateForm wraps the mastodon-compatible status create form along with the GTS advanced -// visibility settings. -// -// swagger:ignore -type AdvancedStatusCreateForm struct { -	StatusCreateRequest -	AdvancedVisibilityFlagsForm -} - -// AdvancedVisibilityFlagsForm allows a few more advanced flags to be set on new statuses, in addition -// to the standard mastodon-compatible ones. -// -// swagger:ignore -type AdvancedVisibilityFlagsForm struct { -	// This status will be federated beyond the local timeline(s). -	Federated *bool `form:"federated" json:"federated" xml:"federated"` -} -  // StatusContentType is the content type with which to parse the submitted status.  // Can be either text/plain or text/markdown. Empty will default to text/plain.  // diff --git a/internal/db/bundb/account_test.go b/internal/db/bundb/account_test.go index 28c9274f7..2caffdeb1 100644 --- a/internal/db/bundb/account_test.go +++ b/internal/db/bundb/account_test.go @@ -86,7 +86,7 @@ func (suite *AccountTestSuite) TestGetAccountStatusesExcludeRepliesAndReblogs()  func (suite *AccountTestSuite) TestGetAccountStatusesExcludeRepliesAndReblogsPublicOnly() {  	statuses, err := suite.db.GetAccountStatuses(context.Background(), suite.testAccounts["local_account_1"].ID, 20, true, true, "", "", false, true)  	suite.NoError(err) -	suite.Len(statuses, 2) +	suite.Len(statuses, 3)  }  // populateTestStatus adds mandatory fields to a partially populated status. diff --git a/internal/filter/visibility/status.go b/internal/filter/visibility/status.go index be1c6a350..fdeefedde 100644 --- a/internal/filter/visibility/status.go +++ b/internal/filter/visibility/status.go @@ -97,10 +97,10 @@ func (f *Filter) isStatusVisible(  	}  	// Check whether status accounts are visible to the requester. -	visible, err := f.areStatusAccountsVisible(ctx, requester, status) +	acctsVisible, err := f.areStatusAccountsVisible(ctx, requester, status)  	if err != nil {  		return false, gtserror.Newf("error checking status %s account visibility: %w", status.ID, err) -	} else if !visible { +	} else if !acctsVisible {  		return false, nil  	} @@ -112,22 +112,34 @@ func (f *Filter) isStatusVisible(  		)  	} -	if status.Visibility == gtsmodel.VisibilityPublic { -		// This status will be visible to all. -		return true, nil +	if requester == nil { +		// The request is unauthed. Only federated, Public statuses are visible without auth. +		visibleUnauthed := !status.IsLocalOnly() && status.Visibility == gtsmodel.VisibilityPublic +		return visibleUnauthed, nil  	} -	if requester == nil { -		// This request is WITHOUT auth, and status is NOT public. -		log.Trace(ctx, "unauthorized request to non-public status") +	/* +		From this point down we know the request is authed. +	*/ + +	if requester.IsRemote() && status.IsLocalOnly() { +		// Remote accounts can't see local-only +		// posts regardless of their visibility.  		return false, nil  	} -	if status.Visibility == gtsmodel.VisibilityUnlocked { -		// This status is visible to all auth'd accounts. +	if status.Visibility == gtsmodel.VisibilityPublic || +		status.Visibility == gtsmodel.VisibilityUnlocked { +		// This status is visible to all auth'd accounts +		// (pending blocks, which we already checked above).  		return true, nil  	} +	/* +		From this point down we know the request +		is of visibility followers-only or below. +	*/ +  	if requester.ID == status.AccountID {  		// Author can always see their own status.  		return true, nil diff --git a/internal/filter/visibility/status_test.go b/internal/filter/visibility/status_test.go index 6f8bb12b4..9b210e500 100644 --- a/internal/filter/visibility/status_test.go +++ b/internal/filter/visibility/status_test.go @@ -200,6 +200,43 @@ func (suite *StatusVisibleTestSuite) TestVisiblePending() {  	}  } +func (suite *StatusVisibleTestSuite) TestVisibleLocalOnly() { +	ctx := context.Background() + +	// Local-only, Public status. +	testStatus := suite.testStatuses["local_account_2_status_4"] + +	for _, testCase := range []struct { +		acct    *gtsmodel.Account +		visible bool +	}{ +		{ +			acct:    suite.testAccounts["local_account_2"], +			visible: true, // Own status, always visible. +		}, +		{ +			acct:    nil, +			visible: false, // No auth, should not be visible.. +		}, +		{ +			acct:    suite.testAccounts["local_account_1"], +			visible: true, // Local account, should be visible. +		}, +		{ +			acct:    suite.testAccounts["remote_account_1"], +			visible: false, // Blocked account, should not be visible. +		}, +		{ +			acct:    suite.testAccounts["remote_account_2"], +			visible: false, // Remote account, should not be visible. +		}, +	} { +		visible, err := suite.filter.StatusVisible(ctx, testCase.acct, testStatus) +		suite.NoError(err) +		suite.Equal(testCase.visible, visible) +	} +} +  func TestStatusVisibleTestSuite(t *testing.T) {  	suite.Run(t, new(StatusVisibleTestSuite))  } diff --git a/internal/gtsmodel/status.go b/internal/gtsmodel/status.go index 5f50fb046..70fd9c367 100644 --- a/internal/gtsmodel/status.go +++ b/internal/gtsmodel/status.go @@ -212,6 +212,12 @@ func (s *Status) IsLocal() bool {  	return s.Local != nil && *s.Local  } +// IsLocalOnly returns true if this status +// is "local-only" ie., unfederated. +func (s *Status) IsLocalOnly() bool { +	return s.Federated == nil || !*s.Federated +} +  // StatusToTag is an intermediate struct to facilitate the many2many relationship between a status and one or more tags.  type StatusToTag struct {  	StatusID string  `bun:"type:CHAR(26),unique:statustag,nullzero,notnull"` diff --git a/internal/processing/fedi/collections.go b/internal/processing/fedi/collections.go index e81d3e269..fd84e7688 100644 --- a/internal/processing/fedi/collections.go +++ b/internal/processing/fedi/collections.go @@ -129,6 +129,18 @@ func (p *Processor) OutboxGet(  			hi = statuses[0].ID  		} +		// Reslice statuses dropping all those invisible to requester +		// (eg., local-only statuses, if the requester is remote). +		statuses, err = p.visFilter.StatusesVisible( +			ctx, +			auth.requestingAcct, +			statuses, +		) +		if err != nil { +			err := gtserror.Newf("error filtering statuses: %w", err) +			return nil, gtserror.NewErrorInternalError(err) +		} +  		// Start building AS collection page params.  		params.Total = util.Ptr(*receivingAcct.Stats.StatusesCount)  		var pageParams ap.CollectionPageParams diff --git a/internal/processing/status/create.go b/internal/processing/status/create.go index 11dece87d..d5898ffe9 100644 --- a/internal/processing/status/create.go +++ b/internal/processing/status/create.go @@ -45,7 +45,7 @@ func (p *Processor) Create(  	ctx context.Context,  	requester *gtsmodel.Account,  	application *gtsmodel.Application, -	form *apimodel.AdvancedStatusCreateForm, +	form *apimodel.StatusCreateRequest,  ) (  	*apimodel.Status,  	gtserror.WithCode, @@ -290,7 +290,7 @@ func (p *Processor) processThreadID(ctx context.Context, status *gtsmodel.Status  	return nil  } -func (p *Processor) processMediaIDs(ctx context.Context, form *apimodel.AdvancedStatusCreateForm, thisAccountID string, status *gtsmodel.Status) gtserror.WithCode { +func (p *Processor) processMediaIDs(ctx context.Context, form *apimodel.StatusCreateRequest, thisAccountID string, status *gtsmodel.Status) gtserror.WithCode {  	if form.MediaIDs == nil {  		return nil  	} @@ -338,7 +338,7 @@ func (p *Processor) processMediaIDs(ctx context.Context, form *apimodel.Advanced  }  func processVisibility( -	form *apimodel.AdvancedStatusCreateForm, +	form *apimodel.StatusCreateRequest,  	accountDefaultVis gtsmodel.Visibility,  	status *gtsmodel.Status,  ) error { @@ -356,16 +356,16 @@ func processVisibility(  		status.Visibility = gtsmodel.VisibilityDefault  	} -	// Set federated flag to form value -	// if provided, or default to true. -	federated := util.PtrOrValue(form.Federated, true) -	status.Federated = &federated +	// Set federated according to "local_only" field, +	// assuming federated (ie., not local-only) by default. +	localOnly := util.PtrOrValue(form.LocalOnly, false) +	status.Federated = util.Ptr(!localOnly)  	return nil  }  func processInteractionPolicy( -	_ *apimodel.AdvancedStatusCreateForm, +	_ *apimodel.StatusCreateRequest,  	settings *gtsmodel.AccountSettings,  	status *gtsmodel.Status,  ) error { @@ -413,7 +413,7 @@ func processInteractionPolicy(  	return nil  } -func processLanguage(form *apimodel.AdvancedStatusCreateForm, accountDefaultLanguage string, status *gtsmodel.Status) error { +func processLanguage(form *apimodel.StatusCreateRequest, accountDefaultLanguage string, status *gtsmodel.Status) error {  	if form.Language != "" {  		status.Language = form.Language  	} else { @@ -425,7 +425,7 @@ func processLanguage(form *apimodel.AdvancedStatusCreateForm, accountDefaultLang  	return nil  } -func (p *Processor) processContent(ctx context.Context, parseMention gtsmodel.ParseMentionFunc, form *apimodel.AdvancedStatusCreateForm, status *gtsmodel.Status) error { +func (p *Processor) processContent(ctx context.Context, parseMention gtsmodel.ParseMentionFunc, form *apimodel.StatusCreateRequest, status *gtsmodel.Status) error {  	if form.ContentType == "" {  		// If content type wasn't specified, use the author's preferred content-type.  		contentType := apimodel.StatusContentType(status.Account.Settings.StatusContentType) diff --git a/internal/processing/status/create_test.go b/internal/processing/status/create_test.go index a8211d1c1..84168880e 100644 --- a/internal/processing/status/create_test.go +++ b/internal/processing/status/create_test.go @@ -26,6 +26,7 @@ import (  	"github.com/superseriousbusiness/gotosocial/internal/config"  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +	"github.com/superseriousbusiness/gotosocial/internal/util"  )  type StatusCreateTestSuite struct { @@ -38,22 +39,18 @@ func (suite *StatusCreateTestSuite) TestProcessContentWarningWithQuotationMarks(  	creatingAccount := suite.testAccounts["local_account_1"]  	creatingApplication := suite.testApplications["application_1"] -	statusCreateForm := &apimodel.AdvancedStatusCreateForm{ -		StatusCreateRequest: apimodel.StatusCreateRequest{ -			Status:      "poopoo peepee", -			MediaIDs:    []string{}, -			Poll:        nil, -			InReplyToID: "", -			Sensitive:   false, -			SpoilerText: "\"test\"", // these should not be html-escaped when the final text is rendered -			Visibility:  apimodel.VisibilityPublic, -			ScheduledAt: "", -			Language:    "en", -			ContentType: apimodel.StatusContentTypePlain, -		}, -		AdvancedVisibilityFlagsForm: apimodel.AdvancedVisibilityFlagsForm{ -			Federated: nil, -		}, +	statusCreateForm := &apimodel.StatusCreateRequest{ +		Status:      "poopoo peepee", +		MediaIDs:    []string{}, +		Poll:        nil, +		InReplyToID: "", +		Sensitive:   false, +		SpoilerText: "\"test\"", // these should not be html-escaped when the final text is rendered +		Visibility:  apimodel.VisibilityPublic, +		LocalOnly:   util.Ptr(false), +		ScheduledAt: "", +		Language:    "en", +		ContentType: apimodel.StatusContentTypePlain,  	}  	apiStatus, err := suite.status.Create(ctx, creatingAccount, creatingApplication, statusCreateForm) @@ -69,22 +66,18 @@ func (suite *StatusCreateTestSuite) TestProcessContentWarningWithHTMLEscapedQuot  	creatingAccount := suite.testAccounts["local_account_1"]  	creatingApplication := suite.testApplications["application_1"] -	statusCreateForm := &apimodel.AdvancedStatusCreateForm{ -		StatusCreateRequest: apimodel.StatusCreateRequest{ -			Status:      "poopoo peepee", -			MediaIDs:    []string{}, -			Poll:        nil, -			InReplyToID: "", -			Sensitive:   false, -			SpoilerText: ""test"", // the html-escaped quotation marks should appear as normal quotation marks in the finished text -			Visibility:  apimodel.VisibilityPublic, -			ScheduledAt: "", -			Language:    "en", -			ContentType: apimodel.StatusContentTypePlain, -		}, -		AdvancedVisibilityFlagsForm: apimodel.AdvancedVisibilityFlagsForm{ -			Federated: nil, -		}, +	statusCreateForm := &apimodel.StatusCreateRequest{ +		Status:      "poopoo peepee", +		MediaIDs:    []string{}, +		Poll:        nil, +		InReplyToID: "", +		Sensitive:   false, +		SpoilerText: ""test"", // the html-escaped quotation marks should appear as normal quotation marks in the finished text +		Visibility:  apimodel.VisibilityPublic, +		LocalOnly:   util.Ptr(false), +		ScheduledAt: "", +		Language:    "en", +		ContentType: apimodel.StatusContentTypePlain,  	}  	apiStatus, err := suite.status.Create(ctx, creatingAccount, creatingApplication, statusCreateForm) @@ -105,21 +98,17 @@ func (suite *StatusCreateTestSuite) TestProcessStatusMarkdownWithUnderscoreEmoji  	creatingAccount := suite.testAccounts["local_account_1"]  	creatingApplication := suite.testApplications["application_1"] -	statusCreateForm := &apimodel.AdvancedStatusCreateForm{ -		StatusCreateRequest: apimodel.StatusCreateRequest{ -			Status:      "poopoo peepee :_rainbow_:", -			MediaIDs:    []string{}, -			Poll:        nil, -			InReplyToID: "", -			Sensitive:   false, -			Visibility:  apimodel.VisibilityPublic, -			ScheduledAt: "", -			Language:    "en", -			ContentType: apimodel.StatusContentTypeMarkdown, -		}, -		AdvancedVisibilityFlagsForm: apimodel.AdvancedVisibilityFlagsForm{ -			Federated: nil, -		}, +	statusCreateForm := &apimodel.StatusCreateRequest{ +		Status:      "poopoo peepee :_rainbow_:", +		MediaIDs:    []string{}, +		Poll:        nil, +		InReplyToID: "", +		Sensitive:   false, +		Visibility:  apimodel.VisibilityPublic, +		LocalOnly:   util.Ptr(false), +		ScheduledAt: "", +		Language:    "en", +		ContentType: apimodel.StatusContentTypeMarkdown,  	}  	apiStatus, err := suite.status.Create(ctx, creatingAccount, creatingApplication, statusCreateForm) @@ -135,22 +124,18 @@ func (suite *StatusCreateTestSuite) TestProcessStatusMarkdownWithSpoilerTextEmoj  	creatingAccount := suite.testAccounts["local_account_1"]  	creatingApplication := suite.testApplications["application_1"] -	statusCreateForm := &apimodel.AdvancedStatusCreateForm{ -		StatusCreateRequest: apimodel.StatusCreateRequest{ -			Status:      "poopoo peepee", -			SpoilerText: "testing something :rainbow:", -			MediaIDs:    []string{}, -			Poll:        nil, -			InReplyToID: "", -			Sensitive:   false, -			Visibility:  apimodel.VisibilityPublic, -			ScheduledAt: "", -			Language:    "en", -			ContentType: apimodel.StatusContentTypeMarkdown, -		}, -		AdvancedVisibilityFlagsForm: apimodel.AdvancedVisibilityFlagsForm{ -			Federated: nil, -		}, +	statusCreateForm := &apimodel.StatusCreateRequest{ +		Status:      "poopoo peepee", +		SpoilerText: "testing something :rainbow:", +		MediaIDs:    []string{}, +		Poll:        nil, +		InReplyToID: "", +		Sensitive:   false, +		Visibility:  apimodel.VisibilityPublic, +		LocalOnly:   util.Ptr(false), +		ScheduledAt: "", +		Language:    "en", +		ContentType: apimodel.StatusContentTypeMarkdown,  	}  	apiStatus, err := suite.status.Create(ctx, creatingAccount, creatingApplication, statusCreateForm) @@ -170,22 +155,18 @@ func (suite *StatusCreateTestSuite) TestProcessMediaDescriptionTooShort() {  	creatingAccount := suite.testAccounts["local_account_1"]  	creatingApplication := suite.testApplications["application_1"] -	statusCreateForm := &apimodel.AdvancedStatusCreateForm{ -		StatusCreateRequest: apimodel.StatusCreateRequest{ -			Status:      "poopoo peepee", -			MediaIDs:    []string{suite.testAttachments["local_account_1_unattached_1"].ID}, -			Poll:        nil, -			InReplyToID: "", -			Sensitive:   false, -			SpoilerText: "", -			Visibility:  apimodel.VisibilityPublic, -			ScheduledAt: "", -			Language:    "en", -			ContentType: apimodel.StatusContentTypePlain, -		}, -		AdvancedVisibilityFlagsForm: apimodel.AdvancedVisibilityFlagsForm{ -			Federated: nil, -		}, +	statusCreateForm := &apimodel.StatusCreateRequest{ +		Status:      "poopoo peepee", +		MediaIDs:    []string{suite.testAttachments["local_account_1_unattached_1"].ID}, +		Poll:        nil, +		InReplyToID: "", +		Sensitive:   false, +		SpoilerText: "", +		Visibility:  apimodel.VisibilityPublic, +		LocalOnly:   util.Ptr(false), +		ScheduledAt: "", +		Language:    "en", +		ContentType: apimodel.StatusContentTypePlain,  	}  	apiStatus, err := suite.status.Create(ctx, creatingAccount, creatingApplication, statusCreateForm) @@ -199,22 +180,18 @@ func (suite *StatusCreateTestSuite) TestProcessLanguageWithScriptPart() {  	creatingAccount := suite.testAccounts["local_account_1"]  	creatingApplication := suite.testApplications["application_1"] -	statusCreateForm := &apimodel.AdvancedStatusCreateForm{ -		StatusCreateRequest: apimodel.StatusCreateRequest{ -			Status:      "你好世界", // hello world -			MediaIDs:    []string{}, -			Poll:        nil, -			InReplyToID: "", -			Sensitive:   false, -			SpoilerText: "", -			Visibility:  apimodel.VisibilityPublic, -			ScheduledAt: "", -			Language:    "zh-Hans", -			ContentType: apimodel.StatusContentTypePlain, -		}, -		AdvancedVisibilityFlagsForm: apimodel.AdvancedVisibilityFlagsForm{ -			Federated: nil, -		}, +	statusCreateForm := &apimodel.StatusCreateRequest{ +		Status:      "你好世界", // hello world +		MediaIDs:    []string{}, +		Poll:        nil, +		InReplyToID: "", +		Sensitive:   false, +		SpoilerText: "", +		Visibility:  apimodel.VisibilityPublic, +		LocalOnly:   util.Ptr(false), +		ScheduledAt: "", +		Language:    "zh-Hans", +		ContentType: apimodel.StatusContentTypePlain,  	}  	apiStatus, err := suite.status.Create(ctx, creatingAccount, creatingApplication, statusCreateForm) @@ -233,22 +210,18 @@ func (suite *StatusCreateTestSuite) TestProcessReplyToUnthreadedRemoteStatus() {  	// Reply to a remote status that  	// doesn't have a threadID set on it. -	statusCreateForm := &apimodel.AdvancedStatusCreateForm{ -		StatusCreateRequest: apimodel.StatusCreateRequest{ -			Status:      "boobies", -			MediaIDs:    []string{}, -			Poll:        nil, -			InReplyToID: inReplyTo.ID, -			Sensitive:   false, -			SpoilerText: "this is a reply", -			Visibility:  apimodel.VisibilityPublic, -			ScheduledAt: "", -			Language:    "en", -			ContentType: apimodel.StatusContentTypePlain, -		}, -		AdvancedVisibilityFlagsForm: apimodel.AdvancedVisibilityFlagsForm{ -			Federated: nil, -		}, +	statusCreateForm := &apimodel.StatusCreateRequest{ +		Status:      "boobies", +		MediaIDs:    []string{}, +		Poll:        nil, +		InReplyToID: inReplyTo.ID, +		Sensitive:   false, +		SpoilerText: "this is a reply", +		Visibility:  apimodel.VisibilityPublic, +		LocalOnly:   util.Ptr(false), +		ScheduledAt: "", +		Language:    "en", +		ContentType: apimodel.StatusContentTypePlain,  	}  	apiStatus, err := suite.status.Create(ctx, creatingAccount, creatingApplication, statusCreateForm) diff --git a/internal/processing/workers/federate.go b/internal/processing/workers/federate.go index d71bb0a83..6e8b558c8 100644 --- a/internal/processing/workers/federate.go +++ b/internal/processing/workers/federate.go @@ -146,7 +146,7 @@ func (f *federate) DeleteAccount(ctx context.Context, account *gtsmodel.Account)  func (f *federate) CreateStatus(ctx context.Context, status *gtsmodel.Status) error {  	// Do nothing if the status  	// shouldn't be federated. -	if !*status.Federated { +	if status.IsLocalOnly() {  		return nil  	} @@ -201,7 +201,7 @@ func (f *federate) CreatePollVote(ctx context.Context, poll *gtsmodel.Poll, vote  	// Do nothing if the status  	// shouldn't be federated. -	if !*status.Federated { +	if status.IsLocalOnly() {  		return nil  	} @@ -234,7 +234,7 @@ func (f *federate) CreatePollVote(ctx context.Context, poll *gtsmodel.Poll, vote  func (f *federate) DeleteStatus(ctx context.Context, status *gtsmodel.Status) error {  	// Do nothing if the status  	// shouldn't be federated. -	if !*status.Federated { +	if status.IsLocalOnly() {  		return nil  	} @@ -272,7 +272,7 @@ func (f *federate) DeleteStatus(ctx context.Context, status *gtsmodel.Status) er  func (f *federate) UpdateStatus(ctx context.Context, status *gtsmodel.Status) error {  	// Do nothing if the status  	// shouldn't be federated. -	if !*status.Federated { +	if status.IsLocalOnly() {  		return nil  	} diff --git a/internal/typeutils/internaltofrontend.go b/internal/typeutils/internaltofrontend.go index 682d76775..4ed65bb08 100644 --- a/internal/typeutils/internaltofrontend.go +++ b/internal/typeutils/internaltofrontend.go @@ -1333,6 +1333,7 @@ func (c *Converter) baseStatusToFrontend(  		Sensitive:          *s.Sensitive,  		SpoilerText:        s.ContentWarning,  		Visibility:         c.VisToAPIVis(ctx, s.Visibility), +		LocalOnly:          s.IsLocalOnly(),  		Language:           nil, // Set below.  		URI:                s.URI,  		URL:                s.URL,  | 
