mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 20:12:26 -05:00 
			
		
		
		
	Follows and relationships (#27)
* Follows -- create and undo, both remote and local * Statuses -- federate new posts, including media, attachments, CWs and image descriptions.
This commit is contained in:
		
					parent
					
						
							
								dc06e71b76
							
						
					
				
			
			
				commit
				
					
						d839f27c30
					
				
			
		
					 54 changed files with 2260 additions and 299 deletions
				
			
		|  | @ -19,55 +19,198 @@ | |||
| package message | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"net/url" | ||||
| 
 | ||||
| 	"github.com/go-fed/activity/streams" | ||||
| 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | ||||
| ) | ||||
| 
 | ||||
| func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error { | ||||
| 	switch clientMsg.APObjectType { | ||||
| 	case gtsmodel.ActivityStreamsNote: | ||||
| 		status, ok := clientMsg.GTSModel.(*gtsmodel.Status) | ||||
| 		if !ok { | ||||
| 			return errors.New("note was not parseable as *gtsmodel.Status") | ||||
| 		} | ||||
| 	switch clientMsg.APActivityType { | ||||
| 	case gtsmodel.ActivityStreamsCreate: | ||||
| 		// CREATE | ||||
| 		switch clientMsg.APObjectType { | ||||
| 		case gtsmodel.ActivityStreamsNote: | ||||
| 			// CREATE NOTE | ||||
| 			status, ok := clientMsg.GTSModel.(*gtsmodel.Status) | ||||
| 			if !ok { | ||||
| 				return errors.New("note was not parseable as *gtsmodel.Status") | ||||
| 			} | ||||
| 
 | ||||
| 		if err := p.notifyStatus(status); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 			if err := p.notifyStatus(status); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 		if status.VisibilityAdvanced.Federated { | ||||
| 			return p.federateStatus(status) | ||||
| 			if status.VisibilityAdvanced.Federated { | ||||
| 				return p.federateStatus(status) | ||||
| 			} | ||||
| 			return nil | ||||
| 		case gtsmodel.ActivityStreamsFollow: | ||||
| 			// CREATE FOLLOW (request) | ||||
| 			follow, ok := clientMsg.GTSModel.(*gtsmodel.Follow) | ||||
| 			if !ok { | ||||
| 				return errors.New("follow was not parseable as *gtsmodel.Follow") | ||||
| 			} | ||||
| 
 | ||||
| 			if err := p.notifyFollow(follow); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			return p.federateFollow(follow, clientMsg.OriginAccount, clientMsg.TargetAccount) | ||||
| 		} | ||||
| 	case gtsmodel.ActivityStreamsUpdate: | ||||
| 		// UPDATE | ||||
| 	case gtsmodel.ActivityStreamsAccept: | ||||
| 		// ACCEPT | ||||
| 		switch clientMsg.APObjectType { | ||||
| 		case gtsmodel.ActivityStreamsFollow: | ||||
| 			// ACCEPT FOLLOW | ||||
| 			follow, ok := clientMsg.GTSModel.(*gtsmodel.Follow) | ||||
| 			if !ok { | ||||
| 				return errors.New("accept was not parseable as *gtsmodel.Follow") | ||||
| 			} | ||||
| 			return p.federateAcceptFollowRequest(follow, clientMsg.OriginAccount, clientMsg.TargetAccount) | ||||
| 		} | ||||
| 	case gtsmodel.ActivityStreamsUndo: | ||||
| 		// UNDO | ||||
| 		switch clientMsg.APObjectType { | ||||
| 		case gtsmodel.ActivityStreamsFollow: | ||||
| 			// UNDO FOLLOW | ||||
| 			follow, ok := clientMsg.GTSModel.(*gtsmodel.Follow) | ||||
| 			if !ok { | ||||
| 				return errors.New("undo was not parseable as *gtsmodel.Follow") | ||||
| 			} | ||||
| 			return p.federateUnfollow(follow, clientMsg.OriginAccount, clientMsg.TargetAccount) | ||||
| 		} | ||||
| 		return nil | ||||
| 	} | ||||
| 	return fmt.Errorf("message type unprocessable: %+v", clientMsg) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (p *processor) federateStatus(status *gtsmodel.Status) error { | ||||
| 	// // derive the sending account -- it might be attached to the status already | ||||
| 	// sendingAcct := >smodel.Account{} | ||||
| 	// if status.GTSAccount != nil { | ||||
| 	// 	sendingAcct = status.GTSAccount | ||||
| 	// } else { | ||||
| 	// 	// it wasn't attached so get it from the db instead | ||||
| 	// 	if err := p.db.GetByID(status.AccountID, sendingAcct); err != nil { | ||||
| 	// 		return err | ||||
| 	// 	} | ||||
| 	// } | ||||
| 	asStatus, err := p.tc.StatusToAS(status) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("federateStatus: error converting status to as format: %s", err) | ||||
| 	} | ||||
| 
 | ||||
| 	// outboxURI, err := url.Parse(sendingAcct.OutboxURI) | ||||
| 	// if err != nil { | ||||
| 	// 	return err | ||||
| 	// } | ||||
| 	outboxIRI, err := url.Parse(status.GTSAccount.OutboxURI) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("federateStatus: error parsing outboxURI %s: %s", status.GTSAccount.OutboxURI, err) | ||||
| 	} | ||||
| 
 | ||||
| 	// // convert the status to AS format Note | ||||
| 	// note, err := p.tc.StatusToAS(status) | ||||
| 	// if err != nil { | ||||
| 	// 	return err | ||||
| 	// } | ||||
| 
 | ||||
| 	// _, err = p.federator.FederatingActor().Send(context.Background(), outboxURI, note) | ||||
| 	return nil | ||||
| 	_, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, asStatus) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func (p *processor) federateFollow(follow *gtsmodel.Follow, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error { | ||||
| 	// if both accounts are local there's nothing to do here | ||||
| 	if originAccount.Domain == "" && targetAccount.Domain == "" { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	asFollow, err := p.tc.FollowToAS(follow, originAccount, targetAccount) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("federateFollow: error converting follow to as format: %s", err) | ||||
| 	} | ||||
| 
 | ||||
| 	outboxIRI, err := url.Parse(originAccount.OutboxURI) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("federateFollow: error parsing outboxURI %s: %s", originAccount.OutboxURI, err) | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, asFollow) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func (p *processor) federateUnfollow(follow *gtsmodel.Follow, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error { | ||||
| 	// if both accounts are local there's nothing to do here | ||||
| 	if originAccount.Domain == "" && targetAccount.Domain == "" { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	// recreate the follow | ||||
| 	asFollow, err := p.tc.FollowToAS(follow, originAccount, targetAccount) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("federateUnfollow: error converting follow to as format: %s", err) | ||||
| 	} | ||||
| 
 | ||||
| 	targetAccountURI, err := url.Parse(targetAccount.URI) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("error parsing uri %s: %s", targetAccount.URI, err) | ||||
| 	} | ||||
| 
 | ||||
| 	// create an Undo and set the appropriate actor on it | ||||
| 	undo := streams.NewActivityStreamsUndo() | ||||
| 	undo.SetActivityStreamsActor(asFollow.GetActivityStreamsActor()) | ||||
| 
 | ||||
| 	// Set the recreated follow as the 'object' property. | ||||
| 	undoObject := streams.NewActivityStreamsObjectProperty() | ||||
| 	undoObject.AppendActivityStreamsFollow(asFollow) | ||||
| 	undo.SetActivityStreamsObject(undoObject) | ||||
| 
 | ||||
| 	// Set the To of the undo as the target of the recreated follow | ||||
| 	undoTo := streams.NewActivityStreamsToProperty() | ||||
| 	undoTo.AppendIRI(targetAccountURI) | ||||
| 	undo.SetActivityStreamsTo(undoTo) | ||||
| 
 | ||||
| 	outboxIRI, err := url.Parse(originAccount.OutboxURI) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("federateUnfollow: error parsing outboxURI %s: %s", originAccount.OutboxURI, err) | ||||
| 	} | ||||
| 
 | ||||
| 	// send off the Undo | ||||
| 	_, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, undo) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func (p *processor) federateAcceptFollowRequest(follow *gtsmodel.Follow, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error { | ||||
| 	// if both accounts are local there's nothing to do here | ||||
| 	if originAccount.Domain == "" && targetAccount.Domain == "" { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	// recreate the AS follow | ||||
| 	asFollow, err := p.tc.FollowToAS(follow, originAccount, targetAccount) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("federateUnfollow: error converting follow to as format: %s", err) | ||||
| 	} | ||||
| 
 | ||||
| 	acceptingAccountURI, err := url.Parse(targetAccount.URI) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("error parsing uri %s: %s", targetAccount.URI, err) | ||||
| 	} | ||||
| 
 | ||||
| 	requestingAccountURI, err := url.Parse(originAccount.URI) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("error parsing uri %s: %s", targetAccount.URI, err) | ||||
| 	} | ||||
| 
 | ||||
| 	// create an Accept | ||||
| 	accept := streams.NewActivityStreamsAccept() | ||||
| 
 | ||||
| 	// set the accepting actor on it | ||||
| 	acceptActorProp := streams.NewActivityStreamsActorProperty() | ||||
| 	acceptActorProp.AppendIRI(acceptingAccountURI) | ||||
| 	accept.SetActivityStreamsActor(acceptActorProp) | ||||
| 
 | ||||
| 	// Set the recreated follow as the 'object' property. | ||||
| 	acceptObject := streams.NewActivityStreamsObjectProperty() | ||||
| 	acceptObject.AppendActivityStreamsFollow(asFollow) | ||||
| 	accept.SetActivityStreamsObject(acceptObject) | ||||
| 
 | ||||
| 	// Set the To of the accept as the originator of the follow | ||||
| 	acceptTo := streams.NewActivityStreamsToProperty() | ||||
| 	acceptTo.AppendIRI(requestingAccountURI) | ||||
| 	accept.SetActivityStreamsTo(acceptTo) | ||||
| 
 | ||||
| 	outboxIRI, err := url.Parse(targetAccount.OutboxURI) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("federateAcceptFollowRequest: error parsing outboxURI %s: %s", originAccount.OutboxURI, err) | ||||
| 	} | ||||
| 
 | ||||
| 	// send off the accept using the accepter's outbox | ||||
| 	_, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, accept) | ||||
| 	return err | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue