mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-11-15 10:07:28 -06:00
[feature] Support new model of interaction flow for forward compat with v0.21.0 (#4394)
~~Still WIP!~~ This PR allows v0.20.0 of GtS to be forward-compatible with the interaction request / authorization flow that will fully replace the current flow in v0.21.0. Basically, this means we need to recognize LikeRequest, ReplyRequest, and AnnounceRequest, and in response to those requests, deliver either a Reject or an Accept, with the latter pointing towards a LikeAuthorization, ReplyAuthorization, or AnnounceAuthorization, respectively. This can then be used by the remote instance to prove to third parties that the interaction has been accepted by the interactee. These Authorization types need to be dereferencable to third parties, so we need to serve them. As well as recognizing the above "polite" interaction request types, we also need to still serve appropriate responses to "impolite" interaction request types, where an instance that's unaware of interaction policies tries to interact with a post by sending a reply, like, or boost directly, without wrapping it in a WhateverRequest type. Doesn't fully close https://codeberg.org/superseriousbusiness/gotosocial/issues/4026 but gets damn near (just gotta update the federating with GtS documentation). Migrations tested on both Postgres and SQLite. Co-authored-by: kim <grufwub@gmail.com> Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4394 Co-authored-by: tobi <tobi.smethurst@protonmail.com> Co-committed-by: tobi <tobi.smethurst@protonmail.com>
This commit is contained in:
parent
33fed81a8d
commit
754b7be9cf
126 changed files with 6637 additions and 1778 deletions
|
|
@ -444,8 +444,8 @@ func (c *Converter) ASStatusToStatus(ctx context.Context, statusable ap.Statusab
|
|||
|
||||
// Set approvedByURI if present,
|
||||
// for later dereferencing.
|
||||
if ipa, ok := statusable.(ap.InteractionPolicyAware); ok {
|
||||
approvedByURI := ap.GetApprovedBy(ipa)
|
||||
if wab, ok := statusable.(ap.WithApprovedBy); ok {
|
||||
approvedByURI := ap.GetApprovedBy(wab)
|
||||
if approvedByURI != nil {
|
||||
status.ApprovedByURI = approvedByURI.String()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,17 +104,18 @@ func (c *Converter) StatusToBoost(
|
|||
return boost, nil
|
||||
}
|
||||
|
||||
func StatusToInteractionRequest(status *gtsmodel.Status) *gtsmodel.InteractionRequest {
|
||||
func StatusToImpoliteInteractionRequest(status *gtsmodel.Status) *gtsmodel.InteractionRequest {
|
||||
reqID := id.NewULIDFromTime(status.CreatedAt)
|
||||
|
||||
var (
|
||||
targetID string
|
||||
target *gtsmodel.Status
|
||||
targetAccountID string
|
||||
targetAccount *gtsmodel.Account
|
||||
interactionType gtsmodel.InteractionType
|
||||
reply *gtsmodel.Status
|
||||
announce *gtsmodel.Status
|
||||
targetID string
|
||||
target *gtsmodel.Status
|
||||
targetAccountID string
|
||||
targetAccount *gtsmodel.Account
|
||||
interactionRequestURI string
|
||||
interactionType gtsmodel.InteractionType
|
||||
reply *gtsmodel.Status
|
||||
announce *gtsmodel.Status
|
||||
)
|
||||
|
||||
if status.InReplyToID != "" {
|
||||
|
|
@ -123,6 +124,7 @@ func StatusToInteractionRequest(status *gtsmodel.Status) *gtsmodel.InteractionRe
|
|||
target = status.InReplyTo
|
||||
targetAccountID = status.InReplyToAccountID
|
||||
targetAccount = status.InReplyToAccount
|
||||
interactionRequestURI = gtsmodel.ForwardCompatibleInteractionRequestURI(status.URI, gtsmodel.ReplyRequestSuffix)
|
||||
interactionType = gtsmodel.InteractionReply
|
||||
reply = status
|
||||
} else {
|
||||
|
|
@ -131,41 +133,43 @@ func StatusToInteractionRequest(status *gtsmodel.Status) *gtsmodel.InteractionRe
|
|||
target = status.BoostOf
|
||||
targetAccountID = status.BoostOfAccountID
|
||||
targetAccount = status.BoostOfAccount
|
||||
interactionRequestURI = gtsmodel.ForwardCompatibleInteractionRequestURI(status.URI, gtsmodel.AnnounceRequestSuffix)
|
||||
interactionType = gtsmodel.InteractionAnnounce
|
||||
announce = status
|
||||
}
|
||||
|
||||
return >smodel.InteractionRequest{
|
||||
ID: reqID,
|
||||
CreatedAt: status.CreatedAt,
|
||||
StatusID: targetID,
|
||||
Status: target,
|
||||
TargetAccountID: targetAccountID,
|
||||
TargetAccount: targetAccount,
|
||||
InteractingAccountID: status.AccountID,
|
||||
InteractingAccount: status.Account,
|
||||
InteractionURI: status.URI,
|
||||
InteractionType: interactionType,
|
||||
Reply: reply,
|
||||
Announce: announce,
|
||||
ID: reqID,
|
||||
TargetStatusID: targetID,
|
||||
TargetStatus: target,
|
||||
TargetAccountID: targetAccountID,
|
||||
TargetAccount: targetAccount,
|
||||
InteractingAccountID: status.AccountID,
|
||||
InteractingAccount: status.Account,
|
||||
InteractionRequestURI: interactionRequestURI,
|
||||
InteractionURI: status.URI,
|
||||
InteractionType: interactionType,
|
||||
Polite: util.Ptr(false),
|
||||
Reply: reply,
|
||||
Announce: announce,
|
||||
}
|
||||
}
|
||||
|
||||
func StatusFaveToInteractionRequest(fave *gtsmodel.StatusFave) *gtsmodel.InteractionRequest {
|
||||
func StatusFaveToImpoliteInteractionRequest(fave *gtsmodel.StatusFave) *gtsmodel.InteractionRequest {
|
||||
reqID := id.NewULIDFromTime(fave.CreatedAt)
|
||||
|
||||
return >smodel.InteractionRequest{
|
||||
ID: reqID,
|
||||
CreatedAt: fave.CreatedAt,
|
||||
StatusID: fave.StatusID,
|
||||
Status: fave.Status,
|
||||
TargetAccountID: fave.TargetAccountID,
|
||||
TargetAccount: fave.TargetAccount,
|
||||
InteractingAccountID: fave.AccountID,
|
||||
InteractingAccount: fave.Account,
|
||||
InteractionURI: fave.URI,
|
||||
InteractionType: gtsmodel.InteractionLike,
|
||||
Like: fave,
|
||||
ID: reqID,
|
||||
TargetStatusID: fave.StatusID,
|
||||
TargetStatus: fave.Status,
|
||||
TargetAccountID: fave.TargetAccountID,
|
||||
TargetAccount: fave.TargetAccount,
|
||||
InteractingAccountID: fave.AccountID,
|
||||
InteractingAccount: fave.Account,
|
||||
InteractionRequestURI: gtsmodel.ForwardCompatibleInteractionRequestURI(fave.URI, gtsmodel.LikeRequestSuffix),
|
||||
InteractionURI: fave.URI,
|
||||
InteractionType: gtsmodel.InteractionLike,
|
||||
Polite: util.Ptr(false),
|
||||
Like: fave,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -25,6 +25,8 @@ import (
|
|||
"code.superseriousbusiness.org/gotosocial/internal/ap"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/db"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/uris"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/util"
|
||||
"code.superseriousbusiness.org/gotosocial/testrig"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
|
@ -947,6 +949,264 @@ func (suite *InternalToASTestSuite) TestStatusToASWithMentions() {
|
|||
}`, string(bytes))
|
||||
}
|
||||
|
||||
func (suite *InternalToASTestSuite) TestStatusToASPoliteApproved() {
|
||||
ctx := suite.T().Context()
|
||||
|
||||
// Take a status from admin that replies to turtle.
|
||||
testStatus := new(gtsmodel.Status)
|
||||
*testStatus = *suite.testStatuses["admin_account_status_5"]
|
||||
|
||||
// Take corresponding interaction request.
|
||||
intReq := new(gtsmodel.InteractionRequest)
|
||||
*intReq = *suite.testInteractionRequests["admin_account_reply_turtle"]
|
||||
|
||||
// Mark the status as approved by updating the
|
||||
// status + corresponding interaction request.
|
||||
username := suite.testAccounts["local_account_2"].Username
|
||||
intReq.ResponseURI = uris.GenerateURIForAccept(
|
||||
username,
|
||||
intReq.ID,
|
||||
)
|
||||
intReq.AuthorizationURI = uris.GenerateURIForAuthorization(
|
||||
username,
|
||||
intReq.ID,
|
||||
)
|
||||
intReq.AcceptedAt = testrig.TimeMustParse("2024-11-01T11:00:00+02:00")
|
||||
|
||||
// Mark it as polite too.
|
||||
intReq.Polite = util.Ptr(true)
|
||||
|
||||
if err := suite.state.DB.UpdateInteractionRequest(
|
||||
ctx,
|
||||
intReq,
|
||||
"response_uri",
|
||||
"authorization_uri",
|
||||
"accepted_at",
|
||||
"polite",
|
||||
); err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
testStatus.ApprovedByURI = intReq.AuthorizationURI
|
||||
if err := suite.state.DB.UpdateStatus(
|
||||
ctx,
|
||||
testStatus,
|
||||
"approved_by_uri",
|
||||
); err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
asStatus, err := suite.typeconverter.StatusToAS(ctx, testStatus)
|
||||
suite.NoError(err)
|
||||
|
||||
ser, err := ap.Serialize(asStatus)
|
||||
suite.NoError(err)
|
||||
|
||||
bytes, err := json.MarshalIndent(ser, "", " ")
|
||||
suite.NoError(err)
|
||||
|
||||
suite.Equal(`{
|
||||
"@context": [
|
||||
"https://gotosocial.org/ns",
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
{
|
||||
"sensitive": "as:sensitive"
|
||||
}
|
||||
],
|
||||
"approvedBy": "http://localhost:8080/users/1happyturtle/accepts/01J5QVXCCEATJYSXM9H6MZT4JR",
|
||||
"attachment": [],
|
||||
"attributedTo": "http://localhost:8080/users/admin",
|
||||
"cc": [
|
||||
"http://localhost:8080/users/admin/followers",
|
||||
"http://localhost:8080/users/1happyturtle"
|
||||
],
|
||||
"content": "\u003cp\u003eHi \u003cspan class=\"h-card\"\u003e\u003ca href=\"http://localhost:8080/@1happyturtle\" class=\"u-url mention\" rel=\"nofollow noreferrer noopener\" target=\"_blank\"\u003e@\u003cspan\u003e1happyturtle\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e, can I reply?\u003c/p\u003e",
|
||||
"id": "http://localhost:8080/users/admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ",
|
||||
"inReplyTo": "http://localhost:8080/users/1happyturtle/statuses/01F8MHC8VWDRBQR0N1BATDDEM5",
|
||||
"interactionPolicy": {
|
||||
"canAnnounce": {
|
||||
"always": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"approvalRequired": [],
|
||||
"automaticApproval": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"manualApproval": []
|
||||
},
|
||||
"canLike": {
|
||||
"always": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"approvalRequired": [],
|
||||
"automaticApproval": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"manualApproval": []
|
||||
},
|
||||
"canReply": {
|
||||
"always": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"approvalRequired": [],
|
||||
"automaticApproval": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"manualApproval": []
|
||||
}
|
||||
},
|
||||
"published": "2024-02-20T12:41:37+02:00",
|
||||
"replies": {
|
||||
"first": {
|
||||
"id": "http://localhost:8080/users/admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ/replies?page=true",
|
||||
"next": "http://localhost:8080/users/admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ/replies?page=true\u0026only_other_accounts=false",
|
||||
"partOf": "http://localhost:8080/users/admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ/replies",
|
||||
"type": "CollectionPage"
|
||||
},
|
||||
"id": "http://localhost:8080/users/admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ/replies",
|
||||
"type": "Collection"
|
||||
},
|
||||
"replyAuthorization": "http://localhost:8080/users/1happyturtle/authorizations/01J5QVXCCEATJYSXM9H6MZT4JR",
|
||||
"sensitive": false,
|
||||
"summary": "",
|
||||
"tag": {
|
||||
"href": "http://localhost:8080/users/1happyturtle",
|
||||
"name": "@1happyturtle@localhost:8080",
|
||||
"type": "Mention"
|
||||
},
|
||||
"to": "https://www.w3.org/ns/activitystreams#Public",
|
||||
"type": "Note",
|
||||
"url": "http://localhost:8080/@admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ"
|
||||
}`, string(bytes))
|
||||
}
|
||||
|
||||
func (suite *InternalToASTestSuite) TestStatusToASPImpoliteApproved() {
|
||||
ctx := suite.T().Context()
|
||||
|
||||
// Take a status from admin that replies to turtle.
|
||||
testStatus := new(gtsmodel.Status)
|
||||
*testStatus = *suite.testStatuses["admin_account_status_5"]
|
||||
|
||||
// Take corresponding interaction request.
|
||||
intReq := new(gtsmodel.InteractionRequest)
|
||||
*intReq = *suite.testInteractionRequests["admin_account_reply_turtle"]
|
||||
|
||||
// Mark the status as approved by updating the
|
||||
// status + corresponding interaction request.
|
||||
username := suite.testAccounts["local_account_2"].Username
|
||||
intReq.ResponseURI = uris.GenerateURIForAccept(
|
||||
username,
|
||||
intReq.ID,
|
||||
)
|
||||
intReq.AuthorizationURI = uris.GenerateURIForAuthorization(
|
||||
username,
|
||||
intReq.ID,
|
||||
)
|
||||
intReq.AcceptedAt = testrig.TimeMustParse("2024-11-01T11:00:00+02:00")
|
||||
|
||||
if err := suite.state.DB.UpdateInteractionRequest(
|
||||
ctx,
|
||||
intReq,
|
||||
"response_uri",
|
||||
"authorization_uri",
|
||||
"accepted_at",
|
||||
); err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
testStatus.ApprovedByURI = intReq.AuthorizationURI
|
||||
if err := suite.state.DB.UpdateStatus(
|
||||
ctx,
|
||||
testStatus,
|
||||
"approved_by_uri",
|
||||
); err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
asStatus, err := suite.typeconverter.StatusToAS(ctx, testStatus)
|
||||
suite.NoError(err)
|
||||
|
||||
ser, err := ap.Serialize(asStatus)
|
||||
suite.NoError(err)
|
||||
|
||||
bytes, err := json.MarshalIndent(ser, "", " ")
|
||||
suite.NoError(err)
|
||||
|
||||
suite.Equal(`{
|
||||
"@context": [
|
||||
"https://gotosocial.org/ns",
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
{
|
||||
"sensitive": "as:sensitive"
|
||||
}
|
||||
],
|
||||
"approvedBy": "http://localhost:8080/users/1happyturtle/accepts/01J5QVXCCEATJYSXM9H6MZT4JR",
|
||||
"attachment": [],
|
||||
"attributedTo": "http://localhost:8080/users/admin",
|
||||
"cc": [
|
||||
"http://localhost:8080/users/admin/followers",
|
||||
"http://localhost:8080/users/1happyturtle"
|
||||
],
|
||||
"content": "\u003cp\u003eHi \u003cspan class=\"h-card\"\u003e\u003ca href=\"http://localhost:8080/@1happyturtle\" class=\"u-url mention\" rel=\"nofollow noreferrer noopener\" target=\"_blank\"\u003e@\u003cspan\u003e1happyturtle\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e, can I reply?\u003c/p\u003e",
|
||||
"id": "http://localhost:8080/users/admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ",
|
||||
"inReplyTo": "http://localhost:8080/users/1happyturtle/statuses/01F8MHC8VWDRBQR0N1BATDDEM5",
|
||||
"interactionPolicy": {
|
||||
"canAnnounce": {
|
||||
"always": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"approvalRequired": [],
|
||||
"automaticApproval": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"manualApproval": []
|
||||
},
|
||||
"canLike": {
|
||||
"always": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"approvalRequired": [],
|
||||
"automaticApproval": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"manualApproval": []
|
||||
},
|
||||
"canReply": {
|
||||
"always": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"approvalRequired": [],
|
||||
"automaticApproval": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"manualApproval": []
|
||||
}
|
||||
},
|
||||
"published": "2024-02-20T12:41:37+02:00",
|
||||
"replies": {
|
||||
"first": {
|
||||
"id": "http://localhost:8080/users/admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ/replies?page=true",
|
||||
"next": "http://localhost:8080/users/admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ/replies?page=true\u0026only_other_accounts=false",
|
||||
"partOf": "http://localhost:8080/users/admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ/replies",
|
||||
"type": "CollectionPage"
|
||||
},
|
||||
"id": "http://localhost:8080/users/admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ/replies",
|
||||
"type": "Collection"
|
||||
},
|
||||
"replyAuthorization": "http://localhost:8080/users/1happyturtle/authorizations/01J5QVXCCEATJYSXM9H6MZT4JR",
|
||||
"sensitive": false,
|
||||
"summary": "",
|
||||
"tag": {
|
||||
"href": "http://localhost:8080/users/1happyturtle",
|
||||
"name": "@1happyturtle@localhost:8080",
|
||||
"type": "Mention"
|
||||
},
|
||||
"to": "https://www.w3.org/ns/activitystreams#Public",
|
||||
"type": "Note",
|
||||
"url": "http://localhost:8080/@admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ"
|
||||
}`, string(bytes))
|
||||
}
|
||||
|
||||
func (suite *InternalToASTestSuite) TestStatusToASDeletePublicReply() {
|
||||
testStatus := suite.testStatuses["admin_account_status_3"]
|
||||
ctx := suite.T().Context()
|
||||
|
|
@ -1119,7 +1379,7 @@ func (suite *InternalToASTestSuite) TestSelfBoostFollowersOnlyToAS() {
|
|||
boostWrapperStatus.URI = "http://localhost:8080/users/the_mighty_zork/statuses/01G74JJ1KS331G2JXHRMZCE0ER"
|
||||
boostWrapperStatus.CreatedAt = testrig.TimeMustParse("2022-06-09T13:12:00Z")
|
||||
|
||||
asBoost, err := suite.typeconverter.BoostToAS(ctx, boostWrapperStatus, testAccount, testAccount)
|
||||
asBoost, err := suite.typeconverter.BoostToAS(ctx, boostWrapperStatus)
|
||||
suite.NoError(err)
|
||||
|
||||
ser, err := ap.Serialize(asBoost)
|
||||
|
|
@ -1320,23 +1580,24 @@ func (suite *InternalToASTestSuite) TestPollVoteToASCreate() {
|
|||
}`, string(bytes1))
|
||||
}
|
||||
|
||||
func (suite *InternalToASTestSuite) TestInteractionReqToASAcceptAnnounce() {
|
||||
func (suite *InternalToASTestSuite) TestImpoliteInteractionReqToASAcceptAnnounce() {
|
||||
acceptingAccount := suite.testAccounts["local_account_1"]
|
||||
interactingAccount := suite.testAccounts["remote_account_1"]
|
||||
|
||||
req := >smodel.InteractionRequest{
|
||||
ID: "01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
CreatedAt: testrig.TimeMustParse("2022-06-09T13:12:00Z"),
|
||||
StatusID: "01JJYCVKCXB9JTQD1XW2KB8MT3",
|
||||
Status: >smodel.Status{URI: "http://localhost:8080/users/the_mighty_zork/statuses/01JJYCVKCXB9JTQD1XW2KB8MT3"},
|
||||
TargetAccountID: acceptingAccount.ID,
|
||||
TargetAccount: acceptingAccount,
|
||||
InteractingAccountID: interactingAccount.ID,
|
||||
InteractingAccount: interactingAccount,
|
||||
InteractionURI: "https://fossbros-anonymous.io/users/foss_satan/statuses/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
InteractionType: gtsmodel.InteractionAnnounce,
|
||||
URI: "http://localhost:8080/users/the_mighty_zork/accepts/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
AcceptedAt: testrig.TimeMustParse("2022-06-09T13:12:00Z"),
|
||||
ID: "01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
TargetStatusID: "01JJYCVKCXB9JTQD1XW2KB8MT3",
|
||||
TargetStatus: >smodel.Status{URI: "http://localhost:8080/users/the_mighty_zork/statuses/01JJYCVKCXB9JTQD1XW2KB8MT3"},
|
||||
TargetAccountID: acceptingAccount.ID,
|
||||
TargetAccount: acceptingAccount,
|
||||
InteractingAccountID: interactingAccount.ID,
|
||||
InteractingAccount: interactingAccount,
|
||||
InteractionRequestURI: "https://fossbros-anonymous.io/users/foss_satan/statuses/01J1AKRRHQ6MDDQHV0TP716T2K" + gtsmodel.AnnounceRequestSuffix,
|
||||
InteractionURI: "https://fossbros-anonymous.io/users/foss_satan/statuses/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
InteractionType: gtsmodel.InteractionAnnounce,
|
||||
Polite: util.Ptr(false),
|
||||
ResponseURI: "http://localhost:8080/users/the_mighty_zork/accepts/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
AcceptedAt: testrig.TimeMustParse("2022-06-09T13:12:00Z"),
|
||||
}
|
||||
|
||||
accept, err := suite.typeconverter.InteractionReqToASAccept(
|
||||
|
|
@ -1372,23 +1633,24 @@ func (suite *InternalToASTestSuite) TestInteractionReqToASAcceptAnnounce() {
|
|||
}`, string(b))
|
||||
}
|
||||
|
||||
func (suite *InternalToASTestSuite) TestInteractionReqToASAcceptLike() {
|
||||
func (suite *InternalToASTestSuite) TestImpoliteInteractionReqToASAcceptLike() {
|
||||
acceptingAccount := suite.testAccounts["local_account_1"]
|
||||
interactingAccount := suite.testAccounts["remote_account_1"]
|
||||
|
||||
req := >smodel.InteractionRequest{
|
||||
ID: "01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
CreatedAt: testrig.TimeMustParse("2022-06-09T13:12:00Z"),
|
||||
StatusID: "01JJYCVKCXB9JTQD1XW2KB8MT3",
|
||||
Status: >smodel.Status{URI: "http://localhost:8080/users/the_mighty_zork/statuses/01JJYCVKCXB9JTQD1XW2KB8MT3"},
|
||||
TargetAccountID: acceptingAccount.ID,
|
||||
TargetAccount: acceptingAccount,
|
||||
InteractingAccountID: interactingAccount.ID,
|
||||
InteractingAccount: interactingAccount,
|
||||
InteractionURI: "https://fossbros-anonymous.io/users/foss_satan/statuses/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
InteractionType: gtsmodel.InteractionLike,
|
||||
URI: "http://localhost:8080/users/the_mighty_zork/accepts/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
AcceptedAt: testrig.TimeMustParse("2022-06-09T13:12:00Z"),
|
||||
ID: "01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
TargetStatusID: "01JJYCVKCXB9JTQD1XW2KB8MT3",
|
||||
TargetStatus: >smodel.Status{URI: "http://localhost:8080/users/the_mighty_zork/statuses/01JJYCVKCXB9JTQD1XW2KB8MT3"},
|
||||
TargetAccountID: acceptingAccount.ID,
|
||||
TargetAccount: acceptingAccount,
|
||||
InteractingAccountID: interactingAccount.ID,
|
||||
InteractingAccount: interactingAccount,
|
||||
InteractionRequestURI: "https://fossbros-anonymous.io/users/foss_satan/likes/01J1AKRRHQ6MDDQHV0TP716T2K" + gtsmodel.LikeRequestSuffix,
|
||||
InteractionURI: "https://fossbros-anonymous.io/users/foss_satan/likes/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
InteractionType: gtsmodel.InteractionLike,
|
||||
Polite: util.Ptr(false),
|
||||
ResponseURI: "http://localhost:8080/users/the_mighty_zork/accepts/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
AcceptedAt: testrig.TimeMustParse("2022-06-09T13:12:00Z"),
|
||||
}
|
||||
|
||||
accept, err := suite.typeconverter.InteractionReqToASAccept(
|
||||
|
|
@ -1413,13 +1675,124 @@ func (suite *InternalToASTestSuite) TestInteractionReqToASAcceptLike() {
|
|||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
"actor": "http://localhost:8080/users/the_mighty_zork",
|
||||
"id": "http://localhost:8080/users/the_mighty_zork/accepts/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
"object": "https://fossbros-anonymous.io/users/foss_satan/statuses/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
"object": "https://fossbros-anonymous.io/users/foss_satan/likes/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
"target": "http://localhost:8080/users/the_mighty_zork/statuses/01JJYCVKCXB9JTQD1XW2KB8MT3",
|
||||
"to": "http://fossbros-anonymous.io/users/foss_satan",
|
||||
"type": "Accept"
|
||||
}`, string(b))
|
||||
}
|
||||
|
||||
func (suite *InternalToASTestSuite) TestInteractionReqToASAcceptLikePolite() {
|
||||
acceptingAccount := suite.testAccounts["local_account_1"]
|
||||
interactingAccount := suite.testAccounts["remote_account_1"]
|
||||
|
||||
req := >smodel.InteractionRequest{
|
||||
ID: "01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
TargetStatusID: "01JJYCVKCXB9JTQD1XW2KB8MT3",
|
||||
TargetStatus: >smodel.Status{URI: "http://localhost:8080/users/the_mighty_zork/statuses/01JJYCVKCXB9JTQD1XW2KB8MT3"},
|
||||
TargetAccountID: acceptingAccount.ID,
|
||||
TargetAccount: acceptingAccount,
|
||||
InteractingAccountID: interactingAccount.ID,
|
||||
InteractingAccount: interactingAccount,
|
||||
InteractionRequestURI: "https://fossbros-anonymous.io/users/foss_satan/interaction_requests/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
InteractionURI: "https://fossbros-anonymous.io/users/foss_satan/likes/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
InteractionType: gtsmodel.InteractionLike,
|
||||
Polite: util.Ptr(true),
|
||||
ResponseURI: "http://localhost:8080/users/the_mighty_zork/accepts/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
AuthorizationURI: "http://localhost:8080/users/the_mighty_zork/authorizations/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
AcceptedAt: testrig.TimeMustParse("2022-06-09T13:12:00Z"),
|
||||
}
|
||||
|
||||
accept, err := suite.typeconverter.InteractionReqToASAccept(
|
||||
suite.T().Context(),
|
||||
req,
|
||||
)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
i, err := ap.Serialize(accept)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
b, err := json.MarshalIndent(i, "", " ")
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
suite.Equal(`{
|
||||
"@context": [
|
||||
"https://gotosocial.org/ns",
|
||||
"https://www.w3.org/ns/activitystreams"
|
||||
],
|
||||
"actor": "http://localhost:8080/users/the_mighty_zork",
|
||||
"id": "http://localhost:8080/users/the_mighty_zork/accepts/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
"object": {
|
||||
"actor": "http://fossbros-anonymous.io/users/foss_satan",
|
||||
"id": "https://fossbros-anonymous.io/users/foss_satan/interaction_requests/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
"instrument": "https://fossbros-anonymous.io/users/foss_satan/likes/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
"object": "http://localhost:8080/users/the_mighty_zork/statuses/01JJYCVKCXB9JTQD1XW2KB8MT3",
|
||||
"type": "LikeRequest"
|
||||
},
|
||||
"result": "http://localhost:8080/users/the_mighty_zork/authorizations/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
"to": "http://fossbros-anonymous.io/users/foss_satan",
|
||||
"type": "Accept"
|
||||
}`, string(b))
|
||||
}
|
||||
|
||||
func (suite *InternalToASTestSuite) TestPoliteInteractionReqToASAuthorization() {
|
||||
acceptingAccount := suite.testAccounts["local_account_1"]
|
||||
interactingAccount := suite.testAccounts["remote_account_1"]
|
||||
|
||||
req := >smodel.InteractionRequest{
|
||||
ID: "01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
TargetStatusID: "01JJYCVKCXB9JTQD1XW2KB8MT3",
|
||||
TargetStatus: >smodel.Status{URI: "http://localhost:8080/users/the_mighty_zork/statuses/01JJYCVKCXB9JTQD1XW2KB8MT3"},
|
||||
TargetAccountID: acceptingAccount.ID,
|
||||
TargetAccount: acceptingAccount,
|
||||
InteractingAccountID: interactingAccount.ID,
|
||||
InteractingAccount: interactingAccount,
|
||||
InteractionURI: "https://fossbros-anonymous.io/users/foss_satan/likes/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
InteractionType: gtsmodel.InteractionLike,
|
||||
Polite: util.Ptr(true),
|
||||
InteractionRequestURI: "https://fossbros-anonymous.io/users/foss_satan/interaction_requests/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
ResponseURI: "http://localhost:8080/users/the_mighty_zork/accepts/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
AuthorizationURI: "http://localhost:8080/users/the_mighty_zork/authorizations/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
AcceptedAt: testrig.TimeMustParse("2022-06-09T13:12:00Z"),
|
||||
}
|
||||
|
||||
auth, err := suite.typeconverter.InteractionReqToASAuthorization(
|
||||
suite.T().Context(),
|
||||
req,
|
||||
)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
i, err := ap.Serialize(auth)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
b, err := json.MarshalIndent(i, "", " ")
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
suite.Equal(`{
|
||||
"@context": [
|
||||
"https://gotosocial.org/ns",
|
||||
"https://www.w3.org/ns/activitystreams"
|
||||
],
|
||||
"attributedTo": "http://localhost:8080/users/the_mighty_zork",
|
||||
"id": "http://localhost:8080/users/the_mighty_zork/authorizations/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
"interactingObject": "https://fossbros-anonymous.io/users/foss_satan/likes/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
"interactionTarget": "http://localhost:8080/users/the_mighty_zork/statuses/01JJYCVKCXB9JTQD1XW2KB8MT3",
|
||||
"type": "LikeAuthorization"
|
||||
}`, string(b))
|
||||
}
|
||||
|
||||
func TestInternalToASTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(InternalToASTestSuite))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2883,7 +2883,7 @@ func (c *Converter) InteractionReqToAPIInteractionReq(
|
|||
|
||||
interactedStatus, err := c.StatusToAPIStatus(
|
||||
ctx,
|
||||
req.Status,
|
||||
req.TargetStatus,
|
||||
requestingAcct,
|
||||
)
|
||||
if err != nil {
|
||||
|
|
@ -2921,16 +2921,21 @@ func (c *Converter) InteractionReqToAPIInteractionReq(
|
|||
rejectedAt = util.FormatISO8601(req.RejectedAt)
|
||||
}
|
||||
|
||||
createdAt, err := id.TimeFromULID(req.ID)
|
||||
if err != nil {
|
||||
err := gtserror.Newf("error converting id to time: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &apimodel.InteractionRequest{
|
||||
ID: req.ID,
|
||||
Type: req.InteractionType.String(),
|
||||
CreatedAt: util.FormatISO8601(req.CreatedAt),
|
||||
CreatedAt: util.FormatISO8601(createdAt),
|
||||
Account: interactingAcct,
|
||||
Status: interactedStatus,
|
||||
Reply: reply,
|
||||
AcceptedAt: acceptedAt,
|
||||
RejectedAt: rejectedAt,
|
||||
URI: req.URI,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3054,7 +3054,7 @@ func (suite *InternalToFrontendTestSuite) TestIntReqToAPI() {
|
|||
suite.Equal(`{
|
||||
"id": "01J5QVXCCEATJYSXM9H6MZT4JR",
|
||||
"type": "reply",
|
||||
"created_at": "2024-02-20T10:41:37.000Z",
|
||||
"created_at": "2024-08-20T12:24:13.966Z",
|
||||
"account": {
|
||||
"id": "01F8MH17FWEB39HZJ76B6VXSKF",
|
||||
"username": "admin",
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ func (c *Converter) WrapAccountableInUpdate(accountable ap.Accountable) (vocab.A
|
|||
update.SetActivityStreamsObject(objectProp)
|
||||
|
||||
// to should be public.
|
||||
ap.AppendTo(update, ap.PublicURI())
|
||||
ap.AppendTo(update, ap.PublicIRI())
|
||||
|
||||
// bcc should be followers.
|
||||
ap.AppendBcc(update, ap.GetFollowers(accountable))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue