mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 10:52:28 -05:00 
			
		
		
		
	some updates to statuses and accounts
This commit is contained in:
		
					parent
					
						
							
								30718d7d10
							
						
					
				
			
			
				commit
				
					
						0b8b0948f6
					
				
			
		
					 11 changed files with 251 additions and 132 deletions
				
			
		|  | @ -32,6 +32,8 @@ import ( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| const ( | const ( | ||||||
|  | 	// LimitKey is for setting the return amount limit for eg., requesting an account's statuses | ||||||
|  | 	LimitKey = "limit" | ||||||
| 	// IDKey is the key to use for retrieving account ID in requests | 	// IDKey is the key to use for retrieving account ID in requests | ||||||
| 	IDKey = "id" | 	IDKey = "id" | ||||||
| 	// BasePath is the base API path for this module | 	// BasePath is the base API path for this module | ||||||
|  | @ -42,6 +44,8 @@ const ( | ||||||
| 	VerifyPath = BasePath + "/verify_credentials" | 	VerifyPath = BasePath + "/verify_credentials" | ||||||
| 	// UpdateCredentialsPath is for updating account credentials | 	// UpdateCredentialsPath is for updating account credentials | ||||||
| 	UpdateCredentialsPath = BasePath + "/update_credentials" | 	UpdateCredentialsPath = BasePath + "/update_credentials" | ||||||
|  | 	// GetStatusesPath is for showing an account's statuses | ||||||
|  | 	GetStatusesPath = BasePathWithID + "/statuses" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Module implements the ClientAPIModule interface for account-related actions | // Module implements the ClientAPIModule interface for account-related actions | ||||||
|  | @ -65,6 +69,7 @@ func (m *Module) Route(r router.Router) error { | ||||||
| 	r.AttachHandler(http.MethodPost, BasePath, m.AccountCreatePOSTHandler) | 	r.AttachHandler(http.MethodPost, BasePath, m.AccountCreatePOSTHandler) | ||||||
| 	r.AttachHandler(http.MethodGet, BasePathWithID, m.muxHandler) | 	r.AttachHandler(http.MethodGet, BasePathWithID, m.muxHandler) | ||||||
| 	r.AttachHandler(http.MethodPatch, BasePathWithID, m.muxHandler) | 	r.AttachHandler(http.MethodPatch, BasePathWithID, m.muxHandler) | ||||||
|  | 	r.AttachHandler(http.MethodGet, GetStatusesPath, m.AccountStatusesGETHandler) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										61
									
								
								internal/api/client/account/statuses.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								internal/api/client/account/statuses.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,61 @@ | ||||||
|  | /* | ||||||
|  |    GoToSocial | ||||||
|  |    Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org | ||||||
|  | 
 | ||||||
|  |    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 account | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"net/http" | ||||||
|  | 	"strconv" | ||||||
|  | 
 | ||||||
|  | 	"github.com/gin-gonic/gin" | ||||||
|  | 	"github.com/superseriousbusiness/gotosocial/internal/oauth" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // AccountStatusesGETHandler serves the statuses of the requested account, if they're visible to the requester. | ||||||
|  | func (m *Module) AccountStatusesGETHandler(c *gin.Context) { | ||||||
|  | 	authed, err := oauth.Authed(c, false, false, false, false) | ||||||
|  | 	if err != nil { | ||||||
|  | 		c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	targetAcctID := c.Param(IDKey) | ||||||
|  | 	if targetAcctID == "" { | ||||||
|  | 		c.JSON(http.StatusBadRequest, gin.H{"error": "no account id specified"}) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	limit := 30 | ||||||
|  | 	limitString := c.Query(LimitKey) | ||||||
|  | 	if limitString != "" { | ||||||
|  | 		l, err := strconv.ParseInt(limitString, 10, 64) | ||||||
|  | 		if err != nil { | ||||||
|  | 			c.JSON(http.StatusBadRequest, gin.H{"error": "couldn't parse limit query param"}) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		limit = int(l) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	statuses, errWithCode := m.processor.AccountStatusesGet(authed, targetAcctID, limit) | ||||||
|  | 	if errWithCode != nil { | ||||||
|  | 		c.JSON(errWithCode.Code(), gin.H{"error": errWithCode.Safe()}) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	c.JSON(http.StatusOK, statuses) | ||||||
|  | } | ||||||
|  | @ -86,23 +86,23 @@ type Status struct { | ||||||
| // It should be used at the path https://mastodon.example/api/v1/statuses | // It should be used at the path https://mastodon.example/api/v1/statuses | ||||||
| type StatusCreateRequest struct { | type StatusCreateRequest struct { | ||||||
| 	// Text content of the status. If media_ids is provided, this becomes optional. Attaching a poll is optional while status is provided. | 	// Text content of the status. If media_ids is provided, this becomes optional. Attaching a poll is optional while status is provided. | ||||||
| 	Status string `form:"status"` | 	Status string `form:"status" json:"status" xml:"status"` | ||||||
| 	// Array of Attachment ids to be attached as media. If provided, status becomes optional, and poll cannot be used. | 	// Array of Attachment ids to be attached as media. 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" xml:"media_ids"` | ||||||
| 	// Poll to include with this status. | 	// Poll to include with this status. | ||||||
| 	Poll *PollRequest `form:"poll"` | 	Poll *PollRequest `form:"poll" json:"poll" xml:"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"` | 	InReplyToID string `form:"in_reply_to_id" json:"in_reply_to_id" xml:"in_reply_to_id"` | ||||||
| 	// Mark status and attached media as sensitive? | 	// Mark status and attached media as sensitive? | ||||||
| 	Sensitive bool `form:"sensitive"` | 	Sensitive bool `form:"sensitive" json:"sensitive" xml:"sensitive"` | ||||||
| 	// Text to be shown as a warning or subject before the actual content. Statuses are generally collapsed behind this field. | 	// Text to be shown as a warning or subject before the actual content. Statuses are generally collapsed behind this field. | ||||||
| 	SpoilerText string `form:"spoiler_text"` | 	SpoilerText string `form:"spoiler_text" json:"spoiler_text" xml:"spoiler_text"` | ||||||
| 	// Visibility of the posted status. Enumerable oneOf public, unlisted, private, direct. | 	// Visibility of the posted status. Enumerable oneOf public, unlisted, private, direct. | ||||||
| 	Visibility Visibility `form:"visibility"` | 	Visibility Visibility `form:"visibility" json:"visibility" xml:"visibility"` | ||||||
| 	// ISO 8601 Datetime at which to schedule a status. Providing this paramter will cause ScheduledStatus to be returned instead of Status. Must be at least 5 minutes in the future. | 	// ISO 8601 Datetime at which to schedule a status. Providing this paramter will cause ScheduledStatus to be returned instead of Status. Must be at least 5 minutes in the future. | ||||||
| 	ScheduledAt string `form:"scheduled_at"` | 	ScheduledAt string `form:"scheduled_at" json:"scheduled_at" xml:"scheduled_at"` | ||||||
| 	// ISO 639 language code for this status. | 	// ISO 639 language code for this status. | ||||||
| 	Language string `form:"language"` | 	Language string `form:"language" json:"language" xml:"language"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Visibility denotes the visibility of this status to other users | // Visibility denotes the visibility of this status to other users | ||||||
|  | @ -130,13 +130,13 @@ type AdvancedStatusCreateForm struct { | ||||||
| // to the standard mastodon-compatible ones. | // to the standard mastodon-compatible ones. | ||||||
| type AdvancedVisibilityFlagsForm struct { | type AdvancedVisibilityFlagsForm struct { | ||||||
| 	// The gotosocial visibility model | 	// The gotosocial visibility model | ||||||
| 	VisibilityAdvanced *string `form:"visibility_advanced"` | 	VisibilityAdvanced *string `form:"visibility_advanced" json:"visibility_advanced" xml:"visibility_advanced"` | ||||||
| 	// This status will be federated beyond the local timeline(s) | 	// This status will be federated beyond the local timeline(s) | ||||||
| 	Federated *bool `form:"federated"` | 	Federated *bool `form:"federated" json:"federated" xml:"federated"` | ||||||
| 	// This status can be boosted/reblogged | 	// This status can be boosted/reblogged | ||||||
| 	Boostable *bool `form:"boostable"` | 	Boostable *bool `form:"boostable" json:"boostable" xml:"boostable"` | ||||||
| 	// This status can be replied to | 	// This status can be replied to | ||||||
| 	Replyable *bool `form:"replyable"` | 	Replyable *bool `form:"replyable" json:"replyable" xml:"replyable"` | ||||||
| 	// This status can be liked/faved | 	// This status can be liked/faved | ||||||
| 	Likeable *bool `form:"likeable"` | 	Likeable *bool `form:"likeable" json:"likeable" xml:"likeable"` | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -364,7 +364,7 @@ func (f *federatingDB) Get(c context.Context, id *url.URL) (value vocab.Type, er | ||||||
| // | // | ||||||
| // Under certain conditions and network activities, Create may be called | // Under certain conditions and network activities, Create may be called | ||||||
| // multiple times for the same ActivityStreams object. | // multiple times for the same ActivityStreams object. | ||||||
| func (f *federatingDB) Create(c context.Context, asType vocab.Type) error { | func (f *federatingDB) Create(ctx context.Context, asType vocab.Type) error { | ||||||
| 	l := f.log.WithFields( | 	l := f.log.WithFields( | ||||||
| 		logrus.Fields{ | 		logrus.Fields{ | ||||||
| 			"func":   "Create", | 			"func":   "Create", | ||||||
|  | @ -373,6 +373,24 @@ func (f *federatingDB) Create(c context.Context, asType vocab.Type) error { | ||||||
| 	) | 	) | ||||||
| 	l.Debugf("received CREATE asType %+v", asType) | 	l.Debugf("received CREATE asType %+v", asType) | ||||||
| 
 | 
 | ||||||
|  | 	targetAcctI := ctx.Value(util.APAccount) | ||||||
|  | 	if targetAcctI == nil { | ||||||
|  | 		l.Error("target account wasn't set on context") | ||||||
|  | 	} | ||||||
|  | 	targetAcct, ok := targetAcctI.(*gtsmodel.Account) | ||||||
|  | 	if !ok { | ||||||
|  | 		l.Error("target account was set on context but couldn't be parsed") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	fromFederatorChanI := ctx.Value(util.APFromFederatorChanKey) | ||||||
|  | 	if fromFederatorChanI == nil { | ||||||
|  | 		l.Error("from federator channel wasn't set on context") | ||||||
|  | 	} | ||||||
|  | 	fromFederatorChan, ok := fromFederatorChanI.(chan gtsmodel.FromFederator) | ||||||
|  | 	if !ok { | ||||||
|  | 		l.Error("from federator channel was set on context but couldn't be parsed") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	switch gtsmodel.ActivityStreamsActivity(asType.GetTypeName()) { | 	switch gtsmodel.ActivityStreamsActivity(asType.GetTypeName()) { | ||||||
| 	case gtsmodel.ActivityStreamsCreate: | 	case gtsmodel.ActivityStreamsCreate: | ||||||
| 		create, ok := asType.(vocab.ActivityStreamsCreate) | 		create, ok := asType.(vocab.ActivityStreamsCreate) | ||||||
|  | @ -391,6 +409,12 @@ func (f *federatingDB) Create(c context.Context, asType vocab.Type) error { | ||||||
| 				if err := f.db.Put(status); err != nil { | 				if err := f.db.Put(status); err != nil { | ||||||
| 					return fmt.Errorf("database error inserting status: %s", err) | 					return fmt.Errorf("database error inserting status: %s", err) | ||||||
| 				} | 				} | ||||||
|  | 
 | ||||||
|  | 				fromFederatorChan <- gtsmodel.FromFederator{ | ||||||
|  | 					APObjectType: gtsmodel.ActivityStreamsNote, | ||||||
|  | 					APActivityType: gtsmodel.ActivityStreamsCreate, | ||||||
|  | 					Activity: status, | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	case gtsmodel.ActivityStreamsFollow: | 	case gtsmodel.ActivityStreamsFollow: | ||||||
|  | @ -407,6 +431,12 @@ func (f *federatingDB) Create(c context.Context, asType vocab.Type) error { | ||||||
| 		if err := f.db.Put(followRequest); err != nil { | 		if err := f.db.Put(followRequest); err != nil { | ||||||
| 			return fmt.Errorf("database error inserting follow request: %s", err) | 			return fmt.Errorf("database error inserting follow request: %s", err) | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		if !targetAcct.Locked { | ||||||
|  | 			if err := f.db.AcceptFollowRequest(followRequest.AccountID, followRequest.TargetAccountID); err != nil { | ||||||
|  | 				return fmt.Errorf("database error accepting follow request: %s", err) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -71,49 +71,7 @@ func (f *federator) PostInboxRequestBodyHook(ctx context.Context, r *http.Reques | ||||||
| 		l.Debug(err) | 		l.Debug(err) | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	// derefence the actor of the activity already |  | ||||||
| 	// var requestingActorIRI *url.URL |  | ||||||
| 	// actorProp := activity.GetActivityStreamsActor() |  | ||||||
| 	// if actorProp != nil { |  | ||||||
| 	// 	for i := actorProp.Begin(); i != actorProp.End(); i = i.Next() { |  | ||||||
| 	// 		if i.IsIRI() { |  | ||||||
| 	// 			requestingActorIRI = i.GetIRI() |  | ||||||
| 	// 			break |  | ||||||
| 	// 		} |  | ||||||
| 	// 	} |  | ||||||
| 	// } |  | ||||||
| 	// if requestingActorIRI != nil { |  | ||||||
| 
 |  | ||||||
| 	// 	requestedAccountI := ctx.Value(util.APAccount) |  | ||||||
| 	// 	requestedAccount, ok := requestedAccountI.(*gtsmodel.Account) |  | ||||||
| 	// 	if !ok { |  | ||||||
| 	// 		return nil, errors.New("requested account was not set on request context") |  | ||||||
| 	// 	} |  | ||||||
| 
 |  | ||||||
| 	// 	requestingActor := >smodel.Account{} |  | ||||||
| 	// 	if err := f.db.GetWhere("uri", requestingActorIRI.String(), requestingActor); err != nil { |  | ||||||
| 	// 		// there's been a proper error so return it |  | ||||||
| 	// 		if _, ok := err.(db.ErrNoEntries); !ok { |  | ||||||
| 	// 			return nil, fmt.Errorf("error getting requesting actor with id %s: %s", requestingActorIRI.String(), err) |  | ||||||
| 	// 		} |  | ||||||
| 
 |  | ||||||
| 	// 		// we don't know this account (yet) so let's dereference it right now |  | ||||||
| 	// 		person, err := f.DereferenceRemoteAccount(requestedAccount.Username, publicKeyOwnerURI) |  | ||||||
| 	// 		if err != nil { |  | ||||||
| 	// 			return ctx, false, fmt.Errorf("error dereferencing account with public key id %s: %s", publicKeyOwnerURI.String(), err) |  | ||||||
| 	// 		} |  | ||||||
| 
 |  | ||||||
| 	// 		a, err := f.typeConverter.ASRepresentationToAccount(person) |  | ||||||
| 	// 		if err != nil { |  | ||||||
| 	// 			return ctx, false, fmt.Errorf("error converting person with public key id %s to account: %s", publicKeyOwnerURI.String(), err) |  | ||||||
| 	// 		} |  | ||||||
| 	// 		requestingAccount = a |  | ||||||
| 	// 	} |  | ||||||
| 	// } |  | ||||||
| 
 |  | ||||||
| 	// set the activity on the context for use later on | 	// set the activity on the context for use later on | ||||||
| 
 |  | ||||||
| 	return context.WithValue(ctx, util.APActivity, activity), nil | 	return context.WithValue(ctx, util.APActivity, activity), nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -285,14 +243,6 @@ func (f *federator) FederatingCallbacks(ctx context.Context) (wrapped pub.Federa | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	wrapped = pub.FederatingWrappedCallbacks{ | 	wrapped = pub.FederatingWrappedCallbacks{ | ||||||
| 		// Follow handles additional side effects for the Follow ActivityStreams |  | ||||||
| 		// type, specific to the application using go-fed. |  | ||||||
| 		// |  | ||||||
| 		// The wrapping function can have one of several default behaviors, |  | ||||||
| 		// depending on the value of the OnFollow setting. |  | ||||||
| 		Follow: func(context.Context, vocab.ActivityStreamsFollow) error { |  | ||||||
| 			return nil |  | ||||||
| 		}, |  | ||||||
| 		// OnFollow determines what action to take for this particular callback | 		// OnFollow determines what action to take for this particular callback | ||||||
| 		// if a Follow Activity is handled. | 		// if a Follow Activity is handled. | ||||||
| 		OnFollow: onFollow, | 		OnFollow: onFollow, | ||||||
|  |  | ||||||
							
								
								
									
										29
									
								
								internal/gtsmodel/messages.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								internal/gtsmodel/messages.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | ||||||
|  | package gtsmodel | ||||||
|  | 
 | ||||||
|  | // ToClientAPI wraps a message that travels from the processor into the client API | ||||||
|  | type ToClientAPI struct { | ||||||
|  | 	APObjectType   ActivityStreamsObject | ||||||
|  | 	APActivityType ActivityStreamsActivity | ||||||
|  | 	Activity       interface{} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // FromClientAPI wraps a message that travels from client API into the processor | ||||||
|  | type FromClientAPI struct { | ||||||
|  | 	APObjectType   ActivityStreamsObject | ||||||
|  | 	APActivityType ActivityStreamsActivity | ||||||
|  | 	Activity       interface{} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ToFederator wraps a message that travels from the processor into the federator | ||||||
|  | type ToFederator struct { | ||||||
|  | 	APObjectType   ActivityStreamsObject | ||||||
|  | 	APActivityType ActivityStreamsActivity | ||||||
|  | 	Activity       interface{} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // FromFederator wraps a message that travels from the federator into the processor | ||||||
|  | type FromFederator struct { | ||||||
|  | 	APObjectType   ActivityStreamsObject | ||||||
|  | 	APActivityType ActivityStreamsActivity | ||||||
|  | 	Activity       interface{} | ||||||
|  | } | ||||||
|  | @ -166,3 +166,67 @@ func (p *processor) AccountUpdate(authed *oauth.Auth, form *apimodel.UpdateCrede | ||||||
| 	} | 	} | ||||||
| 	return acctSensitive, nil | 	return acctSensitive, nil | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func (p *processor) AccountStatusesGet(authed *oauth.Auth, targetAccountID string, limit int) ([]apimodel.Status, ErrorWithCode) { | ||||||
|  | 	targetAccount := >smodel.Account{} | ||||||
|  | 	if err := p.db.GetByID(targetAccountID, targetAccount); err != nil { | ||||||
|  | 		if _, ok := err.(db.ErrNoEntries); ok { | ||||||
|  | 			return nil, NewErrorNotFound(fmt.Errorf("no entry found for account id %s", targetAccountID)) | ||||||
|  | 		} | ||||||
|  | 		return nil, NewErrorInternalError(err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	statuses := []gtsmodel.Status{} | ||||||
|  | 	apiStatuses := []apimodel.Status{} | ||||||
|  | 	if err := p.db.GetStatusesByTimeDescending(targetAccountID, &statuses, limit); err != nil { | ||||||
|  | 		if _, ok := err.(db.ErrNoEntries); ok { | ||||||
|  | 			return apiStatuses, nil | ||||||
|  | 		} | ||||||
|  | 		return nil, NewErrorInternalError(err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, s := range statuses { | ||||||
|  | 		relevantAccounts, err := p.db.PullRelevantAccountsFromStatus(&s) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, NewErrorInternalError(err) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		visible, err := p.db.StatusVisible(&s, targetAccount, authed.Account, relevantAccounts) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, NewErrorInternalError(err) | ||||||
|  | 		} | ||||||
|  | 		if !visible { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		var boostedStatus *gtsmodel.Status | ||||||
|  | 		if s.BoostOfID != "" { | ||||||
|  | 			bs := >smodel.Status{} | ||||||
|  | 			if err := p.db.GetByID(s.BoostOfID, bs); err != nil { | ||||||
|  | 				return nil, NewErrorInternalError(err) | ||||||
|  | 			} | ||||||
|  | 			boostedRelevantAccounts, err := p.db.PullRelevantAccountsFromStatus(bs) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return nil, NewErrorInternalError(err) | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			boostedVisible, err := p.db.StatusVisible(bs, relevantAccounts.BoostedAccount, authed.Account, boostedRelevantAccounts) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return nil, NewErrorInternalError(err) | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if boostedVisible { | ||||||
|  | 				boostedStatus = bs | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		apiStatus, err := p.tc.StatusToMasto(&s, targetAccount, authed.Account, relevantAccounts.BoostedAccount, relevantAccounts.ReplyToAccount, boostedStatus) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, NewErrorInternalError(err) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		apiStatuses = append(apiStatuses, *apiStatus) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return apiStatuses, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -60,7 +60,7 @@ func (p *processor) authenticateAndDereferenceFediRequest(username string, r *ht | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// put it in our channel to queue it for async processing | 	// put it in our channel to queue it for async processing | ||||||
| 	p.FromFederator() <- FromFederator{ | 	p.FromFederator() <- gtsmodel.FromFederator{ | ||||||
| 		APObjectType:   gtsmodel.ActivityStreamsProfile, | 		APObjectType:   gtsmodel.ActivityStreamsProfile, | ||||||
| 		APActivityType: gtsmodel.ActivityStreamsCreate, | 		APActivityType: gtsmodel.ActivityStreamsCreate, | ||||||
| 		Activity:       requestingAccount, | 		Activity:       requestingAccount, | ||||||
|  |  | ||||||
|  | @ -23,7 +23,6 @@ import ( | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/url" |  | ||||||
| 
 | 
 | ||||||
| 	"github.com/sirupsen/logrus" | 	"github.com/sirupsen/logrus" | ||||||
| 	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" | 	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" | ||||||
|  | @ -45,13 +44,13 @@ import ( | ||||||
| // for clean distribution of messages without slowing down the client API and harming the user experience. | // for clean distribution of messages without slowing down the client API and harming the user experience. | ||||||
| type Processor interface { | type Processor interface { | ||||||
| 	// ToClientAPI returns a channel for putting in messages that need to go to the gts client API. | 	// ToClientAPI returns a channel for putting in messages that need to go to the gts client API. | ||||||
| 	ToClientAPI() chan ToClientAPI | 	ToClientAPI() chan gtsmodel.ToClientAPI | ||||||
| 	// FromClientAPI returns a channel for putting messages in that come from the client api going to the processor | 	// FromClientAPI returns a channel for putting messages in that come from the client api going to the processor | ||||||
| 	FromClientAPI() chan FromClientAPI | 	FromClientAPI() chan gtsmodel.FromClientAPI | ||||||
| 	// ToFederator returns a channel for putting in messages that need to go to the federator (activitypub). | 	// ToFederator returns a channel for putting in messages that need to go to the federator (activitypub). | ||||||
| 	ToFederator() chan ToFederator | 	ToFederator() chan gtsmodel.ToFederator | ||||||
| 	// FromFederator returns a channel for putting messages in that come from the federator (activitypub) going into the processor | 	// FromFederator returns a channel for putting messages in that come from the federator (activitypub) going into the processor | ||||||
| 	FromFederator() chan FromFederator | 	FromFederator() chan gtsmodel.FromFederator | ||||||
| 	// Start starts the Processor, reading from its channels and passing messages back and forth. | 	// Start starts the Processor, reading from its channels and passing messages back and forth. | ||||||
| 	Start() error | 	Start() error | ||||||
| 	// Stop stops the processor cleanly, finishing handling any remaining messages before closing down. | 	// Stop stops the processor cleanly, finishing handling any remaining messages before closing down. | ||||||
|  | @ -71,6 +70,7 @@ type Processor interface { | ||||||
| 	AccountGet(authed *oauth.Auth, targetAccountID string) (*apimodel.Account, error) | 	AccountGet(authed *oauth.Auth, targetAccountID string) (*apimodel.Account, error) | ||||||
| 	// AccountUpdate processes the update of an account with the given form | 	// AccountUpdate processes the update of an account with the given form | ||||||
| 	AccountUpdate(authed *oauth.Auth, form *apimodel.UpdateCredentialsRequest) (*apimodel.Account, error) | 	AccountUpdate(authed *oauth.Auth, form *apimodel.UpdateCredentialsRequest) (*apimodel.Account, error) | ||||||
|  | 	AccountStatusesGet(authed *oauth.Auth, targetAccountID string, limit int) ([]apimodel.Status, ErrorWithCode) | ||||||
| 
 | 
 | ||||||
| 	// AdminEmojiCreate handles the creation of a new instance emoji by an admin, using the given form. | 	// AdminEmojiCreate handles the creation of a new instance emoji by an admin, using the given form. | ||||||
| 	AdminEmojiCreate(authed *oauth.Auth, form *apimodel.EmojiCreateRequest) (*apimodel.Emoji, error) | 	AdminEmojiCreate(authed *oauth.Auth, form *apimodel.EmojiCreateRequest) (*apimodel.Emoji, error) | ||||||
|  | @ -142,10 +142,10 @@ type Processor interface { | ||||||
| // processor just implements the Processor interface | // processor just implements the Processor interface | ||||||
| type processor struct { | type processor struct { | ||||||
| 	// federator     pub.FederatingActor | 	// federator     pub.FederatingActor | ||||||
| 	toClientAPI   chan ToClientAPI | 	toClientAPI   chan gtsmodel.ToClientAPI | ||||||
| 	fromClientAPI chan FromClientAPI | 	fromClientAPI chan gtsmodel.FromClientAPI | ||||||
| 	toFederator   chan ToFederator | 	toFederator   chan gtsmodel.ToFederator | ||||||
| 	fromFederator chan FromFederator | 	fromFederator chan gtsmodel.FromFederator | ||||||
| 	federator     federation.Federator | 	federator     federation.Federator | ||||||
| 	stop          chan interface{} | 	stop          chan interface{} | ||||||
| 	log           *logrus.Logger | 	log           *logrus.Logger | ||||||
|  | @ -160,10 +160,10 @@ type processor struct { | ||||||
| // NewProcessor returns a new Processor that uses the given federator and logger | // NewProcessor returns a new Processor that uses the given federator and logger | ||||||
| func NewProcessor(config *config.Config, tc typeutils.TypeConverter, federator federation.Federator, oauthServer oauth.Server, mediaHandler media.Handler, storage storage.Storage, db db.DB, log *logrus.Logger) Processor { | func NewProcessor(config *config.Config, tc typeutils.TypeConverter, federator federation.Federator, oauthServer oauth.Server, mediaHandler media.Handler, storage storage.Storage, db db.DB, log *logrus.Logger) Processor { | ||||||
| 	return &processor{ | 	return &processor{ | ||||||
| 		toClientAPI:   make(chan ToClientAPI, 100), | 		toClientAPI:   make(chan gtsmodel.ToClientAPI, 100), | ||||||
| 		fromClientAPI: make(chan FromClientAPI, 100), | 		fromClientAPI: make(chan gtsmodel.FromClientAPI, 100), | ||||||
| 		toFederator:   make(chan ToFederator, 100), | 		toFederator:   make(chan gtsmodel.ToFederator, 100), | ||||||
| 		fromFederator: make(chan FromFederator, 100), | 		fromFederator: make(chan gtsmodel.FromFederator, 100), | ||||||
| 		federator:     federator, | 		federator:     federator, | ||||||
| 		stop:          make(chan interface{}), | 		stop:          make(chan interface{}), | ||||||
| 		log:           log, | 		log:           log, | ||||||
|  | @ -176,19 +176,19 @@ func NewProcessor(config *config.Config, tc typeutils.TypeConverter, federator f | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *processor) ToClientAPI() chan ToClientAPI { | func (p *processor) ToClientAPI() chan gtsmodel.ToClientAPI { | ||||||
| 	return p.toClientAPI | 	return p.toClientAPI | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *processor) FromClientAPI() chan FromClientAPI { | func (p *processor) FromClientAPI() chan gtsmodel.FromClientAPI { | ||||||
| 	return p.fromClientAPI | 	return p.fromClientAPI | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *processor) ToFederator() chan ToFederator { | func (p *processor) ToFederator() chan gtsmodel.ToFederator { | ||||||
| 	return p.toFederator | 	return p.toFederator | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *processor) FromFederator() chan FromFederator { | func (p *processor) FromFederator() chan gtsmodel.FromFederator { | ||||||
| 	return p.fromFederator | 	return p.fromFederator | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -209,6 +209,9 @@ func (p *processor) Start() error { | ||||||
| 				p.log.Infof("received message TO federator: %+v", federatorMsg) | 				p.log.Infof("received message TO federator: %+v", federatorMsg) | ||||||
| 			case federatorMsg := <-p.fromFederator: | 			case federatorMsg := <-p.fromFederator: | ||||||
| 				p.log.Infof("received message FROM federator: %+v", federatorMsg) | 				p.log.Infof("received message FROM federator: %+v", federatorMsg) | ||||||
|  | 				if err := p.processFromFederator(federatorMsg); err != nil { | ||||||
|  | 					p.log.Error(err) | ||||||
|  | 				} | ||||||
| 			case <-p.stop: | 			case <-p.stop: | ||||||
| 				break DistLoop | 				break DistLoop | ||||||
| 			} | 			} | ||||||
|  | @ -224,35 +227,11 @@ func (p *processor) Stop() error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ToClientAPI wraps a message that travels from the processor into the client API | func (p *processor) processFromFederator(federatorMsg gtsmodel.FromFederator) error { | ||||||
| type ToClientAPI struct { | 	return nil | ||||||
| 	APObjectType   gtsmodel.ActivityStreamsObject |  | ||||||
| 	APActivityType gtsmodel.ActivityStreamsActivity |  | ||||||
| 	Activity       interface{} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // FromClientAPI wraps a message that travels from client API into the processor | func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error { | ||||||
| type FromClientAPI struct { |  | ||||||
| 	APObjectType   gtsmodel.ActivityStreamsObject |  | ||||||
| 	APActivityType gtsmodel.ActivityStreamsActivity |  | ||||||
| 	Activity       interface{} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // ToFederator wraps a message that travels from the processor into the federator |  | ||||||
| type ToFederator struct { |  | ||||||
| 	APObjectType   gtsmodel.ActivityStreamsObject |  | ||||||
| 	APActivityType gtsmodel.ActivityStreamsActivity |  | ||||||
| 	Activity       interface{} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // FromFederator wraps a message that travels from the federator into the processor |  | ||||||
| type FromFederator struct { |  | ||||||
| 	APObjectType   gtsmodel.ActivityStreamsObject |  | ||||||
| 	APActivityType gtsmodel.ActivityStreamsActivity |  | ||||||
| 	Activity       interface{} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (p *processor) processFromClientAPI(clientMsg FromClientAPI) error { |  | ||||||
| 	switch clientMsg.APObjectType { | 	switch clientMsg.APObjectType { | ||||||
| 	case gtsmodel.ActivityStreamsNote: | 	case gtsmodel.ActivityStreamsNote: | ||||||
| 		status, ok := clientMsg.Activity.(*gtsmodel.Status) | 		status, ok := clientMsg.Activity.(*gtsmodel.Status) | ||||||
|  | @ -273,30 +252,30 @@ func (p *processor) processFromClientAPI(clientMsg FromClientAPI) error { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *processor) federateStatus(status *gtsmodel.Status) error { | func (p *processor) federateStatus(status *gtsmodel.Status) error { | ||||||
| 	// derive the sending account -- it might be attached to the status already | 	// // derive the sending account -- it might be attached to the status already | ||||||
| 	sendingAcct := >smodel.Account{} | 	// sendingAcct := >smodel.Account{} | ||||||
| 	if status.GTSAccount != nil { | 	// if status.GTSAccount != nil { | ||||||
| 		sendingAcct = status.GTSAccount | 	// 	sendingAcct = status.GTSAccount | ||||||
| 	} else { | 	// } else { | ||||||
| 		// it wasn't attached so get it from the db instead | 	// 	// it wasn't attached so get it from the db instead | ||||||
| 		if err := p.db.GetByID(status.AccountID, sendingAcct); err != nil { | 	// 	if err := p.db.GetByID(status.AccountID, sendingAcct); err != nil { | ||||||
| 			return err | 	// 		return err | ||||||
| 		} | 	// 	} | ||||||
| 	} | 	// } | ||||||
| 
 | 
 | ||||||
| 	outboxURI, err := url.Parse(sendingAcct.OutboxURI) | 	// outboxURI, err := url.Parse(sendingAcct.OutboxURI) | ||||||
| 	if err != nil { | 	// if err != nil { | ||||||
| 		return err | 	// 	return err | ||||||
| 	} | 	// } | ||||||
| 
 | 
 | ||||||
| 	// convert the status to AS format Note | 	// // convert the status to AS format Note | ||||||
| 	note, err := p.tc.StatusToAS(status) | 	// note, err := p.tc.StatusToAS(status) | ||||||
| 	if err != nil { | 	// if err != nil { | ||||||
| 		return err | 	// 	return err | ||||||
| 	} | 	// } | ||||||
| 
 | 
 | ||||||
| 	_, err = p.federator.FederatingActor().Send(context.Background(), outboxURI, note) | 	// _, err = p.federator.FederatingActor().Send(context.Background(), outboxURI, note) | ||||||
| 	return err | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *processor) notifyStatus(status *gtsmodel.Status) error { | func (p *processor) notifyStatus(status *gtsmodel.Status) error { | ||||||
|  |  | ||||||
|  | @ -82,7 +82,7 @@ func (p *processor) StatusCreate(auth *oauth.Auth, form *apimodel.AdvancedStatus | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// put the new status in the appropriate channel for async processing | 	// put the new status in the appropriate channel for async processing | ||||||
| 	p.fromClientAPI <- FromClientAPI{ | 	p.fromClientAPI <- gtsmodel.FromClientAPI{ | ||||||
| 		APObjectType:   newStatus.ActivityStreamsType, | 		APObjectType:   newStatus.ActivityStreamsType, | ||||||
| 		APActivityType: gtsmodel.ActivityStreamsCreate, | 		APActivityType: gtsmodel.ActivityStreamsCreate, | ||||||
| 		Activity:       newStatus, | 		Activity:       newStatus, | ||||||
|  |  | ||||||
|  | @ -20,6 +20,7 @@ package typeutils | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/api/model" | 	"github.com/superseriousbusiness/gotosocial/internal/api/model" | ||||||
|  | @ -195,7 +196,7 @@ func (c *converter) AppToMastoPublic(a *gtsmodel.Application) (*model.Applicatio | ||||||
| func (c *converter) AttachmentToMasto(a *gtsmodel.MediaAttachment) (model.Attachment, error) { | func (c *converter) AttachmentToMasto(a *gtsmodel.MediaAttachment) (model.Attachment, error) { | ||||||
| 	return model.Attachment{ | 	return model.Attachment{ | ||||||
| 		ID:               a.ID, | 		ID:               a.ID, | ||||||
| 		Type:             string(a.Type), | 		Type:             strings.ToLower(string(a.Type)), | ||||||
| 		URL:              a.URL, | 		URL:              a.URL, | ||||||
| 		PreviewURL:       a.Thumbnail.URL, | 		PreviewURL:       a.Thumbnail.URL, | ||||||
| 		RemoteURL:        a.RemoteURL, | 		RemoteURL:        a.RemoteURL, | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue