From 8cafa6b74b81fd8f0e5730007acdabd4c4e98944 Mon Sep 17 00:00:00 2001 From: tobi <31960611+tsmethurst@users.noreply.github.com> Date: Tue, 20 Feb 2024 18:50:54 +0100 Subject: [PATCH] [feature] Add `requested_by` to relationship model (#2672) * [feature] Add `requested_by` to relationship model * whoops, missed some tests --- docs/api/swagger.yaml | 10 ++- .../client/followrequests/authorize_test.go | 1 + .../api/client/followrequests/reject_test.go | 1 + internal/api/model/relationship.go | 2 + internal/db/bundb/relationship.go | 9 ++ internal/db/bundb/relationship_test.go | 8 ++ internal/gtsmodel/account.go | 3 +- internal/typeutils/internaltofrontend.go | 1 + internal/typeutils/internaltofrontend_test.go | 88 +++++++++++++++++++ 9 files changed, 121 insertions(+), 2 deletions(-) diff --git a/docs/api/swagger.yaml b/docs/api/swagger.yaml index 7f0e2e1f9..2c4e88f2d 100644 --- a/docs/api/swagger.yaml +++ b/docs/api/swagger.yaml @@ -345,6 +345,10 @@ definitions: description: You have requested to follow this account, and the request is pending. type: boolean x-go-name: Requested + requested_by: + description: This account has requested to follow you, and the request is pending. + type: boolean + x-go-name: RequestedBy showing_reblogs: description: You are seeing reblogs/boosts from this account in your home timeline. type: boolean @@ -1487,7 +1491,10 @@ definitions: additionalProperties: format: int64 type: integer - description: 'Statistics about the instance: number of posts, accounts, etc.' + description: |- + Statistics about the instance: number of posts, accounts, etc. + Values are pointers because we don't want to skip 0 values when + rendering stats via web templates. type: object x-go-name: Stats terms: @@ -3648,6 +3655,7 @@ paths: post: consumes: - multipart/form-data + description: NOT IMPLEMENTED YET! operationId: accountMove parameters: - description: Password of the account user, for confirmation. diff --git a/internal/api/client/followrequests/authorize_test.go b/internal/api/client/followrequests/authorize_test.go index 5adb7be86..4c0617958 100644 --- a/internal/api/client/followrequests/authorize_test.go +++ b/internal/api/client/followrequests/authorize_test.go @@ -92,6 +92,7 @@ func (suite *AuthorizeTestSuite) TestAuthorize() { "muting": false, "muting_notifications": false, "requested": false, + "requested_by": false, "domain_blocking": false, "endorsed": false, "note": "" diff --git a/internal/api/client/followrequests/reject_test.go b/internal/api/client/followrequests/reject_test.go index 51fd98150..e6837066c 100644 --- a/internal/api/client/followrequests/reject_test.go +++ b/internal/api/client/followrequests/reject_test.go @@ -92,6 +92,7 @@ func (suite *RejectTestSuite) TestReject() { "muting": false, "muting_notifications": false, "requested": false, + "requested_by": false, "domain_blocking": false, "endorsed": false, "note": "" diff --git a/internal/api/model/relationship.go b/internal/api/model/relationship.go index dfb72bfe5..bb80791b3 100644 --- a/internal/api/model/relationship.go +++ b/internal/api/model/relationship.go @@ -42,6 +42,8 @@ type Relationship struct { MutingNotifications bool `json:"muting_notifications"` // You have requested to follow this account, and the request is pending. Requested bool `json:"requested"` + // This account has requested to follow you, and the request is pending. + RequestedBy bool `json:"requested_by"` // You are blocking this account's domain. DomainBlocking bool `json:"domain_blocking"` // You are featuring this account on your profile. diff --git a/internal/db/bundb/relationship.go b/internal/db/bundb/relationship.go index 71ae37545..a97aa71ff 100644 --- a/internal/db/bundb/relationship.go +++ b/internal/db/bundb/relationship.go @@ -74,6 +74,15 @@ func (r *relationshipDB) GetRelationship(ctx context.Context, requestingAccount return nil, gtserror.Newf("error checking requested: %w", err) } + // check if target has follow requested requesting + rel.RequestedBy, err = r.IsFollowRequested(ctx, + targetAccount, + requestingAccount, + ) + if err != nil { + return nil, gtserror.Newf("error checking requestedBy: %w", err) + } + // check if the requesting account is blocking the target account rel.Blocking, err = r.IsBlocked(ctx, requestingAccount, targetAccount) if err != nil { diff --git a/internal/db/bundb/relationship_test.go b/internal/db/bundb/relationship_test.go index aa2353961..9858e4768 100644 --- a/internal/db/bundb/relationship_test.go +++ b/internal/db/bundb/relationship_test.go @@ -596,6 +596,14 @@ func (suite *RelationshipTestSuite) TestAcceptFollowRequestOK() { suite.False(relationship.Following) suite.True(relationship.Requested) + // Check the other way around too; local_account_2 + // should have requested_by true for admin now. + inverse, err := suite.db.GetRelationship(ctx, targetAccount.ID, account.ID) + if err != nil { + suite.FailNow(err.Error()) + } + suite.True(inverse.RequestedBy) + followRequestNotification := >smodel.Notification{ ID: "01GV8MY1Q9KX2ZSWN4FAQ3V1PB", OriginAccountID: account.ID, diff --git a/internal/gtsmodel/account.go b/internal/gtsmodel/account.go index f5b487cc8..5421c41bb 100644 --- a/internal/gtsmodel/account.go +++ b/internal/gtsmodel/account.go @@ -200,7 +200,8 @@ type Relationship struct { BlockedBy bool // Is this user blocking you? Muting bool // Are you muting this user? MutingNotifications bool // Are you muting notifications from this user? - Requested bool // Do you have a pending follow request for this user? + Requested bool // Do you have a pending follow request targeting this user? + RequestedBy bool // Does the user have a pending follow request targeting you? DomainBlocking bool // Are you blocking this user's domain? Endorsed bool // Are you featuring this user on your profile? Note string // Your note on this account. diff --git a/internal/typeutils/internaltofrontend.go b/internal/typeutils/internaltofrontend.go index 592f36010..d74f4d86e 100644 --- a/internal/typeutils/internaltofrontend.go +++ b/internal/typeutils/internaltofrontend.go @@ -1194,6 +1194,7 @@ func (c *Converter) RelationshipToAPIRelationship(ctx context.Context, r *gtsmod Muting: r.Muting, MutingNotifications: r.MutingNotifications, Requested: r.Requested, + RequestedBy: r.RequestedBy, DomainBlocking: r.DomainBlocking, Endorsed: r.Endorsed, Note: r.Note, diff --git a/internal/typeutils/internaltofrontend_test.go b/internal/typeutils/internaltofrontend_test.go index c99099445..9003dcca3 100644 --- a/internal/typeutils/internaltofrontend_test.go +++ b/internal/typeutils/internaltofrontend_test.go @@ -1967,6 +1967,94 @@ func (suite *InternalToFrontendTestSuite) TestAdminReportToFrontendSuspendedLoca }`, string(b)) } +func (suite *InternalToFrontendTestSuite) TestRelationshipFollowRequested() { + var ( + ctx = context.Background() + account1 = suite.testAccounts["admin_account"] + account2 = suite.testAccounts["local_account_2"] + ) + + // Put a follow request in the db from + // admin account targeting local_account_2. + followRequest := >smodel.FollowRequest{ + ID: "01GEF753FWHCHRDWR0QEHBXM8W", + URI: "http://localhost:8080/weeeeeeeeeeeeeeeee", + AccountID: account1.ID, + TargetAccountID: account2.ID, + } + if err := suite.db.PutFollowRequest(ctx, followRequest); err != nil { + suite.FailNow(err.Error()) + } + + // Fetch the relationship from the database. + dbRelationship, err := suite.state.DB.GetRelationship(ctx, account1.ID, account2.ID) + if err != nil { + suite.FailNow(err.Error()) + } + + // Check API model is set appropriately. + relationship, err := suite.typeconverter.RelationshipToAPIRelationship(ctx, dbRelationship) + if err != nil { + suite.FailNow(err.Error()) + } + + b, err := json.MarshalIndent(relationship, "", " ") + if err != nil { + suite.FailNow(err.Error()) + } + + suite.Equal(`{ + "id": "01F8MH5NBDF2MV7CTC4Q5128HF", + "following": false, + "showing_reblogs": false, + "notifying": false, + "followed_by": false, + "blocking": false, + "blocked_by": false, + "muting": false, + "muting_notifications": false, + "requested": true, + "requested_by": false, + "domain_blocking": false, + "endorsed": false, + "note": "" +}`, string(b)) + + // Check relationship from the other side too. + dbRelationship, err = suite.state.DB.GetRelationship(ctx, account2.ID, account1.ID) + if err != nil { + suite.FailNow(err.Error()) + } + + // Check API model is set appropriately. + relationship, err = suite.typeconverter.RelationshipToAPIRelationship(ctx, dbRelationship) + if err != nil { + suite.FailNow(err.Error()) + } + + b, err = json.MarshalIndent(relationship, "", " ") + if err != nil { + suite.FailNow(err.Error()) + } + + suite.Equal(`{ + "id": "01F8MH17FWEB39HZJ76B6VXSKF", + "following": false, + "showing_reblogs": false, + "notifying": false, + "followed_by": false, + "blocking": false, + "blocked_by": false, + "muting": false, + "muting_notifications": false, + "requested": false, + "requested_by": true, + "domain_blocking": false, + "endorsed": false, + "note": "" +}`, string(b)) +} + func TestInternalToFrontendTestSuite(t *testing.T) { suite.Run(t, new(InternalToFrontendTestSuite)) }