mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-11-28 20:43:32 -06:00
Refactor/tidy (#261)
* tidy up streaming * cut down code duplication * test get followers/following * test streaming processor * fix some test models * add TimeMustParse * fix uri / url typo * make trace logging less verbose * make logging more consistent * disable quote on logging * remove context.Background * remove many extraneous mastodon references * regenerate swagger * don't log query on no rows result * log latency first for easier reading
This commit is contained in:
parent
9ce4234b9f
commit
e04b187702
126 changed files with 1192 additions and 955 deletions
|
|
@ -20,11 +20,9 @@ package federatingdb
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-fed/activity/streams"
|
||||
"github.com/go-fed/activity/streams/vocab"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/ap"
|
||||
|
|
@ -37,43 +35,29 @@ import (
|
|||
func (f *federatingDB) Accept(ctx context.Context, accept vocab.ActivityStreamsAccept) error {
|
||||
l := f.log.WithFields(
|
||||
logrus.Fields{
|
||||
"func": "Accept",
|
||||
"asType": accept.GetTypeName(),
|
||||
"func": "Accept",
|
||||
},
|
||||
)
|
||||
m, err := streams.Serialize(accept)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l.Debugf("received ACCEPT asType %s", string(b))
|
||||
|
||||
targetAcctI := ctx.Value(util.APAccount)
|
||||
if targetAcctI == nil {
|
||||
// If the target account wasn't set on the context, that means this request didn't pass through the
|
||||
// API, but came from inside GtS as the result of another activity on this instance. That being so,
|
||||
if l.Level >= logrus.DebugLevel {
|
||||
i, err := marshalItem(accept)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l = l.WithField("accept", i)
|
||||
l.Debug("entering Accept")
|
||||
}
|
||||
|
||||
targetAcct, fromFederatorChan, err := extractFromCtx(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if targetAcct == nil || fromFederatorChan == nil {
|
||||
// If the target account or federator channel wasn't set on the context, that means this request didn't pass
|
||||
// through the API, but came from inside GtS as the result of another activity on this instance. That being so,
|
||||
// we can safely just ignore this activity, since we know we've already processed it elsewhere.
|
||||
return nil
|
||||
}
|
||||
targetAcct, ok := targetAcctI.(*gtsmodel.Account)
|
||||
if !ok {
|
||||
l.Error("ACCEPT: target account was set on context but couldn't be parsed")
|
||||
return nil
|
||||
}
|
||||
|
||||
fromFederatorChanI := ctx.Value(util.APFromFederatorChanKey)
|
||||
if fromFederatorChanI == nil {
|
||||
l.Error("ACCEPT: from federator channel wasn't set on context")
|
||||
return nil
|
||||
}
|
||||
fromFederatorChan, ok := fromFederatorChanI.(chan messages.FromFederator)
|
||||
if !ok {
|
||||
l.Error("ACCEPT: from federator channel was set on context but couldn't be parsed")
|
||||
return nil
|
||||
}
|
||||
|
||||
acceptObject := accept.GetActivityStreamsObject()
|
||||
if acceptObject == nil {
|
||||
|
|
|
|||
|
|
@ -20,16 +20,12 @@ package federatingdb
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-fed/activity/streams"
|
||||
"github.com/go-fed/activity/streams/vocab"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/ap"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/messages"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
)
|
||||
|
||||
func (f *federatingDB) Announce(ctx context.Context, announce vocab.ActivityStreamsAnnounce) error {
|
||||
|
|
@ -38,40 +34,26 @@ func (f *federatingDB) Announce(ctx context.Context, announce vocab.ActivityStre
|
|||
"func": "Announce",
|
||||
},
|
||||
)
|
||||
m, err := streams.Serialize(announce)
|
||||
|
||||
if l.Level >= logrus.DebugLevel {
|
||||
i, err := marshalItem(announce)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l = l.WithField("announce", i)
|
||||
l.Debug("entering Announce")
|
||||
}
|
||||
|
||||
targetAcct, fromFederatorChan, err := extractFromCtx(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
l.Debugf("received ANNOUNCE %s", string(b))
|
||||
|
||||
targetAcctI := ctx.Value(util.APAccount)
|
||||
if targetAcctI == nil {
|
||||
// If the target account wasn't set on the context, that means this request didn't pass through the
|
||||
// API, but came from inside GtS as the result of another activity on this instance. That being so,
|
||||
if targetAcct == nil || fromFederatorChan == nil {
|
||||
// If the target account or federator channel wasn't set on the context, that means this request didn't pass
|
||||
// through the API, but came from inside GtS as the result of another activity on this instance. That being so,
|
||||
// we can safely just ignore this activity, since we know we've already processed it elsewhere.
|
||||
return nil
|
||||
}
|
||||
targetAcct, ok := targetAcctI.(*gtsmodel.Account)
|
||||
if !ok {
|
||||
l.Error("ANNOUNCE: target account was set on context but couldn't be parsed")
|
||||
return nil
|
||||
}
|
||||
|
||||
fromFederatorChanI := ctx.Value(util.APFromFederatorChanKey)
|
||||
if fromFederatorChanI == nil {
|
||||
l.Error("ANNOUNCE: from federator channel wasn't set on context")
|
||||
return nil
|
||||
}
|
||||
fromFederatorChan, ok := fromFederatorChanI.(chan messages.FromFederator)
|
||||
if !ok {
|
||||
l.Error("ANNOUNCE: from federator channel was set on context but couldn't be parsed")
|
||||
return nil
|
||||
}
|
||||
|
||||
boost, isNew, err := f.typeConverter.ASAnnounceToStatus(ctx, announce)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -20,19 +20,15 @@ package federatingdb
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-fed/activity/streams"
|
||||
"github.com/go-fed/activity/streams/vocab"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/ap"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/id"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/messages"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
)
|
||||
|
||||
// Create adds a new entry to the database which must be able to be
|
||||
|
|
@ -50,44 +46,29 @@ import (
|
|||
func (f *federatingDB) Create(ctx context.Context, asType vocab.Type) error {
|
||||
l := f.log.WithFields(
|
||||
logrus.Fields{
|
||||
"func": "Create",
|
||||
"asType": asType.GetTypeName(),
|
||||
"func": "Create",
|
||||
},
|
||||
)
|
||||
m, err := streams.Serialize(asType)
|
||||
|
||||
if l.Level >= logrus.DebugLevel {
|
||||
i, err := marshalItem(asType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l = l.WithField("create", i)
|
||||
l.Debug("entering Create")
|
||||
}
|
||||
|
||||
targetAcct, fromFederatorChan, err := extractFromCtx(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
l.Debugf("received CREATE asType %s", string(b))
|
||||
|
||||
targetAcctI := ctx.Value(util.APAccount)
|
||||
if targetAcctI == nil {
|
||||
// If the target account wasn't set on the context, that means this request didn't pass through the
|
||||
// API, but came from inside GtS as the result of another activity on this instance. That being so,
|
||||
if targetAcct == nil || fromFederatorChan == nil {
|
||||
// If the target account or federator channel wasn't set on the context, that means this request didn't pass
|
||||
// through the API, but came from inside GtS as the result of another activity on this instance. That being so,
|
||||
// we can safely just ignore this activity, since we know we've already processed it elsewhere.
|
||||
return nil
|
||||
}
|
||||
targetAcct, ok := targetAcctI.(*gtsmodel.Account)
|
||||
if !ok {
|
||||
l.Error("CREATE: target account was set on context but couldn't be parsed")
|
||||
return nil
|
||||
}
|
||||
|
||||
fromFederatorChanI := ctx.Value(util.APFromFederatorChanKey)
|
||||
if fromFederatorChanI == nil {
|
||||
l.Error("CREATE: from federator channel wasn't set on context")
|
||||
return nil
|
||||
}
|
||||
fromFederatorChan, ok := fromFederatorChanI.(chan messages.FromFederator)
|
||||
if !ok {
|
||||
l.Error("CREATE: from federator channel was set on context but couldn't be parsed")
|
||||
return nil
|
||||
}
|
||||
|
||||
switch asType.GetTypeName() {
|
||||
case ap.ActivityCreate:
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ import (
|
|||
"github.com/superseriousbusiness/gotosocial/internal/ap"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/messages"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
)
|
||||
|
||||
// Delete removes the entry with the given id.
|
||||
|
|
@ -40,34 +39,21 @@ func (f *federatingDB) Delete(ctx context.Context, id *url.URL) error {
|
|||
l := f.log.WithFields(
|
||||
logrus.Fields{
|
||||
"func": "Delete",
|
||||
"id": id.String(),
|
||||
"id": id,
|
||||
},
|
||||
)
|
||||
l.Debugf("received DELETE id %s", id.String())
|
||||
l.Debug("entering Delete")
|
||||
|
||||
targetAcctI := ctx.Value(util.APAccount)
|
||||
if targetAcctI == nil {
|
||||
// If the target account wasn't set on the context, that means this request didn't pass through the
|
||||
// API, but came from inside GtS as the result of another activity on this instance. That being so,
|
||||
targetAcct, fromFederatorChan, err := extractFromCtx(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if targetAcct == nil || fromFederatorChan == nil {
|
||||
// If the target account or federator channel wasn't set on the context, that means this request didn't pass
|
||||
// through the API, but came from inside GtS as the result of another activity on this instance. That being so,
|
||||
// we can safely just ignore this activity, since we know we've already processed it elsewhere.
|
||||
return nil
|
||||
}
|
||||
targetAcct, ok := targetAcctI.(*gtsmodel.Account)
|
||||
if !ok {
|
||||
l.Error("DELETE: target account was set on context but couldn't be parsed")
|
||||
return nil
|
||||
}
|
||||
|
||||
fromFederatorChanI := ctx.Value(util.APFromFederatorChanKey)
|
||||
if fromFederatorChanI == nil {
|
||||
l.Error("DELETE: from federator channel wasn't set on context")
|
||||
return nil
|
||||
}
|
||||
fromFederatorChan, ok := fromFederatorChanI.(chan messages.FromFederator)
|
||||
if !ok {
|
||||
l.Error("DELETE: from federator channel was set on context but couldn't be parsed")
|
||||
return nil
|
||||
}
|
||||
|
||||
// in a delete we only get the URI, we can't know if we have a status or a profile or something else,
|
||||
// so we have to try a few different things...
|
||||
|
|
|
|||
|
|
@ -29,14 +29,15 @@ import (
|
|||
// id. It may not be owned by this application instance.
|
||||
//
|
||||
// The library makes this call only after acquiring a lock first.
|
||||
//
|
||||
// Implementation note: this just straight up isn't implemented, and doesn't *really* need to be either.
|
||||
func (f *federatingDB) Exists(c context.Context, id *url.URL) (exists bool, err error) {
|
||||
l := f.log.WithFields(
|
||||
logrus.Fields{
|
||||
"func": "Exists",
|
||||
"id": id.String(),
|
||||
"id": id,
|
||||
},
|
||||
)
|
||||
l.Debugf("entering EXISTS function with id %s", id.String())
|
||||
|
||||
l.Debug("entering Exists")
|
||||
return false, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,4 +18,55 @@
|
|||
|
||||
package federatingdb_test
|
||||
|
||||
// TODO: write tests for pgfed
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/config"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/federation/federatingdb"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/typeutils"
|
||||
"github.com/superseriousbusiness/gotosocial/testrig"
|
||||
)
|
||||
|
||||
type FederatingDBTestSuite struct {
|
||||
suite.Suite
|
||||
config *config.Config
|
||||
db db.DB
|
||||
log *logrus.Logger
|
||||
tc typeutils.TypeConverter
|
||||
federatingDB federatingdb.DB
|
||||
|
||||
testTokens map[string]*gtsmodel.Token
|
||||
testClients map[string]*gtsmodel.Client
|
||||
testApplications map[string]*gtsmodel.Application
|
||||
testUsers map[string]*gtsmodel.User
|
||||
testAccounts map[string]*gtsmodel.Account
|
||||
testAttachments map[string]*gtsmodel.MediaAttachment
|
||||
testStatuses map[string]*gtsmodel.Status
|
||||
testBlocks map[string]*gtsmodel.Block
|
||||
}
|
||||
|
||||
func (suite *FederatingDBTestSuite) SetupSuite() {
|
||||
suite.testTokens = testrig.NewTestTokens()
|
||||
suite.testClients = testrig.NewTestClients()
|
||||
suite.testApplications = testrig.NewTestApplications()
|
||||
suite.testUsers = testrig.NewTestUsers()
|
||||
suite.testAccounts = testrig.NewTestAccounts()
|
||||
suite.testAttachments = testrig.NewTestAttachments()
|
||||
suite.testStatuses = testrig.NewTestStatuses()
|
||||
suite.testBlocks = testrig.NewTestBlocks()
|
||||
}
|
||||
|
||||
func (suite *FederatingDBTestSuite) SetupTest() {
|
||||
suite.config = testrig.NewTestConfig()
|
||||
suite.db = testrig.NewTestDB()
|
||||
suite.tc = testrig.NewTestTypeConverter(suite.db)
|
||||
suite.log = testrig.NewTestLog()
|
||||
suite.federatingDB = testrig.NewTestFederatingDB(suite.db)
|
||||
testrig.StandardDBSetup(suite.db, suite.testAccounts)
|
||||
}
|
||||
|
||||
func (suite *FederatingDBTestSuite) TearDownTest() {
|
||||
testrig.StandardDBTeardown(suite.db)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,12 +5,9 @@ import (
|
|||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/go-fed/activity/streams"
|
||||
"github.com/go-fed/activity/streams/vocab"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
)
|
||||
|
||||
// Followers obtains the Followers Collection for an actor with the
|
||||
|
|
@ -22,39 +19,28 @@ import (
|
|||
func (f *federatingDB) Followers(ctx context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error) {
|
||||
l := f.log.WithFields(
|
||||
logrus.Fields{
|
||||
"func": "Followers",
|
||||
"actorIRI": actorIRI.String(),
|
||||
"func": "Followers",
|
||||
"id": actorIRI,
|
||||
},
|
||||
)
|
||||
l.Debugf("entering FOLLOWERS function with actorIRI %s", actorIRI.String())
|
||||
l.Debug("entering Followers")
|
||||
|
||||
acct := >smodel.Account{}
|
||||
|
||||
if util.IsUserPath(actorIRI) {
|
||||
acct, err = f.db.GetAccountByURI(ctx, actorIRI.String())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("FOLLOWERS: db error getting account with uri %s: %s", actorIRI.String(), err)
|
||||
}
|
||||
} else if util.IsFollowersPath(actorIRI) {
|
||||
if err := f.db.GetWhere(ctx, []db.Where{{Key: "followers_uri", Value: actorIRI.String()}}, acct); err != nil {
|
||||
return nil, fmt.Errorf("FOLLOWERS: db error getting account with followers uri %s: %s", actorIRI.String(), err)
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("FOLLOWERS: could not parse actor IRI %s as users or followers path", actorIRI.String())
|
||||
acct, err := f.getAccountForIRI(ctx, actorIRI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
acctFollowers, err := f.db.GetAccountFollowedBy(ctx, acct.ID, false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("FOLLOWERS: db error getting followers for account id %s: %s", acct.ID, err)
|
||||
return nil, fmt.Errorf("Followers: db error getting followers for account id %s: %s", acct.ID, err)
|
||||
}
|
||||
|
||||
followers = streams.NewActivityStreamsCollection()
|
||||
items := streams.NewActivityStreamsItemsProperty()
|
||||
iris := []*url.URL{}
|
||||
for _, follow := range acctFollowers {
|
||||
if follow.Account == nil {
|
||||
followAccount, err := f.db.GetAccountByID(ctx, follow.AccountID)
|
||||
a, err := f.db.GetAccountByID(ctx, follow.AccountID)
|
||||
if err != nil {
|
||||
errWrapped := fmt.Errorf("FOLLOWERS: db error getting account id %s: %s", follow.AccountID, err)
|
||||
errWrapped := fmt.Errorf("Followers: db error getting account id %s: %s", follow.AccountID, err)
|
||||
if err == db.ErrNoEntries {
|
||||
// no entry for this account id so it's probably been deleted and we haven't caught up yet
|
||||
l.Error(errWrapped)
|
||||
|
|
@ -64,15 +50,14 @@ func (f *federatingDB) Followers(ctx context.Context, actorIRI *url.URL) (follow
|
|||
return nil, errWrapped
|
||||
}
|
||||
}
|
||||
follow.Account = followAccount
|
||||
follow.Account = a
|
||||
}
|
||||
|
||||
uri, err := url.Parse(follow.Account.URI)
|
||||
u, err := url.Parse(follow.Account.URI)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("FOLLOWERS: error parsing %s as url: %s", follow.Account.URI, err)
|
||||
return nil, err
|
||||
}
|
||||
items.AppendIRI(uri)
|
||||
iris = append(iris, u)
|
||||
}
|
||||
followers.SetActivityStreamsItems(items)
|
||||
return
|
||||
|
||||
return f.collectIRIs(ctx, iris)
|
||||
}
|
||||
|
|
|
|||
53
internal/federation/federatingdb/followers_test.go
Normal file
53
internal/federation/federatingdb/followers_test.go
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
GoToSocial
|
||||
Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
|
||||
|
||||
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 federatingdb_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/go-fed/activity/streams"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/superseriousbusiness/gotosocial/testrig"
|
||||
)
|
||||
|
||||
type FollowersTestSuite struct {
|
||||
FederatingDBTestSuite
|
||||
}
|
||||
|
||||
func (suite *FollowersTestSuite) TestGetFollowers() {
|
||||
testAccount := suite.testAccounts["local_account_2"]
|
||||
|
||||
f, err := suite.federatingDB.Followers(context.Background(), testrig.URLMustParse(testAccount.URI))
|
||||
suite.NoError(err)
|
||||
|
||||
fi, err := streams.Serialize(f)
|
||||
suite.NoError(err)
|
||||
|
||||
fJson, err := json.Marshal(fi)
|
||||
suite.NoError(err)
|
||||
|
||||
// zork follows local_account_2 so this should be reflected in the response
|
||||
suite.Equal(`{"@context":"https://www.w3.org/ns/activitystreams","items":"http://localhost:8080/users/the_mighty_zork","type":"Collection"}`, string(fJson))
|
||||
}
|
||||
|
||||
func TestFollowersTestSuite(t *testing.T) {
|
||||
suite.Run(t, &FollowersTestSuite{})
|
||||
}
|
||||
|
|
@ -5,12 +5,9 @@ import (
|
|||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/go-fed/activity/streams"
|
||||
"github.com/go-fed/activity/streams/vocab"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
)
|
||||
|
||||
// Following obtains the Following Collection for an actor with the
|
||||
|
|
@ -22,53 +19,28 @@ import (
|
|||
func (f *federatingDB) Following(ctx context.Context, actorIRI *url.URL) (following vocab.ActivityStreamsCollection, err error) {
|
||||
l := f.log.WithFields(
|
||||
logrus.Fields{
|
||||
"func": "Following",
|
||||
"actorIRI": actorIRI.String(),
|
||||
"func": "Following",
|
||||
"id": actorIRI,
|
||||
},
|
||||
)
|
||||
l.Debugf("entering FOLLOWING function with actorIRI %s", actorIRI.String())
|
||||
l.Debug("entering Following")
|
||||
|
||||
var acct *gtsmodel.Account
|
||||
if util.IsUserPath(actorIRI) {
|
||||
username, err := util.ParseUserPath(actorIRI)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("FOLLOWING: error parsing user path: %s", err)
|
||||
}
|
||||
|
||||
a, err := f.db.GetLocalAccountByUsername(ctx, username)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("FOLLOWING: db error getting account with uri %s: %s", actorIRI.String(), err)
|
||||
}
|
||||
|
||||
acct = a
|
||||
} else if util.IsFollowingPath(actorIRI) {
|
||||
username, err := util.ParseFollowingPath(actorIRI)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("FOLLOWING: error parsing following path: %s", err)
|
||||
}
|
||||
|
||||
a, err := f.db.GetLocalAccountByUsername(ctx, username)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("FOLLOWING: db error getting account with following uri %s: %s", actorIRI.String(), err)
|
||||
}
|
||||
|
||||
acct = a
|
||||
} else {
|
||||
return nil, fmt.Errorf("FOLLOWING: could not parse actor IRI %s as users or following path", actorIRI.String())
|
||||
acct, err := f.getAccountForIRI(ctx, actorIRI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
acctFollowing, err := f.db.GetAccountFollows(ctx, acct.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("FOLLOWING: db error getting following for account id %s: %s", acct.ID, err)
|
||||
return nil, fmt.Errorf("Following: db error getting following for account id %s: %s", acct.ID, err)
|
||||
}
|
||||
|
||||
following = streams.NewActivityStreamsCollection()
|
||||
items := streams.NewActivityStreamsItemsProperty()
|
||||
iris := []*url.URL{}
|
||||
for _, follow := range acctFollowing {
|
||||
if follow.Account == nil {
|
||||
followAccount, err := f.db.GetAccountByID(ctx, follow.AccountID)
|
||||
if follow.TargetAccount == nil {
|
||||
a, err := f.db.GetAccountByID(ctx, follow.TargetAccountID)
|
||||
if err != nil {
|
||||
errWrapped := fmt.Errorf("FOLLOWING: db error getting account id %s: %s", follow.AccountID, err)
|
||||
errWrapped := fmt.Errorf("Following: db error getting account id %s: %s", follow.TargetAccountID, err)
|
||||
if err == db.ErrNoEntries {
|
||||
// no entry for this account id so it's probably been deleted and we haven't caught up yet
|
||||
l.Error(errWrapped)
|
||||
|
|
@ -78,15 +50,14 @@ func (f *federatingDB) Following(ctx context.Context, actorIRI *url.URL) (follow
|
|||
return nil, errWrapped
|
||||
}
|
||||
}
|
||||
follow.Account = followAccount
|
||||
follow.TargetAccount = a
|
||||
}
|
||||
|
||||
uri, err := url.Parse(follow.Account.URI)
|
||||
u, err := url.Parse(follow.TargetAccount.URI)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("FOLLOWING: error parsing %s as url: %s", follow.Account.URI, err)
|
||||
return nil, err
|
||||
}
|
||||
items.AppendIRI(uri)
|
||||
iris = append(iris, u)
|
||||
}
|
||||
following.SetActivityStreamsItems(items)
|
||||
return
|
||||
|
||||
return f.collectIRIs(ctx, iris)
|
||||
}
|
||||
|
|
|
|||
53
internal/federation/federatingdb/following_test.go
Normal file
53
internal/federation/federatingdb/following_test.go
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
GoToSocial
|
||||
Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
|
||||
|
||||
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 federatingdb_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/go-fed/activity/streams"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/superseriousbusiness/gotosocial/testrig"
|
||||
)
|
||||
|
||||
type FollowingTestSuite struct {
|
||||
FederatingDBTestSuite
|
||||
}
|
||||
|
||||
func (suite *FollowingTestSuite) TestGetFollowing() {
|
||||
testAccount := suite.testAccounts["local_account_1"]
|
||||
|
||||
f, err := suite.federatingDB.Following(context.Background(), testrig.URLMustParse(testAccount.URI))
|
||||
suite.NoError(err)
|
||||
|
||||
fi, err := streams.Serialize(f)
|
||||
suite.NoError(err)
|
||||
|
||||
fJson, err := json.Marshal(fi)
|
||||
suite.NoError(err)
|
||||
|
||||
// zork follows admin account and local_account_1
|
||||
suite.Equal(`{"@context":"https://www.w3.org/ns/activitystreams","items":["http://localhost:8080/users/admin","http://localhost:8080/users/1happyturtle"],"type":"Collection"}`, string(fJson))
|
||||
}
|
||||
|
||||
func TestFollowingTestSuite(t *testing.T) {
|
||||
suite.Run(t, &FollowingTestSuite{})
|
||||
}
|
||||
|
|
@ -25,8 +25,6 @@ import (
|
|||
|
||||
"github.com/go-fed/activity/streams/vocab"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
)
|
||||
|
||||
|
|
@ -37,46 +35,33 @@ func (f *federatingDB) Get(ctx context.Context, id *url.URL) (value vocab.Type,
|
|||
l := f.log.WithFields(
|
||||
logrus.Fields{
|
||||
"func": "Get",
|
||||
"id": id.String(),
|
||||
"id": id,
|
||||
},
|
||||
)
|
||||
l.Debug("entering GET function")
|
||||
l.Debug("entering Get")
|
||||
|
||||
if util.IsUserPath(id) {
|
||||
acct, err := f.db.GetAccountByURI(ctx, id.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l.Debug("is user path! returning account")
|
||||
return f.typeConverter.AccountToAS(ctx, acct)
|
||||
}
|
||||
|
||||
if util.IsFollowersPath(id) {
|
||||
acct := >smodel.Account{}
|
||||
if err := f.db.GetWhere(ctx, []db.Where{{Key: "followers_uri", Value: id.String()}}, acct); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
followersURI, err := url.Parse(acct.FollowersURI)
|
||||
if util.IsStatusesPath(id) {
|
||||
status, err := f.db.GetStatusByURI(ctx, id.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f.typeConverter.StatusToAS(ctx, status)
|
||||
}
|
||||
|
||||
return f.Followers(ctx, followersURI)
|
||||
if util.IsFollowersPath(id) {
|
||||
return f.Followers(ctx, id)
|
||||
}
|
||||
|
||||
if util.IsFollowingPath(id) {
|
||||
acct := >smodel.Account{}
|
||||
if err := f.db.GetWhere(ctx, []db.Where{{Key: "following_uri", Value: id.String()}}, acct); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
followingURI, err := url.Parse(acct.FollowingURI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return f.Following(ctx, followingURI)
|
||||
return f.Following(ctx, id)
|
||||
}
|
||||
|
||||
return nil, errors.New("could not get")
|
||||
|
|
|
|||
|
|
@ -20,44 +20,19 @@ package federatingdb
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/go-fed/activity/pub"
|
||||
"github.com/go-fed/activity/streams"
|
||||
"github.com/go-fed/activity/streams/vocab"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
)
|
||||
|
||||
// InboxContains returns true if the OrderedCollection at 'inbox'
|
||||
// contains the specified 'id'.
|
||||
//
|
||||
// The library makes this call only after acquiring a lock first.
|
||||
//
|
||||
// Implementation note: we have our own logic for inboxes so always return false here.
|
||||
func (f *federatingDB) InboxContains(c context.Context, inbox, id *url.URL) (contains bool, err error) {
|
||||
l := f.log.WithFields(
|
||||
logrus.Fields{
|
||||
"func": "InboxContains",
|
||||
"id": id.String(),
|
||||
},
|
||||
)
|
||||
l.Debugf("entering INBOXCONTAINS function with for inbox %s and id %s", inbox.String(), id.String())
|
||||
|
||||
if !util.IsInboxPath(inbox) {
|
||||
return false, fmt.Errorf("%s is not an inbox URI", inbox.String())
|
||||
}
|
||||
|
||||
activityI := c.Value(util.APActivity)
|
||||
if activityI == nil {
|
||||
return false, fmt.Errorf("no activity was set for id %s", id.String())
|
||||
}
|
||||
activity, ok := activityI.(pub.Activity)
|
||||
if !ok || activity == nil {
|
||||
return false, fmt.Errorf("could not parse contextual activity for id %s", id.String())
|
||||
}
|
||||
|
||||
l.Debugf("activity type %s for id %s", activity.GetTypeName(), id.String())
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
|
|
@ -65,13 +40,9 @@ func (f *federatingDB) InboxContains(c context.Context, inbox, id *url.URL) (con
|
|||
// the specified IRI, for prepending new items.
|
||||
//
|
||||
// The library makes this call only after acquiring a lock first.
|
||||
//
|
||||
// Implementation note: we don't (yet) serve inboxes, so just return empty and nil here.
|
||||
func (f *federatingDB) GetInbox(c context.Context, inboxIRI *url.URL) (inbox vocab.ActivityStreamsOrderedCollectionPage, err error) {
|
||||
l := f.log.WithFields(
|
||||
logrus.Fields{
|
||||
"func": "GetInbox",
|
||||
},
|
||||
)
|
||||
l.Debugf("entering GETINBOX function with inboxIRI %s", inboxIRI.String())
|
||||
return streams.NewActivityStreamsOrderedCollectionPage(), nil
|
||||
}
|
||||
|
||||
|
|
@ -80,12 +51,8 @@ func (f *federatingDB) GetInbox(c context.Context, inboxIRI *url.URL) (inbox voc
|
|||
// database entries. Separate calls to Create will do that.
|
||||
//
|
||||
// The library makes this call only after acquiring a lock first.
|
||||
//
|
||||
// Implementation note: we don't allow inbox setting so just return nil here.
|
||||
func (f *federatingDB) SetInbox(c context.Context, inbox vocab.ActivityStreamsOrderedCollectionPage) error {
|
||||
l := f.log.WithFields(
|
||||
logrus.Fields{
|
||||
"func": "SetInbox",
|
||||
},
|
||||
)
|
||||
l.Debug("entering SETINBOX function")
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ import (
|
|||
"context"
|
||||
"net/url"
|
||||
|
||||
"github.com/go-fed/activity/streams"
|
||||
"github.com/go-fed/activity/streams/vocab"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Liked obtains the Liked Collection for an actor with the
|
||||
|
|
@ -32,13 +32,8 @@ import (
|
|||
// If modified, the library will then call Update.
|
||||
//
|
||||
// The library makes this call only after acquiring a lock first.
|
||||
//
|
||||
// Implementation note: we don't serve a Liked collection *yet* so just return an empty collection for now.
|
||||
func (f *federatingDB) Liked(c context.Context, actorIRI *url.URL) (liked vocab.ActivityStreamsCollection, err error) {
|
||||
l := f.log.WithFields(
|
||||
logrus.Fields{
|
||||
"func": "Liked",
|
||||
"actorIRI": actorIRI.String(),
|
||||
},
|
||||
)
|
||||
l.Debugf("entering LIKED function with actorIRI %s", actorIRI.String())
|
||||
return nil, nil
|
||||
return streams.NewActivityStreamsCollection(), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,29 +20,19 @@ package federatingdb
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/go-fed/activity/streams"
|
||||
"github.com/go-fed/activity/streams/vocab"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
)
|
||||
|
||||
// GetOutbox returns the first ordered collection page of the outbox
|
||||
// at the specified IRI, for prepending new items.
|
||||
//
|
||||
// The library makes this call only after acquiring a lock first.
|
||||
//
|
||||
// Implementation note: we don't (yet) serve outboxes, so just return empty and nil here.
|
||||
func (f *federatingDB) GetOutbox(ctx context.Context, outboxIRI *url.URL) (inbox vocab.ActivityStreamsOrderedCollectionPage, err error) {
|
||||
l := f.log.WithFields(
|
||||
logrus.Fields{
|
||||
"func": "GetOutbox",
|
||||
},
|
||||
)
|
||||
l.Debug("entering GETOUTBOX function")
|
||||
|
||||
return streams.NewActivityStreamsOrderedCollectionPage(), nil
|
||||
}
|
||||
|
||||
|
|
@ -51,14 +41,9 @@ func (f *federatingDB) GetOutbox(ctx context.Context, outboxIRI *url.URL) (inbox
|
|||
// database entries. Separate calls to Create will do that.
|
||||
//
|
||||
// The library makes this call only after acquiring a lock first.
|
||||
//
|
||||
// Implementation note: we don't allow outbox setting so just return nil here.
|
||||
func (f *federatingDB) SetOutbox(ctx context.Context, outbox vocab.ActivityStreamsOrderedCollectionPage) error {
|
||||
l := f.log.WithFields(
|
||||
logrus.Fields{
|
||||
"func": "SetOutbox",
|
||||
},
|
||||
)
|
||||
l.Debug("entering SETOUTBOX function")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -67,23 +52,9 @@ func (f *federatingDB) SetOutbox(ctx context.Context, outbox vocab.ActivityStrea
|
|||
//
|
||||
// The library makes this call only after acquiring a lock first.
|
||||
func (f *federatingDB) OutboxForInbox(ctx context.Context, inboxIRI *url.URL) (outboxIRI *url.URL, err error) {
|
||||
l := f.log.WithFields(
|
||||
logrus.Fields{
|
||||
"func": "OutboxForInbox",
|
||||
"inboxIRI": inboxIRI.String(),
|
||||
},
|
||||
)
|
||||
l.Debugf("entering OUTBOXFORINBOX function with inboxIRI %s", inboxIRI.String())
|
||||
|
||||
if !util.IsInboxPath(inboxIRI) {
|
||||
return nil, fmt.Errorf("%s is not an inbox URI", inboxIRI.String())
|
||||
}
|
||||
acct := >smodel.Account{}
|
||||
if err := f.db.GetWhere(ctx, []db.Where{{Key: "inbox_uri", Value: inboxIRI.String()}}, acct); err != nil {
|
||||
if err == db.ErrNoEntries {
|
||||
return nil, fmt.Errorf("no actor found that corresponds to inbox %s", inboxIRI.String())
|
||||
}
|
||||
return nil, fmt.Errorf("db error searching for actor with inbox %s", inboxIRI.String())
|
||||
acct, err := f.getAccountForIRI(ctx, inboxIRI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return url.Parse(acct.OutboxURI)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,10 +36,10 @@ func (f *federatingDB) Owns(ctx context.Context, id *url.URL) (bool, error) {
|
|||
l := f.log.WithFields(
|
||||
logrus.Fields{
|
||||
"func": "Owns",
|
||||
"id": id.String(),
|
||||
"id": id,
|
||||
},
|
||||
)
|
||||
l.Tracef("entering OWNS function with id %s", id.String())
|
||||
l.Debug("entering Owns")
|
||||
|
||||
// if the id host isn't this instance host, we don't own this IRI
|
||||
if id.Host != f.config.Host {
|
||||
|
|
|
|||
|
|
@ -20,46 +20,40 @@ package federatingdb
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-fed/activity/streams"
|
||||
"github.com/go-fed/activity/streams/vocab"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/ap"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
)
|
||||
|
||||
func (f *federatingDB) Undo(ctx context.Context, undo vocab.ActivityStreamsUndo) error {
|
||||
l := f.log.WithFields(
|
||||
logrus.Fields{
|
||||
"func": "Undo",
|
||||
"asType": undo.GetTypeName(),
|
||||
"func": "Undo",
|
||||
},
|
||||
)
|
||||
m, err := streams.Serialize(undo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l.Debugf("received UNDO asType %s", string(b))
|
||||
|
||||
targetAcctI := ctx.Value(util.APAccount)
|
||||
if targetAcctI == nil {
|
||||
// If the target account wasn't set on the context, that means this request didn't pass through the
|
||||
// API, but came from inside GtS as the result of another activity on this instance. That being so,
|
||||
// we can safely just ignore this activity, since we know we've already processed it elsewhere.
|
||||
return nil
|
||||
if l.Level >= logrus.DebugLevel {
|
||||
i, err := marshalItem(undo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l = l.WithField("undo", i)
|
||||
l.Debug("entering Undo")
|
||||
}
|
||||
targetAcct, ok := targetAcctI.(*gtsmodel.Account)
|
||||
if !ok {
|
||||
l.Error("UNDO: target account was set on context but couldn't be parsed")
|
||||
|
||||
targetAcct, fromFederatorChan, err := extractFromCtx(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if targetAcct == nil || fromFederatorChan == nil {
|
||||
// If the target account or federator channel wasn't set on the context, that means this request didn't pass
|
||||
// through the API, but came from inside GtS as the result of another activity on this instance. That being so,
|
||||
// we can safely just ignore this activity, since we know we've already processed it elsewhere.
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,11 +20,9 @@ package federatingdb
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-fed/activity/streams"
|
||||
"github.com/go-fed/activity/streams/vocab"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/ap"
|
||||
|
|
@ -45,35 +43,32 @@ import (
|
|||
func (f *federatingDB) Update(ctx context.Context, asType vocab.Type) error {
|
||||
l := f.log.WithFields(
|
||||
logrus.Fields{
|
||||
"func": "Update",
|
||||
"asType": asType.GetTypeName(),
|
||||
"func": "Update",
|
||||
},
|
||||
)
|
||||
m, err := streams.Serialize(asType)
|
||||
|
||||
if l.Level >= logrus.DebugLevel {
|
||||
i, err := marshalItem(asType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l = l.WithField("update", i)
|
||||
l.Debug("entering Update")
|
||||
}
|
||||
|
||||
targetAcct, fromFederatorChan, err := extractFromCtx(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
l.Debugf("received UPDATE asType %s", string(b))
|
||||
|
||||
targetAcctI := ctx.Value(util.APAccount)
|
||||
if targetAcctI == nil {
|
||||
// If the target account wasn't set on the context, that means this request didn't pass through the
|
||||
// API, but came from inside GtS as the result of another activity on this instance. That being so,
|
||||
if targetAcct == nil || fromFederatorChan == nil {
|
||||
// If the target account or federator channel wasn't set on the context, that means this request didn't pass
|
||||
// through the API, but came from inside GtS as the result of another activity on this instance. That being so,
|
||||
// we can safely just ignore this activity, since we know we've already processed it elsewhere.
|
||||
return nil
|
||||
}
|
||||
targetAcct, ok := targetAcctI.(*gtsmodel.Account)
|
||||
if !ok {
|
||||
l.Error("UPDATE: target account was set on context but couldn't be parsed")
|
||||
}
|
||||
|
||||
requestingAcctI := ctx.Value(util.APRequestingAccount)
|
||||
if targetAcctI == nil {
|
||||
if requestingAcctI == nil {
|
||||
l.Error("UPDATE: requesting account wasn't set on context")
|
||||
}
|
||||
requestingAcct, ok := requestingAcctI.(*gtsmodel.Account)
|
||||
|
|
@ -81,15 +76,6 @@ func (f *federatingDB) Update(ctx context.Context, asType vocab.Type) error {
|
|||
l.Error("UPDATE: requesting account was set on context but couldn't be parsed")
|
||||
}
|
||||
|
||||
fromFederatorChanI := ctx.Value(util.APFromFederatorChanKey)
|
||||
if fromFederatorChanI == nil {
|
||||
l.Error("UPDATE: from federator channel wasn't set on context")
|
||||
}
|
||||
fromFederatorChan, ok := fromFederatorChanI.(chan messages.FromFederator)
|
||||
if !ok {
|
||||
l.Error("UPDATE: from federator channel was set on context but couldn't be parsed")
|
||||
}
|
||||
|
||||
typeName := asType.GetTypeName()
|
||||
if typeName == ap.ActorApplication ||
|
||||
typeName == ap.ActorGroup ||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import (
|
|||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/id"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/messages"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
)
|
||||
|
||||
|
|
@ -64,19 +65,18 @@ func sameActor(activityActor vocab.ActivityStreamsActorProperty, followActor voc
|
|||
func (f *federatingDB) NewID(ctx context.Context, t vocab.Type) (idURL *url.URL, err error) {
|
||||
l := f.log.WithFields(
|
||||
logrus.Fields{
|
||||
"func": "NewID",
|
||||
"asType": t.GetTypeName(),
|
||||
"func": "NewID",
|
||||
},
|
||||
)
|
||||
m, err := streams.Serialize(t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
if l.Level >= logrus.DebugLevel {
|
||||
i, err := marshalItem(t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l = l.WithField("newID", i)
|
||||
l.Debug("entering NewID")
|
||||
}
|
||||
b, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l.Debugf("received NEWID request for asType %s", string(b))
|
||||
|
||||
switch t.GetTypeName() {
|
||||
case ap.ActivityFollow:
|
||||
|
|
@ -201,23 +201,9 @@ func (f *federatingDB) NewID(ctx context.Context, t vocab.Type) (idURL *url.URL,
|
|||
//
|
||||
// The library makes this call only after acquiring a lock first.
|
||||
func (f *federatingDB) ActorForOutbox(ctx context.Context, outboxIRI *url.URL) (actorIRI *url.URL, err error) {
|
||||
l := f.log.WithFields(
|
||||
logrus.Fields{
|
||||
"func": "ActorForOutbox",
|
||||
"inboxIRI": outboxIRI.String(),
|
||||
},
|
||||
)
|
||||
l.Debugf("entering ACTORFOROUTBOX function with outboxIRI %s", outboxIRI.String())
|
||||
|
||||
if !util.IsOutboxPath(outboxIRI) {
|
||||
return nil, fmt.Errorf("%s is not an outbox URI", outboxIRI.String())
|
||||
}
|
||||
acct := >smodel.Account{}
|
||||
if err := f.db.GetWhere(ctx, []db.Where{{Key: "outbox_uri", Value: outboxIRI.String()}}, acct); err != nil {
|
||||
if err == db.ErrNoEntries {
|
||||
return nil, fmt.Errorf("no actor found that corresponds to outbox %s", outboxIRI.String())
|
||||
}
|
||||
return nil, fmt.Errorf("db error searching for actor with outbox %s", outboxIRI.String())
|
||||
acct, err := f.getAccountForIRI(ctx, outboxIRI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return url.Parse(acct.URI)
|
||||
}
|
||||
|
|
@ -226,23 +212,116 @@ func (f *federatingDB) ActorForOutbox(ctx context.Context, outboxIRI *url.URL) (
|
|||
//
|
||||
// The library makes this call only after acquiring a lock first.
|
||||
func (f *federatingDB) ActorForInbox(ctx context.Context, inboxIRI *url.URL) (actorIRI *url.URL, err error) {
|
||||
l := f.log.WithFields(
|
||||
logrus.Fields{
|
||||
"func": "ActorForInbox",
|
||||
"inboxIRI": inboxIRI.String(),
|
||||
},
|
||||
)
|
||||
l.Debugf("entering ACTORFORINBOX function with inboxIRI %s", inboxIRI.String())
|
||||
|
||||
if !util.IsInboxPath(inboxIRI) {
|
||||
return nil, fmt.Errorf("%s is not an inbox URI", inboxIRI.String())
|
||||
}
|
||||
acct := >smodel.Account{}
|
||||
if err := f.db.GetWhere(ctx, []db.Where{{Key: "inbox_uri", Value: inboxIRI.String()}}, acct); err != nil {
|
||||
if err == db.ErrNoEntries {
|
||||
return nil, fmt.Errorf("no actor found that corresponds to inbox %s", inboxIRI.String())
|
||||
}
|
||||
return nil, fmt.Errorf("db error searching for actor with inbox %s", inboxIRI.String())
|
||||
acct, err := f.getAccountForIRI(ctx, inboxIRI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return url.Parse(acct.URI)
|
||||
}
|
||||
|
||||
// getAccountForIRI returns the account that corresponds to or owns the given IRI.
|
||||
func (f *federatingDB) getAccountForIRI(ctx context.Context, iri *url.URL) (account *gtsmodel.Account, err error) {
|
||||
acct := >smodel.Account{}
|
||||
|
||||
if util.IsInboxPath(iri) {
|
||||
if err := f.db.GetWhere(ctx, []db.Where{{Key: "inbox_uri", Value: iri.String()}}, acct); err != nil {
|
||||
if err == db.ErrNoEntries {
|
||||
return nil, fmt.Errorf("no actor found that corresponds to inbox %s", iri.String())
|
||||
}
|
||||
return nil, fmt.Errorf("db error searching for actor with inbox %s", iri.String())
|
||||
}
|
||||
return acct, nil
|
||||
}
|
||||
|
||||
if util.IsOutboxPath(iri) {
|
||||
if err := f.db.GetWhere(ctx, []db.Where{{Key: "outbox_uri", Value: iri.String()}}, acct); err != nil {
|
||||
if err == db.ErrNoEntries {
|
||||
return nil, fmt.Errorf("no actor found that corresponds to outbox %s", iri.String())
|
||||
}
|
||||
return nil, fmt.Errorf("db error searching for actor with outbox %s", iri.String())
|
||||
}
|
||||
return acct, nil
|
||||
}
|
||||
|
||||
if util.IsUserPath(iri) {
|
||||
if err := f.db.GetWhere(ctx, []db.Where{{Key: "uri", Value: iri.String()}}, acct); err != nil {
|
||||
if err == db.ErrNoEntries {
|
||||
return nil, fmt.Errorf("no actor found that corresponds to uri %s", iri.String())
|
||||
}
|
||||
return nil, fmt.Errorf("db error searching for actor with uri %s", iri.String())
|
||||
}
|
||||
return acct, nil
|
||||
}
|
||||
|
||||
if util.IsFollowersPath(iri) {
|
||||
if err := f.db.GetWhere(ctx, []db.Where{{Key: "followers_uri", Value: iri.String()}}, acct); err != nil {
|
||||
if err == db.ErrNoEntries {
|
||||
return nil, fmt.Errorf("no actor found that corresponds to followers_uri %s", iri.String())
|
||||
}
|
||||
return nil, fmt.Errorf("db error searching for actor with followers_uri %s", iri.String())
|
||||
}
|
||||
return acct, nil
|
||||
}
|
||||
|
||||
if util.IsFollowingPath(iri) {
|
||||
if err := f.db.GetWhere(ctx, []db.Where{{Key: "following_uri", Value: iri.String()}}, acct); err != nil {
|
||||
if err == db.ErrNoEntries {
|
||||
return nil, fmt.Errorf("no actor found that corresponds to following_uri %s", iri.String())
|
||||
}
|
||||
return nil, fmt.Errorf("db error searching for actor with following_uri %s", iri.String())
|
||||
}
|
||||
return acct, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("getActorForIRI: iri %s not recognised", iri)
|
||||
}
|
||||
|
||||
// collectFollows takes a slice of iris and converts them into ActivityStreamsCollection of IRIs.
|
||||
func (f *federatingDB) collectIRIs(ctx context.Context, iris []*url.URL) (vocab.ActivityStreamsCollection, error) {
|
||||
collection := streams.NewActivityStreamsCollection()
|
||||
items := streams.NewActivityStreamsItemsProperty()
|
||||
for _, i := range iris {
|
||||
items.AppendIRI(i)
|
||||
}
|
||||
collection.SetActivityStreamsItems(items)
|
||||
return collection, nil
|
||||
}
|
||||
|
||||
// extractFromCtx extracts some useful values from a context passed into the federatingDB via the API:
|
||||
// - The target account that owns the inbox or URI being interacted with.
|
||||
// - A channel that messages for the processor can be placed into.
|
||||
func extractFromCtx(ctx context.Context) (*gtsmodel.Account, chan messages.FromFederator, error) {
|
||||
var targetAcct *gtsmodel.Account
|
||||
targetAcctI := ctx.Value(util.APAccount)
|
||||
if targetAcctI != nil {
|
||||
var ok bool
|
||||
targetAcct, ok = targetAcctI.(*gtsmodel.Account)
|
||||
if !ok {
|
||||
return nil, nil, errors.New("extractFromCtx: account value in context not parseable")
|
||||
}
|
||||
}
|
||||
|
||||
var fromFederatorChan chan messages.FromFederator
|
||||
fromFederatorChanI := ctx.Value(util.APFromFederatorChanKey)
|
||||
if fromFederatorChanI != nil {
|
||||
var ok bool
|
||||
fromFederatorChan, ok = fromFederatorChanI.(chan messages.FromFederator)
|
||||
if !ok {
|
||||
return nil, nil, errors.New("extractFromCtx: fromFederatorChan value in context not parseable")
|
||||
}
|
||||
}
|
||||
|
||||
return targetAcct, fromFederatorChan, nil
|
||||
}
|
||||
|
||||
func marshalItem(item vocab.Type) (string, error) {
|
||||
m, err := streams.Serialize(item)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
b, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(b), nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue