2023-09-12 14:00:35 +01:00
// GoToSocial
// Copyright (C) GoToSocial Authors admin@gotosocial.org
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package account
import (
"context"
"errors"
2025-04-26 15:34:10 +02:00
"code.superseriousbusiness.org/gotosocial/internal/ap"
apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
"code.superseriousbusiness.org/gotosocial/internal/db"
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
"code.superseriousbusiness.org/gotosocial/internal/messages"
"code.superseriousbusiness.org/gotosocial/internal/paging"
2023-09-12 14:00:35 +01:00
)
// FollowRequestAccept handles the accepting of a follow request from the sourceAccountID to the requestingAccount (the currently authorized account).
func ( p * Processor ) FollowRequestAccept ( ctx context . Context , requestingAccount * gtsmodel . Account , sourceAccountID string ) ( * apimodel . Relationship , gtserror . WithCode ) {
follow , err := p . state . DB . AcceptFollowRequest ( ctx , sourceAccountID , requestingAccount . ID )
if err != nil {
return nil , gtserror . NewErrorNotFound ( err )
}
if follow . Account != nil {
// Only enqueue work in the case we have a request creating account stored.
// NOTE: due to how AcceptFollowRequest works, the inverse shouldn't be possible.
2024-04-26 13:50:46 +01:00
p . state . Workers . Client . Queue . Push ( & messages . FromClientAPI {
2023-09-12 14:00:35 +01:00
APObjectType : ap . ActivityFollow ,
APActivityType : ap . ActivityAccept ,
GTSModel : follow ,
2024-04-26 13:50:46 +01:00
Origin : follow . Account ,
Target : follow . TargetAccount ,
2023-09-12 14:00:35 +01:00
} )
}
return p . RelationshipGet ( ctx , requestingAccount , sourceAccountID )
}
// FollowRequestReject handles the rejection of a follow request from the sourceAccountID to the requestingAccount (the currently authorized account).
func ( p * Processor ) FollowRequestReject ( ctx context . Context , requestingAccount * gtsmodel . Account , sourceAccountID string ) ( * apimodel . Relationship , gtserror . WithCode ) {
followRequest , err := p . state . DB . GetFollowRequest ( ctx , sourceAccountID , requestingAccount . ID )
if err != nil {
return nil , gtserror . NewErrorNotFound ( err )
}
err = p . state . DB . RejectFollowRequest ( ctx , sourceAccountID , requestingAccount . ID )
if err != nil {
return nil , gtserror . NewErrorNotFound ( err )
}
if followRequest . Account != nil {
// Only enqueue work in the case we have a request creating account stored.
// NOTE: due to how GetFollowRequest works, the inverse shouldn't be possible.
2024-04-26 13:50:46 +01:00
p . state . Workers . Client . Queue . Push ( & messages . FromClientAPI {
2023-09-12 14:00:35 +01:00
APObjectType : ap . ActivityFollow ,
APActivityType : ap . ActivityReject ,
GTSModel : followRequest ,
2024-04-26 13:50:46 +01:00
Origin : followRequest . Account ,
Target : followRequest . TargetAccount ,
2023-09-12 14:00:35 +01:00
} )
}
return p . RelationshipGet ( ctx , requestingAccount , sourceAccountID )
}
// FollowRequestsGet fetches a list of the accounts that are follow requesting the given requestingAccount (the currently authorized account).
func ( p * Processor ) FollowRequestsGet ( ctx context . Context , requestingAccount * gtsmodel . Account , page * paging . Page ) ( * apimodel . PageableResponse , gtserror . WithCode ) {
// Fetch follow requests targeting the given requesting account model.
followRequests , err := p . state . DB . GetAccountFollowRequests ( ctx , requestingAccount . ID , page )
if err != nil && ! errors . Is ( err , db . ErrNoEntries ) {
return nil , gtserror . NewErrorInternalError ( err )
}
// Check for empty response.
count := len ( followRequests )
if count == 0 {
return paging . EmptyResponse ( ) , nil
}
// Get the lowest and highest
// ID values, used for paging.
lo := followRequests [ count - 1 ] . ID
hi := followRequests [ 0 ] . ID
// Func to fetch follow source at index.
getIdx := func ( i int ) * gtsmodel . Account {
return followRequests [ i ] . Account
}
// Get a filtered slice of public API account models.
items := p . c . GetVisibleAPIAccountsPaged ( ctx ,
requestingAccount ,
getIdx ,
count ,
)
return paging . PackageResponse ( paging . ResponseParams {
Items : items ,
Path : "/api/v1/follow_requests" ,
Next : page . Next ( lo , hi ) ,
Prev : page . Prev ( lo , hi ) ,
} ) , nil
}
2025-06-02 11:46:17 +02:00
// OutgoingFollowRequestsGet fetches a list of the accounts with a pending follow request originating from the given requestingAccount (the currently authorized account).
func ( p * Processor ) OutgoingFollowRequestsGet ( ctx context . Context , requestingAccount * gtsmodel . Account , page * paging . Page ) ( * apimodel . PageableResponse , gtserror . WithCode ) {
// Fetch follow requests originating from the given requesting account model.
followRequests , err := p . state . DB . GetAccountFollowRequesting ( ctx , requestingAccount . ID , page )
if err != nil && ! errors . Is ( err , db . ErrNoEntries ) {
return nil , gtserror . NewErrorInternalError ( err )
}
// Check for empty response.
count := len ( followRequests )
if count == 0 {
return paging . EmptyResponse ( ) , nil
}
// Get the lowest and highest
// ID values, used for paging.
lo := followRequests [ count - 1 ] . ID
hi := followRequests [ 0 ] . ID
// Func to fetch follow source at index.
getIdx := func ( i int ) * gtsmodel . Account {
return followRequests [ i ] . TargetAccount
}
// Get a filtered slice of public API account models.
items := p . c . GetVisibleAPIAccountsPaged ( ctx ,
requestingAccount ,
getIdx ,
count ,
)
return paging . PackageResponse ( paging . ResponseParams {
Items : items ,
Path : "/api/v1/follow_requests/outgoing" ,
Next : page . Next ( lo , hi ) ,
Prev : page . Prev ( lo , hi ) ,
} ) , nil
}