mirror of
https://codeberg.org/superseriousbusiness/gotosocial.git
synced 2024-12-19 23:52:04 +03: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…
Reference in a new issue