mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-11-22 07:07:29 -06:00
lots of stufffffffffffffffff
This commit is contained in:
parent
dc06e71b76
commit
8832784778
26 changed files with 721 additions and 88 deletions
|
|
@ -78,6 +78,15 @@ func (p *processor) AccountGet(authed *oauth.Auth, targetAccountID string) (*api
|
|||
return nil, fmt.Errorf("db error: %s", err)
|
||||
}
|
||||
|
||||
// lazily dereference things on the account if it hasn't been done yet
|
||||
var requestingUsername string
|
||||
if authed.Account != nil {
|
||||
requestingUsername = authed.Account.Username
|
||||
}
|
||||
if err := p.dereferenceAccountFields(targetAccount, requestingUsername); err != nil {
|
||||
p.log.WithField("func", "AccountGet").Debugf("dereferencing account: %s", err)
|
||||
}
|
||||
|
||||
var mastoAccount *apimodel.Account
|
||||
var err error
|
||||
if authed.Account != nil && targetAccount.ID == authed.Account.ID {
|
||||
|
|
@ -285,6 +294,12 @@ func (p *processor) AccountFollowersGet(authed *oauth.Auth, targetAccountID stri
|
|||
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", "AccountFollowersGet").Debugf("error dereferencing account fields: %s", err)
|
||||
}
|
||||
|
||||
account, err := p.tc.AccountToMastoPublic(a)
|
||||
if err != nil {
|
||||
return nil, NewErrorInternalError(err)
|
||||
|
|
@ -293,3 +308,21 @@ func (p *processor) AccountFollowersGet(authed *oauth.Auth, targetAccountID stri
|
|||
}
|
||||
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"))
|
||||
}
|
||||
|
||||
gtsR, err := p.db.GetRelationship(authed.Account.ID, targetAccountID)
|
||||
if err != nil {
|
||||
return nil, NewErrorInternalError(fmt.Errorf("error getting relationship: %s", err))
|
||||
}
|
||||
|
||||
r, err := p.tc.RelationshipToMasto(gtsR)
|
||||
if err != nil {
|
||||
return nil, NewErrorInternalError(fmt.Errorf("error converting relationship: %s", err))
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,30 +19,48 @@
|
|||
package message
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/go-fed/activity/pub"
|
||||
"github.com/go-fed/activity/streams"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
)
|
||||
|
||||
func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error {
|
||||
switch clientMsg.APObjectType {
|
||||
case gtsmodel.ActivityStreamsNote:
|
||||
status, ok := clientMsg.GTSModel.(*gtsmodel.Status)
|
||||
switch clientMsg.APActivityType {
|
||||
case gtsmodel.ActivityStreamsCreate:
|
||||
// CREATE
|
||||
switch clientMsg.APObjectType {
|
||||
case gtsmodel.ActivityStreamsNote:
|
||||
// CREATE NOTE
|
||||
status, ok := clientMsg.GTSModel.(*gtsmodel.Status)
|
||||
if !ok {
|
||||
return errors.New("note was not parseable as *gtsmodel.Status")
|
||||
}
|
||||
|
||||
if err := p.notifyStatus(status); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if status.VisibilityAdvanced.Federated {
|
||||
return p.federateStatus(status)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
case gtsmodel.ActivityStreamsUpdate:
|
||||
// UPDATE
|
||||
case gtsmodel.ActivityStreamsAccept:
|
||||
// ACCEPT
|
||||
follow, ok := clientMsg.GTSModel.(*gtsmodel.Follow)
|
||||
if !ok {
|
||||
return errors.New("note was not parseable as *gtsmodel.Status")
|
||||
return errors.New("accept was not parseable as *gtsmodel.Follow")
|
||||
}
|
||||
|
||||
if err := p.notifyStatus(status); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if status.VisibilityAdvanced.Federated {
|
||||
return p.federateStatus(status)
|
||||
}
|
||||
return nil
|
||||
return p.federateAcceptFollowRequest(follow)
|
||||
}
|
||||
return fmt.Errorf("message type unprocessable: %+v", clientMsg)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *processor) federateStatus(status *gtsmodel.Status) error {
|
||||
|
|
@ -71,3 +89,74 @@ func (p *processor) federateStatus(status *gtsmodel.Status) error {
|
|||
// _, err = p.federator.FederatingActor().Send(context.Background(), outboxURI, note)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *processor) federateAcceptFollowRequest(follow *gtsmodel.Follow) error {
|
||||
|
||||
followAccepter := >smodel.Account{}
|
||||
if err := p.db.GetByID(follow.TargetAccountID, followAccepter); err != nil {
|
||||
return fmt.Errorf("error federating follow accept: %s", err)
|
||||
}
|
||||
followAccepterIRI, err := url.Parse(followAccepter.URI)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing URL: %s", err)
|
||||
}
|
||||
followAccepterOutboxIRI, err := url.Parse(followAccepter.OutboxURI)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing URL: %s", err)
|
||||
}
|
||||
me := streams.NewActivityStreamsActorProperty()
|
||||
me.AppendIRI(followAccepterIRI)
|
||||
|
||||
followRequester := >smodel.Account{}
|
||||
if err := p.db.GetByID(follow.AccountID, followRequester); err != nil {
|
||||
return fmt.Errorf("error federating follow accept: %s", err)
|
||||
}
|
||||
requesterIRI, err := url.Parse(followRequester.URI)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing URL: %s", err)
|
||||
}
|
||||
them := streams.NewActivityStreamsActorProperty()
|
||||
them.AppendIRI(requesterIRI)
|
||||
|
||||
// prepare the follow
|
||||
ASFollow := streams.NewActivityStreamsFollow()
|
||||
// set the follow requester as the actor
|
||||
ASFollow.SetActivityStreamsActor(them)
|
||||
// set the ID from the follow
|
||||
ASFollowURI, err := url.Parse(follow.URI)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing URL: %s", err)
|
||||
}
|
||||
ASFollowIDProp := streams.NewJSONLDIdProperty()
|
||||
ASFollowIDProp.SetIRI(ASFollowURI)
|
||||
ASFollow.SetJSONLDId(ASFollowIDProp)
|
||||
|
||||
// set the object as the accepter URI
|
||||
ASFollowObjectProp := streams.NewActivityStreamsObjectProperty()
|
||||
ASFollowObjectProp.AppendIRI(followAccepterIRI)
|
||||
|
||||
// Prepare the response.
|
||||
ASAccept := streams.NewActivityStreamsAccept()
|
||||
// Set us as the 'actor'.
|
||||
ASAccept.SetActivityStreamsActor(me)
|
||||
|
||||
// Set the Follow as the 'object' property.
|
||||
ASAcceptObject := streams.NewActivityStreamsObjectProperty()
|
||||
ASAcceptObject.AppendActivityStreamsFollow(ASFollow)
|
||||
ASAccept.SetActivityStreamsObject(ASAcceptObject)
|
||||
|
||||
// Add all actors on the original Follow to the 'to' property.
|
||||
ASAcceptTo := streams.NewActivityStreamsToProperty()
|
||||
followActors := ASFollow.GetActivityStreamsActor()
|
||||
for iter := followActors.Begin(); iter != followActors.End(); iter = iter.Next() {
|
||||
id, err := pub.ToId(iter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ASAcceptTo.AppendIRI(id)
|
||||
}
|
||||
ASAccept.SetActivityStreamsTo(ASAcceptTo)
|
||||
|
||||
_, err = p.federator.FederatingActor().Send(context.Background(), followAccepterOutboxIRI, ASAccept)
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,24 +38,60 @@ func (p *processor) processFromFederator(federatorMsg gtsmodel.FromFederator) er
|
|||
|
||||
l.Debug("entering function PROCESS FROM FEDERATOR")
|
||||
|
||||
switch federatorMsg.APObjectType {
|
||||
case gtsmodel.ActivityStreamsNote:
|
||||
switch federatorMsg.APActivityType {
|
||||
case gtsmodel.ActivityStreamsCreate:
|
||||
// CREATE
|
||||
switch federatorMsg.APObjectType {
|
||||
case gtsmodel.ActivityStreamsNote:
|
||||
// CREATE A STATUS
|
||||
incomingStatus, ok := federatorMsg.GTSModel.(*gtsmodel.Status)
|
||||
if !ok {
|
||||
return errors.New("note was not parseable as *gtsmodel.Status")
|
||||
}
|
||||
|
||||
incomingStatus, ok := federatorMsg.GTSModel.(*gtsmodel.Status)
|
||||
if !ok {
|
||||
return errors.New("note was not parseable as *gtsmodel.Status")
|
||||
}
|
||||
l.Debug("will now derefence incoming status")
|
||||
if err := p.dereferenceStatusFields(incomingStatus); err != nil {
|
||||
return fmt.Errorf("error dereferencing status from federator: %s", err)
|
||||
}
|
||||
if err := p.db.UpdateByID(incomingStatus.ID, incomingStatus); err != nil {
|
||||
return fmt.Errorf("error updating dereferenced status in the db: %s", err)
|
||||
}
|
||||
|
||||
l.Debug("will now derefence incoming status")
|
||||
if err := p.dereferenceStatusFields(incomingStatus); err != nil {
|
||||
return fmt.Errorf("error dereferencing status from federator: %s", err)
|
||||
}
|
||||
if err := p.db.UpdateByID(incomingStatus.ID, incomingStatus); err != nil {
|
||||
return fmt.Errorf("error updating dereferenced status in the db: %s", err)
|
||||
}
|
||||
if err := p.notifyStatus(incomingStatus); err != nil {
|
||||
return err
|
||||
}
|
||||
case gtsmodel.ActivityStreamsProfile:
|
||||
// CREATE AN ACCOUNT
|
||||
incomingAccount, ok := federatorMsg.GTSModel.(*gtsmodel.Account)
|
||||
if !ok {
|
||||
return errors.New("profile was not parseable as *gtsmodel.Account")
|
||||
}
|
||||
|
||||
if err := p.notifyStatus(incomingStatus); err != nil {
|
||||
return err
|
||||
l.Debug("will now derefence incoming account")
|
||||
if err := p.dereferenceAccountFields(incomingAccount, ""); err != nil {
|
||||
return fmt.Errorf("error dereferencing account from federator: %s", err)
|
||||
}
|
||||
if err := p.db.UpdateByID(incomingAccount.ID, incomingAccount); err != nil {
|
||||
return fmt.Errorf("error updating dereferenced account in the db: %s", err)
|
||||
}
|
||||
}
|
||||
case gtsmodel.ActivityStreamsUpdate:
|
||||
// UPDATE
|
||||
switch federatorMsg.APObjectType {
|
||||
case gtsmodel.ActivityStreamsProfile:
|
||||
// UPDATE AN ACCOUNT
|
||||
incomingAccount, ok := federatorMsg.GTSModel.(*gtsmodel.Account)
|
||||
if !ok {
|
||||
return errors.New("profile was not parseable as *gtsmodel.Account")
|
||||
}
|
||||
|
||||
l.Debug("will now derefence incoming account")
|
||||
if err := p.dereferenceAccountFields(incomingAccount, ""); err != nil {
|
||||
return fmt.Errorf("error dereferencing account from federator: %s", err)
|
||||
}
|
||||
if err := p.db.UpdateByID(incomingAccount.ID, incomingAccount); err != nil {
|
||||
return fmt.Errorf("error updating dereferenced account in the db: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -206,3 +242,27 @@ func (p *processor) dereferenceStatusFields(status *gtsmodel.Status) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *processor) dereferenceAccountFields(account *gtsmodel.Account, requestingUsername string) error {
|
||||
l := p.log.WithFields(logrus.Fields{
|
||||
"func": "dereferenceAccountFields",
|
||||
"requestingUsername": requestingUsername,
|
||||
})
|
||||
|
||||
t, err := p.federator.GetTransportForUser(requestingUsername)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting transport for user: %s", err)
|
||||
}
|
||||
|
||||
// fetch the header and avatar
|
||||
if err := p.fetchHeaderAndAviForAccount(account, t); err != nil {
|
||||
// if this doesn't work, just skip it -- we can do it later
|
||||
l.Debugf("error fetching header/avi for account: %s", err)
|
||||
}
|
||||
|
||||
if err := p.db.UpdateByID(account.ID, account); err != nil {
|
||||
return fmt.Errorf("error updating account in database: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,11 +48,28 @@ func (p *processor) FollowRequestsGet(auth *oauth.Auth) ([]apimodel.Account, Err
|
|||
return accts, nil
|
||||
}
|
||||
|
||||
func (p *processor) FollowRequestAccept(auth *oauth.Auth, accountID string) ErrorWithCode {
|
||||
if err := p.db.AcceptFollowRequest(accountID, auth.Account.ID); err != nil {
|
||||
return NewErrorNotFound(err)
|
||||
func (p *processor) FollowRequestAccept(auth *oauth.Auth, accountID string) (*apimodel.Relationship, ErrorWithCode) {
|
||||
follow, err := p.db.AcceptFollowRequest(accountID, auth.Account.ID)
|
||||
if err != nil {
|
||||
return nil, NewErrorNotFound(err)
|
||||
}
|
||||
return nil
|
||||
|
||||
p.fromClientAPI <- gtsmodel.FromClientAPI{
|
||||
APActivityType: gtsmodel.ActivityStreamsAccept,
|
||||
GTSModel: follow,
|
||||
}
|
||||
|
||||
gtsR, err := p.db.GetRelationship(auth.Account.ID, accountID)
|
||||
if err != nil {
|
||||
return nil, NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
r, err := p.tc.RelationshipToMasto(gtsR)
|
||||
if err != nil {
|
||||
return nil, NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (p *processor) FollowRequestDeny(auth *oauth.Auth) ErrorWithCode {
|
||||
|
|
|
|||
|
|
@ -73,6 +73,8 @@ type Processor interface {
|
|||
AccountStatusesGet(authed *oauth.Auth, targetAccountID string, limit int, excludeReplies bool, maxID string, pinned bool, mediaOnly bool) ([]apimodel.Status, ErrorWithCode)
|
||||
// AccountFollowersGet
|
||||
AccountFollowersGet(authed *oauth.Auth, targetAccountID string) ([]apimodel.Account, ErrorWithCode)
|
||||
// AccountRelationshipGet
|
||||
AccountRelationshipGet(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)
|
||||
|
|
@ -86,7 +88,7 @@ type Processor interface {
|
|||
// FollowRequestsGet handles the getting of the authed account's incoming follow requests
|
||||
FollowRequestsGet(auth *oauth.Auth) ([]apimodel.Account, ErrorWithCode)
|
||||
// FollowRequestAccept handles the acceptance of a follow request from the given account ID
|
||||
FollowRequestAccept(auth *oauth.Auth, accountID string) ErrorWithCode
|
||||
FollowRequestAccept(auth *oauth.Auth, accountID string) (*apimodel.Relationship, ErrorWithCode)
|
||||
|
||||
// InstanceGet retrieves instance information for serving at api/v1/instance
|
||||
InstanceGet(domain string) (*apimodel.Instance, ErrorWithCode)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import (
|
|||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/media"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/transport"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
)
|
||||
|
||||
|
|
@ -280,7 +281,7 @@ func (p *processor) updateAccountAvatar(avatar *multipart.FileHeader, accountID
|
|||
}
|
||||
|
||||
// do the setting
|
||||
avatarInfo, err := p.mediaHandler.ProcessHeaderOrAvatar(buf.Bytes(), accountID, media.Avatar)
|
||||
avatarInfo, err := p.mediaHandler.ProcessHeaderOrAvatar(buf.Bytes(), accountID, media.Avatar, "")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error processing avatar: %s", err)
|
||||
}
|
||||
|
|
@ -313,10 +314,42 @@ func (p *processor) updateAccountHeader(header *multipart.FileHeader, accountID
|
|||
}
|
||||
|
||||
// do the setting
|
||||
headerInfo, err := p.mediaHandler.ProcessHeaderOrAvatar(buf.Bytes(), accountID, media.Header)
|
||||
headerInfo, err := p.mediaHandler.ProcessHeaderOrAvatar(buf.Bytes(), accountID, media.Header, "")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error processing header: %s", err)
|
||||
}
|
||||
|
||||
return headerInfo, f.Close()
|
||||
}
|
||||
|
||||
// fetchHeaderAndAviForAccount fetches the header and avatar for a remote account, using a transport
|
||||
// on behalf of requestingUsername.
|
||||
//
|
||||
// targetAccount's AvatarMediaAttachmentID and HeaderMediaAttachmentID will be updated as necessary.
|
||||
//
|
||||
// SIDE EFFECTS: remote header and avatar will be stored in local storage, and the database will be updated
|
||||
// to reflect the creation of these new attachments.
|
||||
func (p *processor) fetchHeaderAndAviForAccount(targetAccount *gtsmodel.Account, t transport.Transport) error {
|
||||
if targetAccount.AvatarRemoteURL != "" && targetAccount.AvatarMediaAttachmentID == "" {
|
||||
a, err := p.mediaHandler.ProcessRemoteHeaderOrAvatar(t, >smodel.MediaAttachment{
|
||||
RemoteURL: targetAccount.AvatarRemoteURL,
|
||||
Avatar: true,
|
||||
}, targetAccount.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error processing avatar for user: %s", err)
|
||||
}
|
||||
targetAccount.AvatarMediaAttachmentID = a.ID
|
||||
}
|
||||
|
||||
if targetAccount.HeaderRemoteURL != "" && targetAccount.HeaderMediaAttachmentID == "" {
|
||||
a, err := p.mediaHandler.ProcessRemoteHeaderOrAvatar(t, >smodel.MediaAttachment{
|
||||
RemoteURL: targetAccount.HeaderRemoteURL,
|
||||
Header: true,
|
||||
}, targetAccount.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error processing header for user: %s", err)
|
||||
}
|
||||
targetAccount.HeaderMediaAttachmentID = a.ID
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue