mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 09:02:25 -05:00 
			
		
		
		
	send out poll votes as separate create activities given that no other AP servers support multiple objects in a single activity (#3582)
This commit is contained in:
		
					parent
					
						
							
								3cc50491c2
							
						
					
				
			
			
				commit
				
					
						d9f67efae5
					
				
			
		
					 3 changed files with 75 additions and 48 deletions
				
			
		|  | @ -217,18 +217,23 @@ func (f *federate) CreatePollVote(ctx context.Context, poll *gtsmodel.Poll, vote | |||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	// Convert vote to AS Create with vote choices as Objects. | ||||
| 	create, err := f.converter.PollVoteToASCreate(ctx, vote) | ||||
| 	// Convert vote to AS Creates with vote choices as Objects. | ||||
| 	creates, err := f.converter.PollVoteToASCreates(ctx, vote) | ||||
| 	if err != nil { | ||||
| 		return gtserror.Newf("error converting to notes: %w", err) | ||||
| 	} | ||||
| 
 | ||||
| 	// Send the Create via the Actor's outbox. | ||||
| 	if _, err := f.FederatingActor().Send(ctx, outboxIRI, create); err != nil { | ||||
| 		return gtserror.Newf("error sending Create activity via outbox %s: %w", outboxIRI, err) | ||||
| 	var errs gtserror.MultiError | ||||
| 
 | ||||
| 	// Send each create activity. | ||||
| 	actor := f.FederatingActor() | ||||
| 	for _, create := range creates { | ||||
| 		if _, err := actor.Send(ctx, outboxIRI, create); err != nil { | ||||
| 			errs.Appendf("error sending Create activity via outbox %s: %w", outboxIRI, err) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| 	return errs.Combine() | ||||
| } | ||||
| 
 | ||||
| func (f *federate) DeleteStatus(ctx context.Context, status *gtsmodel.Status) error { | ||||
|  |  | |||
|  | @ -1701,10 +1701,14 @@ func (c *Converter) ReportToASFlag(ctx context.Context, r *gtsmodel.Report) (voc | |||
| // PollVoteToASCreate converts a vote on a poll into a Create | ||||
| // activity, suitable for federation, with each choice in the | ||||
| // vote appended as a Note to the Create's Object field. | ||||
| func (c *Converter) PollVoteToASCreate( | ||||
| // | ||||
| // TODO: as soon as other AP server implementations support | ||||
| // the use of multiple objects in a single create, update this | ||||
| // to return just the one create event again. | ||||
| func (c *Converter) PollVoteToASCreates( | ||||
| 	ctx context.Context, | ||||
| 	vote *gtsmodel.PollVote, | ||||
| ) (vocab.ActivityStreamsCreate, error) { | ||||
| ) ([]vocab.ActivityStreamsCreate, error) { | ||||
| 	if len(vote.Choices) == 0 { | ||||
| 		panic("no vote.Choices") | ||||
| 	} | ||||
|  | @ -1743,13 +1747,17 @@ func (c *Converter) PollVoteToASCreate( | |||
| 		return nil, gtserror.Newf("invalid account uri: %w", err) | ||||
| 	} | ||||
| 
 | ||||
| 	// Parse each choice to a Note and add it to the list of Creates. | ||||
| 	creates := make([]vocab.ActivityStreamsCreate, len(vote.Choices)) | ||||
| 	for i, choice := range vote.Choices { | ||||
| 
 | ||||
| 		// Allocate Create activity and address 'To' poll author. | ||||
| 		create := streams.NewActivityStreamsCreate() | ||||
| 		ap.AppendTo(create, pollAuthorIRI) | ||||
| 
 | ||||
| 	// Create ID formatted as: {$voterIRI}/activity#vote/{$statusIRI}. | ||||
| 	id := author.URI + "/activity#vote/" + poll.Status.URI | ||||
| 	ap.MustSet(ap.SetJSONLDIdStr, ap.WithJSONLDId(create), id) | ||||
| 		// Create ID formatted as: {$voterIRI}/activity#vote{$index}/{$statusIRI}. | ||||
| 		createID := fmt.Sprintf("%s/activity#vote%d/%s", author.URI, i, poll.Status.URI) | ||||
| 		ap.MustSet(ap.SetJSONLDIdStr, ap.WithJSONLDId(create), createID) | ||||
| 
 | ||||
| 		// Set Create actor appropriately. | ||||
| 		ap.AppendActorIRIs(create, authorIRI) | ||||
|  | @ -1757,8 +1765,7 @@ func (c *Converter) PollVoteToASCreate( | |||
| 		// Set publish time for activity. | ||||
| 		ap.SetPublished(create, vote.CreatedAt) | ||||
| 
 | ||||
| 	// Parse each choice to a Note and add it to the Create. | ||||
| 	for _, choice := range vote.Choices { | ||||
| 		// Allocate new note to hold the vote. | ||||
| 		note := streams.NewActivityStreamsNote() | ||||
| 
 | ||||
| 		// For AP IRI generate from author URI + poll ID + vote choice. | ||||
|  | @ -1775,11 +1782,14 @@ func (c *Converter) PollVoteToASCreate( | |||
| 		ap.AppendInReplyTo(note, statusIRI) | ||||
| 		ap.AppendTo(note, pollAuthorIRI) | ||||
| 
 | ||||
| 		// Append this note as Create Object. | ||||
| 		// Append this note to the Create Object. | ||||
| 		appendStatusableToActivity(create, note, false) | ||||
| 
 | ||||
| 		// Set create in slice. | ||||
| 		creates[i] = create | ||||
| 	} | ||||
| 
 | ||||
| 	return create, nil | ||||
| 	return creates, nil | ||||
| } | ||||
| 
 | ||||
| // populateValuesForProp appends the given PolicyValues | ||||
|  |  | |||
|  | @ -1104,23 +1104,27 @@ func (suite *InternalToASTestSuite) TestPinnedStatusesToASOneItem() { | |||
| func (suite *InternalToASTestSuite) TestPollVoteToASCreate() { | ||||
| 	vote := suite.testPollVotes["remote_account_1_status_2_poll_vote_local_account_1"] | ||||
| 
 | ||||
| 	create, err := suite.typeconverter.PollVoteToASCreate(context.Background(), vote) | ||||
| 	if err != nil { | ||||
| 		suite.FailNow(err.Error()) | ||||
| 	} | ||||
| 	creates, err := suite.typeconverter.PollVoteToASCreates(context.Background(), vote) | ||||
| 	suite.NoError(err) | ||||
| 	suite.Len(creates, 2) | ||||
| 
 | ||||
| 	createI, err := ap.Serialize(create) | ||||
| 	createI0, err := ap.Serialize(creates[0]) | ||||
| 	suite.NoError(err) | ||||
| 
 | ||||
| 	bytes, err := json.MarshalIndent(createI, "", "  ") | ||||
| 	createI1, err := ap.Serialize(creates[1]) | ||||
| 	suite.NoError(err) | ||||
| 
 | ||||
| 	bytes0, err := json.MarshalIndent(createI0, "", "  ") | ||||
| 	suite.NoError(err) | ||||
| 
 | ||||
| 	bytes1, err := json.MarshalIndent(createI1, "", "  ") | ||||
| 	suite.NoError(err) | ||||
| 
 | ||||
| 	suite.Equal(`{ | ||||
|   "@context": "https://www.w3.org/ns/activitystreams", | ||||
|   "actor": "http://localhost:8080/users/the_mighty_zork", | ||||
|   "id": "http://localhost:8080/users/the_mighty_zork/activity#vote/http://fossbros-anonymous.io/users/foss_satan/statuses/01HEN2QRFA8H3C6QPN7RD4KSR6", | ||||
|   "object": [ | ||||
|     { | ||||
|   "id": "http://localhost:8080/users/the_mighty_zork/activity#vote0/http://fossbros-anonymous.io/users/foss_satan/statuses/01HEN2QRFA8H3C6QPN7RD4KSR6", | ||||
|   "object": { | ||||
|     "attributedTo": "http://localhost:8080/users/the_mighty_zork", | ||||
|     "id": "http://localhost:8080/users/the_mighty_zork#01HEN2R65468ZG657C4ZPHJ4EX/votes/1", | ||||
|     "inReplyTo": "http://fossbros-anonymous.io/users/foss_satan/statuses/01HEN2QRFA8H3C6QPN7RD4KSR6", | ||||
|  | @ -1128,19 +1132,27 @@ func (suite *InternalToASTestSuite) TestPollVoteToASCreate() { | |||
|     "to": "http://fossbros-anonymous.io/users/foss_satan", | ||||
|     "type": "Note" | ||||
|   }, | ||||
|     { | ||||
|   "published": "2021-09-11T11:45:37+02:00", | ||||
|   "to": "http://fossbros-anonymous.io/users/foss_satan", | ||||
|   "type": "Create" | ||||
| }`, string(bytes0)) | ||||
| 
 | ||||
| 	suite.Equal(`{ | ||||
|   "@context": "https://www.w3.org/ns/activitystreams", | ||||
|   "actor": "http://localhost:8080/users/the_mighty_zork", | ||||
|   "id": "http://localhost:8080/users/the_mighty_zork/activity#vote1/http://fossbros-anonymous.io/users/foss_satan/statuses/01HEN2QRFA8H3C6QPN7RD4KSR6", | ||||
|   "object": { | ||||
|     "attributedTo": "http://localhost:8080/users/the_mighty_zork", | ||||
|     "id": "http://localhost:8080/users/the_mighty_zork#01HEN2R65468ZG657C4ZPHJ4EX/votes/2", | ||||
|     "inReplyTo": "http://fossbros-anonymous.io/users/foss_satan/statuses/01HEN2QRFA8H3C6QPN7RD4KSR6", | ||||
|     "name": "financial times", | ||||
|     "to": "http://fossbros-anonymous.io/users/foss_satan", | ||||
|     "type": "Note" | ||||
|     } | ||||
|   ], | ||||
|   }, | ||||
|   "published": "2021-09-11T11:45:37+02:00", | ||||
|   "to": "http://fossbros-anonymous.io/users/foss_satan", | ||||
|   "type": "Create" | ||||
| }`, string(bytes)) | ||||
| }`, string(bytes1)) | ||||
| } | ||||
| 
 | ||||
| func (suite *InternalToASTestSuite) TestInteractionReqToASAcceptAnnounce() { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue