mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-11-26 01:03:31 -06:00
unfollows from gts => remote now working
This commit is contained in:
parent
6c7b7659f8
commit
3623205fd7
21 changed files with 368 additions and 47 deletions
|
|
@ -309,6 +309,57 @@ func (p *processor) AccountFollowersGet(authed *oauth.Auth, targetAccountID stri
|
|||
return accounts, nil
|
||||
}
|
||||
|
||||
func (p *processor) AccountFollowingGet(authed *oauth.Auth, targetAccountID string) ([]apimodel.Account, ErrorWithCode) {
|
||||
blocked, err := p.db.Blocked(authed.Account.ID, targetAccountID)
|
||||
if err != nil {
|
||||
return nil, NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
if blocked {
|
||||
return nil, NewErrorNotFound(fmt.Errorf("block exists between accounts"))
|
||||
}
|
||||
|
||||
following := []gtsmodel.Follow{}
|
||||
accounts := []apimodel.Account{}
|
||||
if err := p.db.GetFollowingByAccountID(targetAccountID, &following); err != nil {
|
||||
if _, ok := err.(db.ErrNoEntries); ok {
|
||||
return accounts, nil
|
||||
}
|
||||
return nil, NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
for _, f := range following {
|
||||
blocked, err := p.db.Blocked(authed.Account.ID, f.AccountID)
|
||||
if err != nil {
|
||||
return nil, NewErrorInternalError(err)
|
||||
}
|
||||
if blocked {
|
||||
continue
|
||||
}
|
||||
|
||||
a := >smodel.Account{}
|
||||
if err := p.db.GetByID(f.TargetAccountID, a); err != nil {
|
||||
if _, ok := err.(db.ErrNoEntries); ok {
|
||||
continue
|
||||
}
|
||||
return nil, NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
// derefence account fields in case we haven't done it already
|
||||
if err := p.dereferenceAccountFields(a, authed.Account.Username); err != nil {
|
||||
// don't bail if we can't fetch them, we'll try another time
|
||||
p.log.WithField("func", "AccountFollowingGet").Debugf("error dereferencing account fields: %s", err)
|
||||
}
|
||||
|
||||
account, err := p.tc.AccountToMastoPublic(a)
|
||||
if err != nil {
|
||||
return nil, NewErrorInternalError(err)
|
||||
}
|
||||
accounts = append(accounts, *account)
|
||||
}
|
||||
return accounts, nil
|
||||
}
|
||||
|
||||
func (p *processor) AccountRelationshipGet(authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, ErrorWithCode) {
|
||||
if authed == nil || authed.Account == nil {
|
||||
return nil, NewErrorForbidden(errors.New("not authed"))
|
||||
|
|
@ -410,3 +461,85 @@ func (p *processor) AccountFollowCreate(authed *oauth.Auth, form *apimodel.Accou
|
|||
// return whatever relationship results from this
|
||||
return p.AccountRelationshipGet(authed, form.TargetAccountID)
|
||||
}
|
||||
|
||||
func (p *processor) AccountFollowRemove(authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, ErrorWithCode) {
|
||||
// if there's a block between the accounts we shouldn't do anything
|
||||
blocked, err := p.db.Blocked(authed.Account.ID, targetAccountID)
|
||||
if err != nil {
|
||||
return nil, NewErrorInternalError(err)
|
||||
}
|
||||
if blocked {
|
||||
return nil, NewErrorNotFound(fmt.Errorf("AccountFollowRemove: block exists between accounts"))
|
||||
}
|
||||
|
||||
// make sure the target account actually exists in our db
|
||||
targetAcct := >smodel.Account{}
|
||||
if err := p.db.GetByID(targetAccountID, targetAcct); err != nil {
|
||||
if _, ok := err.(db.ErrNoEntries); ok {
|
||||
return nil, NewErrorNotFound(fmt.Errorf("AccountFollowRemove: account %s not found in the db: %s", targetAccountID, err))
|
||||
}
|
||||
}
|
||||
|
||||
// check if a follow request exists, and remove it if it does (storing the URI for later)
|
||||
var frChanged bool
|
||||
var frURI string
|
||||
fr := >smodel.FollowRequest{}
|
||||
if err := p.db.GetWhere([]db.Where{
|
||||
{Key: "account_id", Value: authed.Account.ID},
|
||||
{Key: "target_account_id", Value: targetAccountID},
|
||||
}, fr); err == nil {
|
||||
frURI = fr.URI
|
||||
if err := p.db.DeleteByID(fr.ID, fr); err != nil {
|
||||
return nil, NewErrorInternalError(fmt.Errorf("AccountFollowRemove: error removing follow request from db: %s", err))
|
||||
}
|
||||
frChanged = true
|
||||
}
|
||||
|
||||
// now do the same thing for any existing follow
|
||||
var fChanged bool
|
||||
var fURI string
|
||||
f := >smodel.Follow{}
|
||||
if err := p.db.GetWhere([]db.Where{
|
||||
{Key: "account_id", Value: authed.Account.ID},
|
||||
{Key: "target_account_id", Value: targetAccountID},
|
||||
}, f); err == nil {
|
||||
fURI = f.URI
|
||||
if err := p.db.DeleteByID(f.ID, f); err != nil {
|
||||
return nil, NewErrorInternalError(fmt.Errorf("AccountFollowRemove: error removing follow from db: %s", err))
|
||||
}
|
||||
fChanged = true
|
||||
}
|
||||
|
||||
// follow request status changed so send the UNDO activity to the channel for async processing
|
||||
if frChanged {
|
||||
p.fromClientAPI <- gtsmodel.FromClientAPI{
|
||||
APObjectType: gtsmodel.ActivityStreamsFollow,
|
||||
APActivityType: gtsmodel.ActivityStreamsUndo,
|
||||
GTSModel: >smodel.Follow{
|
||||
AccountID: authed.Account.ID,
|
||||
TargetAccountID: targetAccountID,
|
||||
URI: frURI,
|
||||
},
|
||||
OriginAccount: authed.Account,
|
||||
TargetAccount: targetAcct,
|
||||
}
|
||||
}
|
||||
|
||||
// follow status changed so send the UNDO activity to the channel for async processing
|
||||
if fChanged {
|
||||
p.fromClientAPI <- gtsmodel.FromClientAPI{
|
||||
APObjectType: gtsmodel.ActivityStreamsFollow,
|
||||
APActivityType: gtsmodel.ActivityStreamsUndo,
|
||||
GTSModel: >smodel.Follow{
|
||||
AccountID: authed.Account.ID,
|
||||
TargetAccountID: targetAccountID,
|
||||
URI: fURI,
|
||||
},
|
||||
OriginAccount: authed.Account,
|
||||
TargetAccount: targetAcct,
|
||||
}
|
||||
}
|
||||
|
||||
// return whatever relationship results from all this
|
||||
return p.AccountRelationshipGet(authed, targetAccountID)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ func (p *processor) authenticateAndDereferenceFediRequest(username string, r *ht
|
|||
// we might already have an entry for this account so check that first
|
||||
requestingAccount := >smodel.Account{}
|
||||
|
||||
err = p.db.GetWhere("uri", requestingAccountURI.String(), requestingAccount)
|
||||
err = p.db.GetWhere([]db.Where{{Key: "uri", Value: requestingAccountURI.String()}}, requestingAccount)
|
||||
if err == nil {
|
||||
// we do have it yay, return it
|
||||
return requestingAccount, nil
|
||||
|
|
|
|||
|
|
@ -71,6 +71,17 @@ func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error
|
|||
return errors.New("accept was not parseable as *gtsmodel.Follow")
|
||||
}
|
||||
return p.federateAcceptFollowRequest(follow)
|
||||
case gtsmodel.ActivityStreamsUndo:
|
||||
// UNDO
|
||||
switch clientMsg.APObjectType {
|
||||
// UNDO FOLLOW
|
||||
case gtsmodel.ActivityStreamsFollow:
|
||||
follow, ok := clientMsg.GTSModel.(*gtsmodel.Follow)
|
||||
if !ok {
|
||||
return errors.New("undo was not parseable as *gtsmodel.Follow")
|
||||
}
|
||||
return p.federateUnfollow(follow, clientMsg.OriginAccount, clientMsg.TargetAccount)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -117,11 +128,46 @@ func (p *processor) federateFollow(follow *gtsmodel.Follow, originAccount *gtsmo
|
|||
return err
|
||||
}
|
||||
|
||||
func (p *processor) federateUnfollow(follow *gtsmodel.Follow, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error {
|
||||
// recreate the follow
|
||||
asFollow, err := p.tc.FollowToAS(follow, originAccount, targetAccount)
|
||||
if err != nil {
|
||||
return fmt.Errorf("federateUnfollow: error converting follow to as format: %s", err)
|
||||
}
|
||||
|
||||
targetAccountURI, err := url.Parse(targetAccount.URI)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing uri %s: %s", targetAccount.URI, err)
|
||||
}
|
||||
|
||||
// create an Undo and set the appropriate actor on it
|
||||
undo := streams.NewActivityStreamsUndo()
|
||||
undo.SetActivityStreamsActor(asFollow.GetActivityStreamsActor())
|
||||
|
||||
// Set the recreated follow as the 'object' property.
|
||||
undoObject := streams.NewActivityStreamsObjectProperty()
|
||||
undoObject.AppendActivityStreamsFollow(asFollow)
|
||||
undo.SetActivityStreamsObject(undoObject)
|
||||
|
||||
// Set the To of the undo as the target of the recreated follow
|
||||
undoTo := streams.NewActivityStreamsToProperty()
|
||||
undoTo.AppendIRI(targetAccountURI)
|
||||
undo.SetActivityStreamsTo(undoTo)
|
||||
|
||||
outboxIRI, err := url.Parse(originAccount.OutboxURI)
|
||||
if err != nil {
|
||||
return fmt.Errorf("federateUnfollow: error parsing outboxURI %s: %s", originAccount.OutboxURI, err)
|
||||
}
|
||||
|
||||
// send off the Undo
|
||||
_, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, undo)
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *processor) federateAcceptFollowRequest(follow *gtsmodel.Follow) error {
|
||||
|
||||
// TODO: tidy up this whole function -- move most of the logic for the conversion to the type converter because this is just a mess! Shame on me!
|
||||
|
||||
|
||||
followAccepter := >smodel.Account{}
|
||||
if err := p.db.GetByID(follow.TargetAccountID, followAccepter); err != nil {
|
||||
return fmt.Errorf("error federating follow accept: %s", err)
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ func (p *processor) dereferenceStatusFields(status *gtsmodel.Status) error {
|
|||
|
||||
// it might have been processed elsewhere so check first if it's already in the database or not
|
||||
maybeAttachment := >smodel.MediaAttachment{}
|
||||
err := p.db.GetWhere("remote_url", a.RemoteURL, maybeAttachment)
|
||||
err := p.db.GetWhere([]db.Where{{Key: "remote_url", Value: a.RemoteURL}}, maybeAttachment)
|
||||
if err == nil {
|
||||
// we already have it in the db, dereferenced, no need to do it again
|
||||
l.Debugf("attachment already exists with id %s", maybeAttachment.ID)
|
||||
|
|
@ -206,7 +206,7 @@ func (p *processor) dereferenceStatusFields(status *gtsmodel.Status) error {
|
|||
m.OriginAccountURI = status.GTSAccount.URI
|
||||
|
||||
targetAccount := >smodel.Account{}
|
||||
if err := p.db.GetWhere("uri", uri.String(), targetAccount); err != nil {
|
||||
if err := p.db.GetWhere([]db.Where{{Key: "uri", Value: uri.String()}}, targetAccount); err != nil {
|
||||
// proper error
|
||||
if _, ok := err.(db.ErrNoEntries); !ok {
|
||||
return fmt.Errorf("db error checking for account with uri %s", uri.String())
|
||||
|
|
|
|||
|
|
@ -22,12 +22,13 @@ import (
|
|||
"fmt"
|
||||
|
||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
)
|
||||
|
||||
func (p *processor) InstanceGet(domain string) (*apimodel.Instance, ErrorWithCode) {
|
||||
i := >smodel.Instance{}
|
||||
if err := p.db.GetWhere("domain", domain, i); err != nil {
|
||||
if err := p.db.GetWhere([]db.Where{{Key: "domain", Value: domain}}, i); err != nil {
|
||||
return nil, NewErrorInternalError(fmt.Errorf("db error fetching instance %s: %s", p.config.Host, err))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -73,10 +73,14 @@ type Processor interface {
|
|||
AccountStatusesGet(authed *oauth.Auth, targetAccountID string, limit int, excludeReplies bool, maxID string, pinned bool, mediaOnly bool) ([]apimodel.Status, ErrorWithCode)
|
||||
// AccountFollowersGet fetches a list of the target account's followers.
|
||||
AccountFollowersGet(authed *oauth.Auth, targetAccountID string) ([]apimodel.Account, ErrorWithCode)
|
||||
// AccountFollowingGet fetches a list of the accounts that target account is following.
|
||||
AccountFollowingGet(authed *oauth.Auth, targetAccountID string) ([]apimodel.Account, ErrorWithCode)
|
||||
// AccountRelationshipGet returns a relationship model describing the relationship of the targetAccount to the Authed account.
|
||||
AccountRelationshipGet(authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, ErrorWithCode)
|
||||
// AccountFollowCreate handles a follow request to an account, either remote or local.
|
||||
AccountFollowCreate(authed *oauth.Auth, form *apimodel.AccountFollowRequest) (*apimodel.Relationship, ErrorWithCode)
|
||||
// AccountFollowRemove handles the removal of a follow/follow request to an account, either remote or local.
|
||||
AccountFollowRemove(authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, ErrorWithCode)
|
||||
|
||||
// AdminEmojiCreate handles the creation of a new instance emoji by an admin, using the given form.
|
||||
AdminEmojiCreate(authed *oauth.Auth, form *apimodel.EmojiCreateRequest) (*apimodel.Emoji, error)
|
||||
|
|
@ -204,15 +208,11 @@ func (p *processor) Start() error {
|
|||
DistLoop:
|
||||
for {
|
||||
select {
|
||||
// case clientMsg := <-p.toClientAPI:
|
||||
// p.log.Infof("received message TO client API: %+v", clientMsg)
|
||||
case clientMsg := <-p.fromClientAPI:
|
||||
p.log.Infof("received message FROM client API: %+v", clientMsg)
|
||||
if err := p.processFromClientAPI(clientMsg); err != nil {
|
||||
p.log.Error(err)
|
||||
}
|
||||
// case federatorMsg := <-p.toFederator:
|
||||
// p.log.Infof("received message TO federator: %+v", federatorMsg)
|
||||
case federatorMsg := <-p.fromFederator:
|
||||
p.log.Infof("received message FROM federator: %+v", federatorMsg)
|
||||
if err := p.processFromFederator(federatorMsg); err != nil {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue