mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 15:42:26 -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 | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Convert vote to AS Create with vote choices as Objects. | 	// Convert vote to AS Creates with vote choices as Objects. | ||||||
| 	create, err := f.converter.PollVoteToASCreate(ctx, vote) | 	creates, err := f.converter.PollVoteToASCreates(ctx, vote) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return gtserror.Newf("error converting to notes: %w", err) | 		return gtserror.Newf("error converting to notes: %w", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Send the Create via the Actor's outbox. | 	var errs gtserror.MultiError | ||||||
| 	if _, err := f.FederatingActor().Send(ctx, outboxIRI, create); err != nil { | 
 | ||||||
| 		return gtserror.Newf("error sending Create activity via outbox %s: %w", outboxIRI, err) | 	// 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 { | 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 | // PollVoteToASCreate converts a vote on a poll into a Create | ||||||
| // activity, suitable for federation, with each choice in the | // activity, suitable for federation, with each choice in the | ||||||
| // vote appended as a Note to the Create's Object field. | // 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, | 	ctx context.Context, | ||||||
| 	vote *gtsmodel.PollVote, | 	vote *gtsmodel.PollVote, | ||||||
| ) (vocab.ActivityStreamsCreate, error) { | ) ([]vocab.ActivityStreamsCreate, error) { | ||||||
| 	if len(vote.Choices) == 0 { | 	if len(vote.Choices) == 0 { | ||||||
| 		panic("no vote.Choices") | 		panic("no vote.Choices") | ||||||
| 	} | 	} | ||||||
|  | @ -1743,22 +1747,25 @@ func (c *Converter) PollVoteToASCreate( | ||||||
| 		return nil, gtserror.Newf("invalid account uri: %w", err) | 		return nil, gtserror.Newf("invalid account uri: %w", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Allocate Create activity and address 'To' poll author. | 	// Parse each choice to a Note and add it to the list of Creates. | ||||||
| 	create := streams.NewActivityStreamsCreate() | 	creates := make([]vocab.ActivityStreamsCreate, len(vote.Choices)) | ||||||
| 	ap.AppendTo(create, pollAuthorIRI) | 	for i, choice := range vote.Choices { | ||||||
| 
 | 
 | ||||||
| 	// Create ID formatted as: {$voterIRI}/activity#vote/{$statusIRI}. | 		// Allocate Create activity and address 'To' poll author. | ||||||
| 	id := author.URI + "/activity#vote/" + poll.Status.URI | 		create := streams.NewActivityStreamsCreate() | ||||||
| 	ap.MustSet(ap.SetJSONLDIdStr, ap.WithJSONLDId(create), id) | 		ap.AppendTo(create, pollAuthorIRI) | ||||||
| 
 | 
 | ||||||
| 	// Set Create actor appropriately. | 		// Create ID formatted as: {$voterIRI}/activity#vote{$index}/{$statusIRI}. | ||||||
| 	ap.AppendActorIRIs(create, authorIRI) | 		createID := fmt.Sprintf("%s/activity#vote%d/%s", author.URI, i, poll.Status.URI) | ||||||
|  | 		ap.MustSet(ap.SetJSONLDIdStr, ap.WithJSONLDId(create), createID) | ||||||
| 
 | 
 | ||||||
| 	// Set publish time for activity. | 		// Set Create actor appropriately. | ||||||
| 	ap.SetPublished(create, vote.CreatedAt) | 		ap.AppendActorIRIs(create, authorIRI) | ||||||
| 
 | 
 | ||||||
| 	// Parse each choice to a Note and add it to the Create. | 		// Set publish time for activity. | ||||||
| 	for _, choice := range vote.Choices { | 		ap.SetPublished(create, vote.CreatedAt) | ||||||
|  | 
 | ||||||
|  | 		// Allocate new note to hold the vote. | ||||||
| 		note := streams.NewActivityStreamsNote() | 		note := streams.NewActivityStreamsNote() | ||||||
| 
 | 
 | ||||||
| 		// For AP IRI generate from author URI + poll ID + vote choice. | 		// For AP IRI generate from author URI + poll ID + vote choice. | ||||||
|  | @ -1775,11 +1782,14 @@ func (c *Converter) PollVoteToASCreate( | ||||||
| 		ap.AppendInReplyTo(note, statusIRI) | 		ap.AppendInReplyTo(note, statusIRI) | ||||||
| 		ap.AppendTo(note, pollAuthorIRI) | 		ap.AppendTo(note, pollAuthorIRI) | ||||||
| 
 | 
 | ||||||
| 		// Append this note as Create Object. | 		// Append this note to the Create Object. | ||||||
| 		appendStatusableToActivity(create, note, false) | 		appendStatusableToActivity(create, note, false) | ||||||
|  | 
 | ||||||
|  | 		// Set create in slice. | ||||||
|  | 		creates[i] = create | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return create, nil | 	return creates, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // populateValuesForProp appends the given PolicyValues | // populateValuesForProp appends the given PolicyValues | ||||||
|  |  | ||||||
|  | @ -1104,43 +1104,55 @@ func (suite *InternalToASTestSuite) TestPinnedStatusesToASOneItem() { | ||||||
| func (suite *InternalToASTestSuite) TestPollVoteToASCreate() { | func (suite *InternalToASTestSuite) TestPollVoteToASCreate() { | ||||||
| 	vote := suite.testPollVotes["remote_account_1_status_2_poll_vote_local_account_1"] | 	vote := suite.testPollVotes["remote_account_1_status_2_poll_vote_local_account_1"] | ||||||
| 
 | 
 | ||||||
| 	create, err := suite.typeconverter.PollVoteToASCreate(context.Background(), vote) | 	creates, err := suite.typeconverter.PollVoteToASCreates(context.Background(), vote) | ||||||
| 	if err != nil { | 	suite.NoError(err) | ||||||
| 		suite.FailNow(err.Error()) | 	suite.Len(creates, 2) | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	createI, err := ap.Serialize(create) | 	createI0, err := ap.Serialize(creates[0]) | ||||||
| 	suite.NoError(err) | 	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.NoError(err) | ||||||
| 
 | 
 | ||||||
| 	suite.Equal(`{ | 	suite.Equal(`{ | ||||||
|   "@context": "https://www.w3.org/ns/activitystreams", |   "@context": "https://www.w3.org/ns/activitystreams", | ||||||
|   "actor": "http://localhost:8080/users/the_mighty_zork", |   "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", |   "id": "http://localhost:8080/users/the_mighty_zork/activity#vote0/http://fossbros-anonymous.io/users/foss_satan/statuses/01HEN2QRFA8H3C6QPN7RD4KSR6", | ||||||
|   "object": [ |   "object": { | ||||||
|     { |     "attributedTo": "http://localhost:8080/users/the_mighty_zork", | ||||||
|       "attributedTo": "http://localhost:8080/users/the_mighty_zork", |     "id": "http://localhost:8080/users/the_mighty_zork#01HEN2R65468ZG657C4ZPHJ4EX/votes/1", | ||||||
|       "id": "http://localhost:8080/users/the_mighty_zork#01HEN2R65468ZG657C4ZPHJ4EX/votes/1", |     "inReplyTo": "http://fossbros-anonymous.io/users/foss_satan/statuses/01HEN2QRFA8H3C6QPN7RD4KSR6", | ||||||
|       "inReplyTo": "http://fossbros-anonymous.io/users/foss_satan/statuses/01HEN2QRFA8H3C6QPN7RD4KSR6", |     "name": "tissues", | ||||||
|       "name": "tissues", |     "to": "http://fossbros-anonymous.io/users/foss_satan", | ||||||
|       "to": "http://fossbros-anonymous.io/users/foss_satan", |     "type": "Note" | ||||||
|       "type": "Note" |   }, | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       "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", |   "published": "2021-09-11T11:45:37+02:00", | ||||||
|   "to": "http://fossbros-anonymous.io/users/foss_satan", |   "to": "http://fossbros-anonymous.io/users/foss_satan", | ||||||
|   "type": "Create" |   "type": "Create" | ||||||
| }`, string(bytes)) | }`, 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(bytes1)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (suite *InternalToASTestSuite) TestInteractionReqToASAcceptAnnounce() { | func (suite *InternalToASTestSuite) TestInteractionReqToASAcceptAnnounce() { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue