mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-10-30 01:02:25 -05:00
incoming UNDO for follows now working
This commit is contained in:
parent
8832784778
commit
c7b4f847d8
18 changed files with 265 additions and 110 deletions
|
|
@ -30,7 +30,7 @@
|
||||||
* [ ] /api/v1/accounts/:id/pin POST (Feature this account on profile)
|
* [ ] /api/v1/accounts/:id/pin POST (Feature this account on profile)
|
||||||
* [ ] /api/v1/accounts/:id/unpin POST (Remove this account from profile)
|
* [ ] /api/v1/accounts/:id/unpin POST (Remove this account from profile)
|
||||||
* [ ] /api/v1/accounts/:id/note POST (Make a personal note about this account)
|
* [ ] /api/v1/accounts/:id/note POST (Make a personal note about this account)
|
||||||
* [ ] /api/v1/accounts/relationships GET (Check relationships with accounts)
|
* [x] /api/v1/accounts/relationships GET (Check relationships with accounts)
|
||||||
* [ ] /api/v1/accounts/search GET (Search for an account)
|
* [ ] /api/v1/accounts/search GET (Search for an account)
|
||||||
* [ ] Bookmarks
|
* [ ] Bookmarks
|
||||||
* [ ] /api/v1/bookmarks GET (See bookmarked statuses)
|
* [ ] /api/v1/bookmarks GET (See bookmarked statuses)
|
||||||
|
|
@ -177,6 +177,7 @@
|
||||||
* [ ] 'Greedy' federation
|
* [ ] 'Greedy' federation
|
||||||
* [ ] No federation (insulate this instance from the Fediverse)
|
* [ ] No federation (insulate this instance from the Fediverse)
|
||||||
* [ ] Allowlist
|
* [ ] Allowlist
|
||||||
|
* [x] Secure HTTP signatures (creation and validation)
|
||||||
* [ ] Storage
|
* [ ] Storage
|
||||||
* [x] Internal/statuses/preferences etc
|
* [x] Internal/statuses/preferences etc
|
||||||
* [x] Postgres interface
|
* [x] Postgres interface
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/go-fed/activity/pub"
|
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -44,7 +43,7 @@ func (e ErrNoEntries) Error() string {
|
||||||
type DB interface {
|
type DB interface {
|
||||||
// Federation returns an interface that's compatible with go-fed, for performing federation storage/retrieval functions.
|
// Federation returns an interface that's compatible with go-fed, for performing federation storage/retrieval functions.
|
||||||
// See: https://pkg.go.dev/github.com/go-fed/activity@v1.0.0/pub?utm_source=gopls#Database
|
// See: https://pkg.go.dev/github.com/go-fed/activity@v1.0.0/pub?utm_source=gopls#Database
|
||||||
Federation() pub.Database
|
// Federation() federatingdb.FederatingDB
|
||||||
|
|
||||||
/*
|
/*
|
||||||
BASIC DB FUNCTIONALITY
|
BASIC DB FUNCTIONALITY
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-fed/activity/pub"
|
|
||||||
"github.com/go-pg/pg/extra/pgdebug"
|
"github.com/go-pg/pg/extra/pgdebug"
|
||||||
"github.com/go-pg/pg/v10"
|
"github.com/go-pg/pg/v10"
|
||||||
"github.com/go-pg/pg/v10/orm"
|
"github.com/go-pg/pg/v10/orm"
|
||||||
|
|
@ -38,7 +37,6 @@ import (
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/config"
|
"github.com/superseriousbusiness/gotosocial/internal/config"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/federation"
|
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
|
@ -46,11 +44,11 @@ import (
|
||||||
|
|
||||||
// postgresService satisfies the DB interface
|
// postgresService satisfies the DB interface
|
||||||
type postgresService struct {
|
type postgresService struct {
|
||||||
config *config.Config
|
config *config.Config
|
||||||
conn *pg.DB
|
conn *pg.DB
|
||||||
log *logrus.Logger
|
log *logrus.Logger
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
federationDB pub.Database
|
// federationDB pub.Database
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPostgresService returns a postgresService derived from the provided config, which implements the go-fed DB interface.
|
// NewPostgresService returns a postgresService derived from the provided config, which implements the go-fed DB interface.
|
||||||
|
|
@ -97,9 +95,6 @@ func NewPostgresService(ctx context.Context, c *config.Config, log *logrus.Logge
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
}
|
}
|
||||||
|
|
||||||
federatingDB := federation.NewFederatingDB(ps, c, log)
|
|
||||||
ps.federationDB = federatingDB
|
|
||||||
|
|
||||||
// we can confidently return this useable postgres service now
|
// we can confidently return this useable postgres service now
|
||||||
return ps, nil
|
return ps, nil
|
||||||
}
|
}
|
||||||
|
|
@ -159,14 +154,6 @@ func derivePGOptions(c *config.Config) (*pg.Options, error) {
|
||||||
return options, nil
|
return options, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
FEDERATION FUNCTIONALITY
|
|
||||||
*/
|
|
||||||
|
|
||||||
func (ps *postgresService) Federation() pub.Database {
|
|
||||||
return ps.federationDB
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
BASIC DB FUNCTIONALITY
|
BASIC DB FUNCTIONALITY
|
||||||
*/
|
*/
|
||||||
|
|
@ -285,20 +272,22 @@ func (ps *postgresService) UpdateOneByID(id string, key string, value interface{
|
||||||
|
|
||||||
func (ps *postgresService) DeleteByID(id string, i interface{}) error {
|
func (ps *postgresService) DeleteByID(id string, i interface{}) error {
|
||||||
if _, err := ps.conn.Model(i).Where("id = ?", id).Delete(); err != nil {
|
if _, err := ps.conn.Model(i).Where("id = ?", id).Delete(); err != nil {
|
||||||
if err == pg.ErrNoRows {
|
// if there are no rows *anyway* then that's fine
|
||||||
return db.ErrNoEntries{}
|
// just return err if there's an actual error
|
||||||
|
if err != pg.ErrNoRows {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *postgresService) DeleteWhere(key string, value interface{}, i interface{}) error {
|
func (ps *postgresService) DeleteWhere(key string, value interface{}, i interface{}) error {
|
||||||
if _, err := ps.conn.Model(i).Where("? = ?", pg.Safe(key), value).Delete(); err != nil {
|
if _, err := ps.conn.Model(i).Where("? = ?", pg.Safe(key), value).Delete(); err != nil {
|
||||||
if err == pg.ErrNoRows {
|
// if there are no rows *anyway* then that's fine
|
||||||
return db.ErrNoEntries{}
|
// just return err if there's an actual error
|
||||||
|
if err != pg.ErrNoRows {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,11 @@ import (
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type FederatingDB interface {
|
||||||
|
pub.Database
|
||||||
|
Undo(c context.Context, asType vocab.Type) error
|
||||||
|
}
|
||||||
|
|
||||||
// FederatingDB uses the underlying DB interface to implement the go-fed pub.Database interface.
|
// FederatingDB uses the underlying DB interface to implement the go-fed pub.Database interface.
|
||||||
// It doesn't care what the underlying implementation of the DB interface is, as long as it works.
|
// It doesn't care what the underlying implementation of the DB interface is, as long as it works.
|
||||||
type federatingDB struct {
|
type federatingDB struct {
|
||||||
|
|
@ -48,8 +53,8 @@ type federatingDB struct {
|
||||||
typeConverter typeutils.TypeConverter
|
typeConverter typeutils.TypeConverter
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFederatingDB returns a pub.Database interface using the given database, config, and logger.
|
// NewFederatingDB returns a FederatingDB interface using the given database, config, and logger.
|
||||||
func NewFederatingDB(db db.DB, config *config.Config, log *logrus.Logger) pub.Database {
|
func NewFederatingDB(db db.DB, config *config.Config, log *logrus.Logger) FederatingDB {
|
||||||
return &federatingDB{
|
return &federatingDB{
|
||||||
locks: new(sync.Map),
|
locks: new(sync.Map),
|
||||||
db: db,
|
db: db,
|
||||||
|
|
@ -405,7 +410,7 @@ func (f *federatingDB) Create(ctx context.Context, asType vocab.Type) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
switch gtsmodel.ActivityStreamsActivity(asType.GetTypeName()) {
|
switch asType.GetTypeName() {
|
||||||
case gtsmodel.ActivityStreamsCreate:
|
case gtsmodel.ActivityStreamsCreate:
|
||||||
create, ok := asType.(vocab.ActivityStreamsCreate)
|
create, ok := asType.(vocab.ActivityStreamsCreate)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
@ -413,7 +418,7 @@ func (f *federatingDB) Create(ctx context.Context, asType vocab.Type) error {
|
||||||
}
|
}
|
||||||
object := create.GetActivityStreamsObject()
|
object := create.GetActivityStreamsObject()
|
||||||
for objectIter := object.Begin(); objectIter != object.End(); objectIter = objectIter.Next() {
|
for objectIter := object.Begin(); objectIter != object.End(); objectIter = objectIter.Next() {
|
||||||
switch gtsmodel.ActivityStreamsObject(objectIter.GetType().GetTypeName()) {
|
switch objectIter.GetType().GetTypeName() {
|
||||||
case gtsmodel.ActivityStreamsNote:
|
case gtsmodel.ActivityStreamsNote:
|
||||||
note := objectIter.GetActivityStreamsNote()
|
note := objectIter.GetActivityStreamsNote()
|
||||||
status, err := f.typeConverter.ASStatusToStatus(note)
|
status, err := f.typeConverter.ASStatusToStatus(note)
|
||||||
|
|
@ -425,9 +430,10 @@ func (f *federatingDB) Create(ctx context.Context, asType vocab.Type) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
fromFederatorChan <- gtsmodel.FromFederator{
|
fromFederatorChan <- gtsmodel.FromFederator{
|
||||||
APObjectType: gtsmodel.ActivityStreamsNote,
|
APObjectType: gtsmodel.ActivityStreamsNote,
|
||||||
APActivityType: gtsmodel.ActivityStreamsCreate,
|
APActivityType: gtsmodel.ActivityStreamsCreate,
|
||||||
GTSModel: status,
|
GTSModel: status,
|
||||||
|
ReceivingAccount: targetAcct,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -455,6 +461,98 @@ func (f *federatingDB) Create(ctx context.Context, asType vocab.Type) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *federatingDB) Undo(ctx context.Context, asType vocab.Type) error {
|
||||||
|
l := f.log.WithFields(
|
||||||
|
logrus.Fields{
|
||||||
|
"func": "Undo",
|
||||||
|
"asType": asType.GetTypeName(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
m, err := streams.Serialize(asType)
|
||||||
|
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 {
|
||||||
|
l.Error("UNDO: target account wasn't set on context")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
targetAcct, ok := targetAcctI.(*gtsmodel.Account)
|
||||||
|
if !ok {
|
||||||
|
l.Error("UNDO: target account was set on context but couldn't be parsed")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// fromFederatorChanI := ctx.Value(util.APFromFederatorChanKey)
|
||||||
|
// if fromFederatorChanI == nil {
|
||||||
|
// l.Error("from federator channel wasn't set on context")
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
// fromFederatorChan, ok := fromFederatorChanI.(chan gtsmodel.FromFederator)
|
||||||
|
// if !ok {
|
||||||
|
// l.Error("from federator channel was set on context but couldn't be parsed")
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
switch asType.GetTypeName() {
|
||||||
|
// UNDO
|
||||||
|
case gtsmodel.ActivityStreamsUndo:
|
||||||
|
undo, ok := asType.(vocab.ActivityStreamsUndo)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("UNDO: couldn't parse UNDO into vocab.ActivityStreamsUndo")
|
||||||
|
}
|
||||||
|
undoObject := undo.GetActivityStreamsObject()
|
||||||
|
if undoObject == nil {
|
||||||
|
return errors.New("UNDO: no object set on vocab.ActivityStreamsUndo")
|
||||||
|
}
|
||||||
|
|
||||||
|
for iter := undoObject.Begin(); iter != undoObject.End(); iter = iter.Next() {
|
||||||
|
switch iter.GetType().GetTypeName() {
|
||||||
|
case string(gtsmodel.ActivityStreamsFollow):
|
||||||
|
// UNDO FOLLOW
|
||||||
|
ASFollow, ok := iter.GetType().(vocab.ActivityStreamsFollow)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("UNDO: couldn't parse follow into vocab.ActivityStreamsFollow")
|
||||||
|
}
|
||||||
|
// make sure the actor owns the follow
|
||||||
|
if !sameActor(undo.GetActivityStreamsActor(), ASFollow.GetActivityStreamsActor()) {
|
||||||
|
return errors.New("UNDO: follow actor and activity actor not the same")
|
||||||
|
}
|
||||||
|
// convert the follow to something we can understand
|
||||||
|
gtsFollow, err := f.typeConverter.ASFollowToFollow(ASFollow)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("UNDO: error converting asfollow to gtsfollow: %s", err)
|
||||||
|
}
|
||||||
|
// make sure the addressee of the original follow is the same as whatever inbox this landed in
|
||||||
|
if gtsFollow.TargetAccountID != targetAcct.ID {
|
||||||
|
return errors.New("UNDO: follow object account and inbox account were not the same")
|
||||||
|
}
|
||||||
|
// delete any existing FOLLOW
|
||||||
|
if err := f.db.DeleteWhere("uri", gtsFollow.URI, >smodel.Follow{}); err != nil {
|
||||||
|
return fmt.Errorf("UNDO: db error removing follow: %s", err)
|
||||||
|
}
|
||||||
|
// delete any existing FOLLOW REQUEST
|
||||||
|
if err := f.db.DeleteWhere("uri", gtsFollow.URI, >smodel.FollowRequest{}); err != nil {
|
||||||
|
return fmt.Errorf("UNDO: db error removing follow request: %s", err)
|
||||||
|
}
|
||||||
|
l.Debug("follow undone")
|
||||||
|
return nil
|
||||||
|
case string(gtsmodel.ActivityStreamsLike):
|
||||||
|
// UNDO LIKE
|
||||||
|
case string(gtsmodel.ActivityStreamsAnnounce):
|
||||||
|
// UNDO BOOST/REBLOG/ANNOUNCE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Update sets an existing entry to the database based on the value's
|
// Update sets an existing entry to the database based on the value's
|
||||||
// id.
|
// id.
|
||||||
//
|
//
|
||||||
|
|
@ -500,7 +598,7 @@ func (f *federatingDB) Update(ctx context.Context, asType vocab.Type) error {
|
||||||
l.Error("from federator channel was set on context but couldn't be parsed")
|
l.Error("from federator channel was set on context but couldn't be parsed")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch gtsmodel.ActivityStreamsActivity(asType.GetTypeName()) {
|
switch asType.GetTypeName() {
|
||||||
case gtsmodel.ActivityStreamsUpdate:
|
case gtsmodel.ActivityStreamsUpdate:
|
||||||
update, ok := asType.(vocab.ActivityStreamsCreate)
|
update, ok := asType.(vocab.ActivityStreamsCreate)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
|
||||||
|
|
@ -20,14 +20,12 @@ package federation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/go-fed/activity/pub"
|
"github.com/go-fed/activity/pub"
|
||||||
"github.com/go-fed/activity/streams"
|
|
||||||
"github.com/go-fed/activity/streams/vocab"
|
"github.com/go-fed/activity/streams/vocab"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||||
|
|
@ -271,7 +269,7 @@ func (f *federator) FederatingCallbacks(ctx context.Context) (wrapped pub.Federa
|
||||||
// override default undo behavior
|
// override default undo behavior
|
||||||
other = []interface{}{
|
other = []interface{}{
|
||||||
func(ctx context.Context, undo vocab.ActivityStreamsUndo) error {
|
func(ctx context.Context, undo vocab.ActivityStreamsUndo) error {
|
||||||
return f.typeConverter.
|
return f.FederatingDB().Undo(ctx, undo)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ type Federator interface {
|
||||||
type federator struct {
|
type federator struct {
|
||||||
config *config.Config
|
config *config.Config
|
||||||
db db.DB
|
db db.DB
|
||||||
|
federatingDB FederatingDB
|
||||||
clock pub.Clock
|
clock pub.Clock
|
||||||
typeConverter typeutils.TypeConverter
|
typeConverter typeutils.TypeConverter
|
||||||
transportController transport.Controller
|
transportController transport.Controller
|
||||||
|
|
@ -60,18 +61,19 @@ type federator struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFederator returns a new federator
|
// NewFederator returns a new federator
|
||||||
func NewFederator(db db.DB, transportController transport.Controller, config *config.Config, log *logrus.Logger, typeConverter typeutils.TypeConverter) Federator {
|
func NewFederator(db db.DB, federatingDB FederatingDB, transportController transport.Controller, config *config.Config, log *logrus.Logger, typeConverter typeutils.TypeConverter) Federator {
|
||||||
|
|
||||||
clock := &Clock{}
|
clock := &Clock{}
|
||||||
f := &federator{
|
f := &federator{
|
||||||
config: config,
|
config: config,
|
||||||
db: db,
|
db: db,
|
||||||
|
federatingDB: federatingDB,
|
||||||
clock: &Clock{},
|
clock: &Clock{},
|
||||||
typeConverter: typeConverter,
|
typeConverter: typeConverter,
|
||||||
transportController: transportController,
|
transportController: transportController,
|
||||||
log: log,
|
log: log,
|
||||||
}
|
}
|
||||||
actor := newFederatingActor(f, f, db.Federation(), clock)
|
actor := newFederatingActor(f, f, federatingDB, clock)
|
||||||
f.actor = actor
|
f.actor = actor
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
@ -79,3 +81,7 @@ func NewFederator(db db.DB, transportController transport.Controller, config *co
|
||||||
func (f *federator) FederatingActor() pub.FederatingActor {
|
func (f *federator) FederatingActor() pub.FederatingActor {
|
||||||
return f.actor
|
return f.actor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *federator) FederatingDB() FederatingDB {
|
||||||
|
return f.federatingDB
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ func (suite *ProtocolTestSuite) TestPostInboxRequestBodyHook() {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}))
|
}))
|
||||||
// setup module being tested
|
// setup module being tested
|
||||||
federator := federation.NewFederator(suite.db, tc, suite.config, suite.log, suite.typeConverter)
|
federator := federation.NewFederator(suite.db, testrig.NewTestFederatingDB(suite.db), tc, suite.config, suite.log, suite.typeConverter)
|
||||||
|
|
||||||
// setup request
|
// setup request
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
@ -155,7 +155,7 @@ func (suite *ProtocolTestSuite) TestAuthenticatePostInbox() {
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// now setup module being tested, with the mock transport controller
|
// now setup module being tested, with the mock transport controller
|
||||||
federator := federation.NewFederator(suite.db, tc, suite.config, suite.log, suite.typeConverter)
|
federator := federation.NewFederator(suite.db, testrig.NewTestFederatingDB(suite.db), tc, suite.config, suite.log, suite.typeConverter)
|
||||||
|
|
||||||
// setup request
|
// setup request
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
|
||||||
|
|
@ -243,3 +243,23 @@ func (f *federator) GetTransportForUser(username string) (transport.Transport, e
|
||||||
}
|
}
|
||||||
return transport, nil
|
return transport, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sameActor(activityActor vocab.ActivityStreamsActorProperty, followActor vocab.ActivityStreamsActorProperty) bool {
|
||||||
|
if activityActor == nil || followActor == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for aIter := activityActor.Begin(); aIter != activityActor.End(); aIter = aIter.Next() {
|
||||||
|
for fIter := followActor.Begin(); fIter != followActor.End(); fIter = fIter.Next() {
|
||||||
|
if aIter.GetIRI() == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if fIter.GetIRI() == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if aIter.GetIRI().String() == fIter.GetIRI().String() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,8 @@ var Run action.GTSAction = func(ctx context.Context, c *config.Config, log *logr
|
||||||
return fmt.Errorf("error creating dbservice: %s", err)
|
return fmt.Errorf("error creating dbservice: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
federatingDB := federation.NewFederatingDB(dbService, c, log)
|
||||||
|
|
||||||
router, err := router.New(c, log)
|
router, err := router.New(c, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error creating router: %s", err)
|
return fmt.Errorf("error creating router: %s", err)
|
||||||
|
|
@ -100,7 +102,7 @@ var Run action.GTSAction = func(ctx context.Context, c *config.Config, log *logr
|
||||||
mediaHandler := media.New(c, dbService, storageBackend, log)
|
mediaHandler := media.New(c, dbService, storageBackend, log)
|
||||||
oauthServer := oauth.New(dbService, log)
|
oauthServer := oauth.New(dbService, log)
|
||||||
transportController := transport.NewController(c, &federation.Clock{}, http.DefaultClient, log)
|
transportController := transport.NewController(c, &federation.Clock{}, http.DefaultClient, log)
|
||||||
federator := federation.NewFederator(dbService, transportController, c, log, typeConverter)
|
federator := federation.NewFederator(dbService, federatingDB, transportController, c, log, typeConverter)
|
||||||
processor := message.NewProcessor(c, typeConverter, federator, oauthServer, mediaHandler, storageBackend, dbService, log)
|
processor := message.NewProcessor(c, typeConverter, federator, oauthServer, mediaHandler, storageBackend, dbService, log)
|
||||||
if err := processor.Start(); err != nil {
|
if err := processor.Start(); err != nil {
|
||||||
return fmt.Errorf("error starting processor: %s", err)
|
return fmt.Errorf("error starting processor: %s", err)
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ type Account struct {
|
||||||
// URL for getting the featured collection list of this account
|
// URL for getting the featured collection list of this account
|
||||||
FeaturedCollectionURI string `pg:",unique"`
|
FeaturedCollectionURI string `pg:",unique"`
|
||||||
// What type of activitypub actor is this account?
|
// What type of activitypub actor is this account?
|
||||||
ActorType ActivityStreamsActor
|
ActorType string
|
||||||
// This account is associated with x account id
|
// This account is associated with x account id
|
||||||
AlsoKnownAs string
|
AlsoKnownAs string
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,110 +18,101 @@
|
||||||
|
|
||||||
package gtsmodel
|
package gtsmodel
|
||||||
|
|
||||||
// ActivityStreamsObject refers to https://www.w3.org/TR/activitystreams-vocabulary/#object-types
|
|
||||||
type ActivityStreamsObject string
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// ActivityStreamsArticle https://www.w3.org/TR/activitystreams-vocabulary/#dfn-article
|
// ActivityStreamsArticle https://www.w3.org/TR/activitystreams-vocabulary/#dfn-article
|
||||||
ActivityStreamsArticle ActivityStreamsObject = "Article"
|
ActivityStreamsArticle = "Article"
|
||||||
// ActivityStreamsAudio https://www.w3.org/TR/activitystreams-vocabulary/#dfn-audio
|
// ActivityStreamsAudio https://www.w3.org/TR/activitystreams-vocabulary/#dfn-audio
|
||||||
ActivityStreamsAudio ActivityStreamsObject = "Audio"
|
ActivityStreamsAudio = "Audio"
|
||||||
// ActivityStreamsDocument https://www.w3.org/TR/activitystreams-vocabulary/#dfn-document
|
// ActivityStreamsDocument https://www.w3.org/TR/activitystreams-vocabulary/#dfn-document
|
||||||
ActivityStreamsDocument ActivityStreamsObject = "Event"
|
ActivityStreamsDocument = "Event"
|
||||||
// ActivityStreamsEvent https://www.w3.org/TR/activitystreams-vocabulary/#dfn-event
|
// ActivityStreamsEvent https://www.w3.org/TR/activitystreams-vocabulary/#dfn-event
|
||||||
ActivityStreamsEvent ActivityStreamsObject = "Event"
|
ActivityStreamsEvent = "Event"
|
||||||
// ActivityStreamsImage https://www.w3.org/TR/activitystreams-vocabulary/#dfn-image
|
// ActivityStreamsImage https://www.w3.org/TR/activitystreams-vocabulary/#dfn-image
|
||||||
ActivityStreamsImage ActivityStreamsObject = "Image"
|
ActivityStreamsImage = "Image"
|
||||||
// ActivityStreamsNote https://www.w3.org/TR/activitystreams-vocabulary/#dfn-note
|
// ActivityStreamsNote https://www.w3.org/TR/activitystreams-vocabulary/#dfn-note
|
||||||
ActivityStreamsNote ActivityStreamsObject = "Note"
|
ActivityStreamsNote = "Note"
|
||||||
// ActivityStreamsPage https://www.w3.org/TR/activitystreams-vocabulary/#dfn-page
|
// ActivityStreamsPage https://www.w3.org/TR/activitystreams-vocabulary/#dfn-page
|
||||||
ActivityStreamsPage ActivityStreamsObject = "Page"
|
ActivityStreamsPage = "Page"
|
||||||
// ActivityStreamsPlace https://www.w3.org/TR/activitystreams-vocabulary/#dfn-place
|
// ActivityStreamsPlace https://www.w3.org/TR/activitystreams-vocabulary/#dfn-place
|
||||||
ActivityStreamsPlace ActivityStreamsObject = "Place"
|
ActivityStreamsPlace = "Place"
|
||||||
// ActivityStreamsProfile https://www.w3.org/TR/activitystreams-vocabulary/#dfn-profile
|
// ActivityStreamsProfile https://www.w3.org/TR/activitystreams-vocabulary/#dfn-profile
|
||||||
ActivityStreamsProfile ActivityStreamsObject = "Profile"
|
ActivityStreamsProfile = "Profile"
|
||||||
// ActivityStreamsRelationship https://www.w3.org/TR/activitystreams-vocabulary/#dfn-relationship
|
// ActivityStreamsRelationship https://www.w3.org/TR/activitystreams-vocabulary/#dfn-relationship
|
||||||
ActivityStreamsRelationship ActivityStreamsObject = "Relationship"
|
ActivityStreamsRelationship = "Relationship"
|
||||||
// ActivityStreamsTombstone https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tombstone
|
// ActivityStreamsTombstone https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tombstone
|
||||||
ActivityStreamsTombstone ActivityStreamsObject = "Tombstone"
|
ActivityStreamsTombstone = "Tombstone"
|
||||||
// ActivityStreamsVideo https://www.w3.org/TR/activitystreams-vocabulary/#dfn-video
|
// ActivityStreamsVideo https://www.w3.org/TR/activitystreams-vocabulary/#dfn-video
|
||||||
ActivityStreamsVideo ActivityStreamsObject = "Video"
|
ActivityStreamsVideo = "Video"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ActivityStreamsActor refers to https://www.w3.org/TR/activitystreams-vocabulary/#actor-types
|
|
||||||
type ActivityStreamsActor string
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// ActivityStreamsApplication https://www.w3.org/TR/activitystreams-vocabulary/#dfn-application
|
// ActivityStreamsApplication https://www.w3.org/TR/activitystreams-vocabulary/#dfn-application
|
||||||
ActivityStreamsApplication ActivityStreamsActor = "Application"
|
ActivityStreamsApplication = "Application"
|
||||||
// ActivityStreamsGroup https://www.w3.org/TR/activitystreams-vocabulary/#dfn-group
|
// ActivityStreamsGroup https://www.w3.org/TR/activitystreams-vocabulary/#dfn-group
|
||||||
ActivityStreamsGroup ActivityStreamsActor = "Group"
|
ActivityStreamsGroup = "Group"
|
||||||
// ActivityStreamsOrganization https://www.w3.org/TR/activitystreams-vocabulary/#dfn-organization
|
// ActivityStreamsOrganization https://www.w3.org/TR/activitystreams-vocabulary/#dfn-organization
|
||||||
ActivityStreamsOrganization ActivityStreamsActor = "Organization"
|
ActivityStreamsOrganization = "Organization"
|
||||||
// ActivityStreamsPerson https://www.w3.org/TR/activitystreams-vocabulary/#dfn-person
|
// ActivityStreamsPerson https://www.w3.org/TR/activitystreams-vocabulary/#dfn-person
|
||||||
ActivityStreamsPerson ActivityStreamsActor = "Person"
|
ActivityStreamsPerson = "Person"
|
||||||
// ActivityStreamsService https://www.w3.org/TR/activitystreams-vocabulary/#dfn-service
|
// ActivityStreamsService https://www.w3.org/TR/activitystreams-vocabulary/#dfn-service
|
||||||
ActivityStreamsService ActivityStreamsActor = "Service"
|
ActivityStreamsService = "Service"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ActivityStreamsActivity refers to https://www.w3.org/TR/activitystreams-vocabulary/#activity-types
|
|
||||||
type ActivityStreamsActivity string
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// ActivityStreamsAccept https://www.w3.org/TR/activitystreams-vocabulary/#dfn-accept
|
// ActivityStreamsAccept https://www.w3.org/TR/activitystreams-vocabulary/#dfn-accept
|
||||||
ActivityStreamsAccept ActivityStreamsActivity = "Accept"
|
ActivityStreamsAccept = "Accept"
|
||||||
// ActivityStreamsAdd https://www.w3.org/TR/activitystreams-vocabulary/#dfn-add
|
// ActivityStreamsAdd https://www.w3.org/TR/activitystreams-vocabulary/#dfn-add
|
||||||
ActivityStreamsAdd ActivityStreamsActivity = "Add"
|
ActivityStreamsAdd = "Add"
|
||||||
// ActivityStreamsAnnounce https://www.w3.org/TR/activitystreams-vocabulary/#dfn-announce
|
// ActivityStreamsAnnounce https://www.w3.org/TR/activitystreams-vocabulary/#dfn-announce
|
||||||
ActivityStreamsAnnounce ActivityStreamsActivity = "Announce"
|
ActivityStreamsAnnounce = "Announce"
|
||||||
// ActivityStreamsArrive https://www.w3.org/TR/activitystreams-vocabulary/#dfn-arrive
|
// ActivityStreamsArrive https://www.w3.org/TR/activitystreams-vocabulary/#dfn-arrive
|
||||||
ActivityStreamsArrive ActivityStreamsActivity = "Arrive"
|
ActivityStreamsArrive = "Arrive"
|
||||||
// ActivityStreamsBlock https://www.w3.org/TR/activitystreams-vocabulary/#dfn-block
|
// ActivityStreamsBlock https://www.w3.org/TR/activitystreams-vocabulary/#dfn-block
|
||||||
ActivityStreamsBlock ActivityStreamsActivity = "Block"
|
ActivityStreamsBlock = "Block"
|
||||||
// ActivityStreamsCreate https://www.w3.org/TR/activitystreams-vocabulary/#dfn-create
|
// ActivityStreamsCreate https://www.w3.org/TR/activitystreams-vocabulary/#dfn-create
|
||||||
ActivityStreamsCreate ActivityStreamsActivity = "Create"
|
ActivityStreamsCreate = "Create"
|
||||||
// ActivityStreamsDelete https://www.w3.org/TR/activitystreams-vocabulary/#dfn-delete
|
// ActivityStreamsDelete https://www.w3.org/TR/activitystreams-vocabulary/#dfn-delete
|
||||||
ActivityStreamsDelete ActivityStreamsActivity = "Delete"
|
ActivityStreamsDelete = "Delete"
|
||||||
// ActivityStreamsDislike https://www.w3.org/TR/activitystreams-vocabulary/#dfn-dislike
|
// ActivityStreamsDislike https://www.w3.org/TR/activitystreams-vocabulary/#dfn-dislike
|
||||||
ActivityStreamsDislike ActivityStreamsActivity = "Dislike"
|
ActivityStreamsDislike = "Dislike"
|
||||||
// ActivityStreamsFlag https://www.w3.org/TR/activitystreams-vocabulary/#dfn-flag
|
// ActivityStreamsFlag https://www.w3.org/TR/activitystreams-vocabulary/#dfn-flag
|
||||||
ActivityStreamsFlag ActivityStreamsActivity = "Flag"
|
ActivityStreamsFlag = "Flag"
|
||||||
// ActivityStreamsFollow https://www.w3.org/TR/activitystreams-vocabulary/#dfn-follow
|
// ActivityStreamsFollow https://www.w3.org/TR/activitystreams-vocabulary/#dfn-follow
|
||||||
ActivityStreamsFollow ActivityStreamsActivity = "Follow"
|
ActivityStreamsFollow = "Follow"
|
||||||
// ActivityStreamsIgnore https://www.w3.org/TR/activitystreams-vocabulary/#dfn-ignore
|
// ActivityStreamsIgnore https://www.w3.org/TR/activitystreams-vocabulary/#dfn-ignore
|
||||||
ActivityStreamsIgnore ActivityStreamsActivity = "Ignore"
|
ActivityStreamsIgnore = "Ignore"
|
||||||
// ActivityStreamsInvite https://www.w3.org/TR/activitystreams-vocabulary/#dfn-invite
|
// ActivityStreamsInvite https://www.w3.org/TR/activitystreams-vocabulary/#dfn-invite
|
||||||
ActivityStreamsInvite ActivityStreamsActivity = "Invite"
|
ActivityStreamsInvite = "Invite"
|
||||||
// ActivityStreamsJoin https://www.w3.org/TR/activitystreams-vocabulary/#dfn-join
|
// ActivityStreamsJoin https://www.w3.org/TR/activitystreams-vocabulary/#dfn-join
|
||||||
ActivityStreamsJoin ActivityStreamsActivity = "Join"
|
ActivityStreamsJoin = "Join"
|
||||||
// ActivityStreamsLeave https://www.w3.org/TR/activitystreams-vocabulary/#dfn-leave
|
// ActivityStreamsLeave https://www.w3.org/TR/activitystreams-vocabulary/#dfn-leave
|
||||||
ActivityStreamsLeave ActivityStreamsActivity = "Leave"
|
ActivityStreamsLeave = "Leave"
|
||||||
// ActivityStreamsLike https://www.w3.org/TR/activitystreams-vocabulary/#dfn-like
|
// ActivityStreamsLike https://www.w3.org/TR/activitystreams-vocabulary/#dfn-like
|
||||||
ActivityStreamsLike ActivityStreamsActivity = "Like"
|
ActivityStreamsLike = "Like"
|
||||||
// ActivityStreamsListen https://www.w3.org/TR/activitystreams-vocabulary/#dfn-listen
|
// ActivityStreamsListen https://www.w3.org/TR/activitystreams-vocabulary/#dfn-listen
|
||||||
ActivityStreamsListen ActivityStreamsActivity = "Listen"
|
ActivityStreamsListen = "Listen"
|
||||||
// ActivityStreamsMove https://www.w3.org/TR/activitystreams-vocabulary/#dfn-move
|
// ActivityStreamsMove https://www.w3.org/TR/activitystreams-vocabulary/#dfn-move
|
||||||
ActivityStreamsMove ActivityStreamsActivity = "Move"
|
ActivityStreamsMove = "Move"
|
||||||
// ActivityStreamsOffer https://www.w3.org/TR/activitystreams-vocabulary/#dfn-offer
|
// ActivityStreamsOffer https://www.w3.org/TR/activitystreams-vocabulary/#dfn-offer
|
||||||
ActivityStreamsOffer ActivityStreamsActivity = "Offer"
|
ActivityStreamsOffer = "Offer"
|
||||||
// ActivityStreamsQuestion https://www.w3.org/TR/activitystreams-vocabulary/#dfn-question
|
// ActivityStreamsQuestion https://www.w3.org/TR/activitystreams-vocabulary/#dfn-question
|
||||||
ActivityStreamsQuestion ActivityStreamsActivity = "Question"
|
ActivityStreamsQuestion = "Question"
|
||||||
// ActivityStreamsReject https://www.w3.org/TR/activitystreams-vocabulary/#dfn-reject
|
// ActivityStreamsReject https://www.w3.org/TR/activitystreams-vocabulary/#dfn-reject
|
||||||
ActivityStreamsReject ActivityStreamsActivity = "Reject"
|
ActivityStreamsReject = "Reject"
|
||||||
// ActivityStreamsRead https://www.w3.org/TR/activitystreams-vocabulary/#dfn-read
|
// ActivityStreamsRead https://www.w3.org/TR/activitystreams-vocabulary/#dfn-read
|
||||||
ActivityStreamsRead ActivityStreamsActivity = "Read"
|
ActivityStreamsRead = "Read"
|
||||||
// ActivityStreamsRemove https://www.w3.org/TR/activitystreams-vocabulary/#dfn-remove
|
// ActivityStreamsRemove https://www.w3.org/TR/activitystreams-vocabulary/#dfn-remove
|
||||||
ActivityStreamsRemove ActivityStreamsActivity = "Remove"
|
ActivityStreamsRemove = "Remove"
|
||||||
// ActivityStreamsTentativeReject https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tentativereject
|
// ActivityStreamsTentativeReject https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tentativereject
|
||||||
ActivityStreamsTentativeReject ActivityStreamsActivity = "TentativeReject"
|
ActivityStreamsTentativeReject = "TentativeReject"
|
||||||
// ActivityStreamsTentativeAccept https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tentativeaccept
|
// ActivityStreamsTentativeAccept https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tentativeaccept
|
||||||
ActivityStreamsTentativeAccept ActivityStreamsActivity = "TentativeAccept"
|
ActivityStreamsTentativeAccept = "TentativeAccept"
|
||||||
// ActivityStreamsTravel https://www.w3.org/TR/activitystreams-vocabulary/#dfn-travel
|
// ActivityStreamsTravel https://www.w3.org/TR/activitystreams-vocabulary/#dfn-travel
|
||||||
ActivityStreamsTravel ActivityStreamsActivity = "Travel"
|
ActivityStreamsTravel = "Travel"
|
||||||
// ActivityStreamsUndo https://www.w3.org/TR/activitystreams-vocabulary/#dfn-undo
|
// ActivityStreamsUndo https://www.w3.org/TR/activitystreams-vocabulary/#dfn-undo
|
||||||
ActivityStreamsUndo ActivityStreamsActivity = "Undo"
|
ActivityStreamsUndo = "Undo"
|
||||||
// ActivityStreamsUpdate https://www.w3.org/TR/activitystreams-vocabulary/#dfn-update
|
// ActivityStreamsUpdate https://www.w3.org/TR/activitystreams-vocabulary/#dfn-update
|
||||||
ActivityStreamsUpdate ActivityStreamsActivity = "Update"
|
ActivityStreamsUpdate = "Update"
|
||||||
// ActivityStreamsView https://www.w3.org/TR/activitystreams-vocabulary/#dfn-view
|
// ActivityStreamsView https://www.w3.org/TR/activitystreams-vocabulary/#dfn-view
|
||||||
ActivityStreamsView ActivityStreamsActivity = "View"
|
ActivityStreamsView = "View"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ package gtsmodel
|
||||||
|
|
||||||
// FromClientAPI wraps a message that travels from client API into the processor
|
// FromClientAPI wraps a message that travels from client API into the processor
|
||||||
type FromClientAPI struct {
|
type FromClientAPI struct {
|
||||||
APObjectType ActivityStreamsObject
|
APObjectType string
|
||||||
APActivityType ActivityStreamsActivity
|
APActivityType string
|
||||||
GTSModel interface{}
|
GTSModel interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -23,8 +23,8 @@ type FromClientAPI struct {
|
||||||
|
|
||||||
// FromFederator wraps a message that travels from the federator into the processor
|
// FromFederator wraps a message that travels from the federator into the processor
|
||||||
type FromFederator struct {
|
type FromFederator struct {
|
||||||
APObjectType ActivityStreamsObject
|
APObjectType string
|
||||||
APActivityType ActivityStreamsActivity
|
APActivityType string
|
||||||
GTSModel interface{}
|
GTSModel interface{}
|
||||||
ReceivingAccount *Account
|
ReceivingAccount *Account
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ type Status struct {
|
||||||
VisibilityAdvanced *VisibilityAdvanced
|
VisibilityAdvanced *VisibilityAdvanced
|
||||||
// What is the activitystreams type of this status? See: https://www.w3.org/TR/activitystreams-vocabulary/#object-types
|
// What is the activitystreams type of this status? See: https://www.w3.org/TR/activitystreams-vocabulary/#object-types
|
||||||
// Will probably almost always be Note but who knows!.
|
// Will probably almost always be Note but who knows!.
|
||||||
ActivityStreamsType ActivityStreamsObject
|
ActivityStreamsType string
|
||||||
// Original text of the status without formatting
|
// Original text of the status without formatting
|
||||||
Text string
|
Text string
|
||||||
// Has this status been pinned by its owner?
|
// Has this status been pinned by its owner?
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ func (c *converter) ASRepresentationToAccount(accountable Accountable) (*gtsmode
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for bot and actor type
|
// check for bot and actor type
|
||||||
switch gtsmodel.ActivityStreamsActor(accountable.GetTypeName()) {
|
switch accountable.GetTypeName() {
|
||||||
case gtsmodel.ActivityStreamsPerson, gtsmodel.ActivityStreamsGroup, gtsmodel.ActivityStreamsOrganization:
|
case gtsmodel.ActivityStreamsPerson, gtsmodel.ActivityStreamsGroup, gtsmodel.ActivityStreamsOrganization:
|
||||||
// people, groups, and organizations aren't bots
|
// people, groups, and organizations aren't bots
|
||||||
acct.Bot = false
|
acct.Bot = false
|
||||||
|
|
@ -101,7 +101,7 @@ func (c *converter) ASRepresentationToAccount(accountable Accountable) (*gtsmode
|
||||||
// we don't know what this is!
|
// we don't know what this is!
|
||||||
return nil, fmt.Errorf("type name %s not recognised or not convertible to gtsmodel.ActivityStreamsActor", accountable.GetTypeName())
|
return nil, fmt.Errorf("type name %s not recognised or not convertible to gtsmodel.ActivityStreamsActor", accountable.GetTypeName())
|
||||||
}
|
}
|
||||||
acct.ActorType = gtsmodel.ActivityStreamsActor(accountable.GetTypeName())
|
acct.ActorType = accountable.GetTypeName()
|
||||||
|
|
||||||
// TODO: locked aka manuallyApprovesFollowers
|
// TODO: locked aka manuallyApprovesFollowers
|
||||||
|
|
||||||
|
|
@ -281,7 +281,10 @@ func (c *converter) ASStatusToStatus(statusable Statusable) (*gtsmodel.Status, e
|
||||||
|
|
||||||
// if it's CC'ed to public, it's public or unlocked
|
// if it's CC'ed to public, it's public or unlocked
|
||||||
// mentioned SPECIFIC ACCOUNTS also get added to CC'es if it's not a direct message
|
// mentioned SPECIFIC ACCOUNTS also get added to CC'es if it's not a direct message
|
||||||
if isPublic(cc) || isPublic(to) {
|
if isPublic(cc) {
|
||||||
|
visibility = gtsmodel.VisibilityUnlocked
|
||||||
|
}
|
||||||
|
if isPublic(to) {
|
||||||
visibility = gtsmodel.VisibilityPublic
|
visibility = gtsmodel.VisibilityPublic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -301,7 +304,7 @@ func (c *converter) ASStatusToStatus(statusable Statusable) (*gtsmodel.Status, e
|
||||||
// we might be able to extract this from the contentMap field
|
// we might be able to extract this from the contentMap field
|
||||||
|
|
||||||
// ActivityStreamsType
|
// ActivityStreamsType
|
||||||
status.ActivityStreamsType = gtsmodel.ActivityStreamsObject(statusable.GetTypeName())
|
status.ActivityStreamsType = statusable.GetTypeName()
|
||||||
|
|
||||||
return status, nil
|
return status, nil
|
||||||
}
|
}
|
||||||
|
|
@ -341,6 +344,40 @@ func (c *converter) ASFollowToFollowRequest(followable Followable) (*gtsmodel.Fo
|
||||||
return followRequest, nil
|
return followRequest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *converter) ASFollowToFollow(followable Followable) (*gtsmodel.Follow, error) {
|
||||||
|
idProp := followable.GetJSONLDId()
|
||||||
|
if idProp == nil || !idProp.IsIRI() {
|
||||||
|
return nil, errors.New("no id property set on follow, or was not an iri")
|
||||||
|
}
|
||||||
|
uri := idProp.GetIRI().String()
|
||||||
|
|
||||||
|
origin, err := extractActor(followable)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("error extracting actor property from follow")
|
||||||
|
}
|
||||||
|
originAccount := >smodel.Account{}
|
||||||
|
if err := c.db.GetWhere("uri", origin.String(), originAccount); err != nil {
|
||||||
|
return nil, fmt.Errorf("error extracting account with uri %s from the database: %s", origin.String(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
target, err := extractObject(followable)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("error extracting object property from follow")
|
||||||
|
}
|
||||||
|
targetAccount := >smodel.Account{}
|
||||||
|
if err := c.db.GetWhere("uri", target.String(), targetAccount); err != nil {
|
||||||
|
return nil, fmt.Errorf("error extracting account with uri %s from the database: %s", origin.String(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
follow := >smodel.Follow{
|
||||||
|
URI: uri,
|
||||||
|
AccountID: originAccount.ID,
|
||||||
|
TargetAccountID: targetAccount.ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
return follow, nil
|
||||||
|
}
|
||||||
|
|
||||||
func isPublic(tos []*url.URL) bool {
|
func isPublic(tos []*url.URL) bool {
|
||||||
for _, entry := range tos {
|
for _, entry := range tos {
|
||||||
if strings.EqualFold(entry.String(), "https://www.w3.org/ns/activitystreams#Public") {
|
if strings.EqualFold(entry.String(), "https://www.w3.org/ns/activitystreams#Public") {
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,9 @@ type TypeConverter interface {
|
||||||
ASStatusToStatus(statusable Statusable) (*gtsmodel.Status, error)
|
ASStatusToStatus(statusable Statusable) (*gtsmodel.Status, error)
|
||||||
// ASFollowToFollowRequest converts a remote activitystreams `follow` representation into gts model follow request.
|
// ASFollowToFollowRequest converts a remote activitystreams `follow` representation into gts model follow request.
|
||||||
ASFollowToFollowRequest(followable Followable) (*gtsmodel.FollowRequest, error)
|
ASFollowToFollowRequest(followable Followable) (*gtsmodel.FollowRequest, error)
|
||||||
|
// ASFollowToFollowRequest converts a remote activitystreams `follow` representation into gts model follow.
|
||||||
|
ASFollowToFollow(followable Followable) (*gtsmodel.Follow, error)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
INTERNAL (gts) MODEL TO ACTIVITYSTREAMS MODEL
|
INTERNAL (gts) MODEL TO ACTIVITYSTREAMS MODEL
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ import (
|
||||||
var Run action.GTSAction = func(ctx context.Context, _ *config.Config, log *logrus.Logger) error {
|
var Run action.GTSAction = func(ctx context.Context, _ *config.Config, log *logrus.Logger) error {
|
||||||
c := NewTestConfig()
|
c := NewTestConfig()
|
||||||
dbService := NewTestDB()
|
dbService := NewTestDB()
|
||||||
|
federatingDB := NewTestFederatingDB(dbService)
|
||||||
router := NewTestRouter()
|
router := NewTestRouter()
|
||||||
storageBackend := NewTestStorage()
|
storageBackend := NewTestStorage()
|
||||||
|
|
||||||
|
|
@ -59,7 +60,7 @@ var Run action.GTSAction = func(ctx context.Context, _ *config.Config, log *logr
|
||||||
Body: r,
|
Body: r,
|
||||||
}, nil
|
}, nil
|
||||||
}))
|
}))
|
||||||
federator := federation.NewFederator(dbService, transportController, c, log, typeConverter)
|
federator := federation.NewFederator(dbService, federatingDB, transportController, c, log, typeConverter)
|
||||||
processor := NewTestProcessor(dbService, storageBackend, federator)
|
processor := NewTestProcessor(dbService, storageBackend, federator)
|
||||||
if err := processor.Start(); err != nil {
|
if err := processor.Start(); err != nil {
|
||||||
return fmt.Errorf("error starting processor: %s", err)
|
return fmt.Errorf("error starting processor: %s", err)
|
||||||
|
|
|
||||||
11
testrig/federatingdb.go
Normal file
11
testrig/federatingdb.go
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
package testrig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||||
|
"github.com/superseriousbusiness/gotosocial/internal/federation"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewTestFederatingDB returns a federating DB with the underlying db
|
||||||
|
func NewTestFederatingDB(db db.DB) federation.FederatingDB {
|
||||||
|
return federation.NewFederatingDB(db, NewTestConfig(), NewTestLog())
|
||||||
|
}
|
||||||
|
|
@ -26,5 +26,5 @@ import (
|
||||||
|
|
||||||
// NewTestFederator returns a federator with the given database and (mock!!) transport controller.
|
// NewTestFederator returns a federator with the given database and (mock!!) transport controller.
|
||||||
func NewTestFederator(db db.DB, tc transport.Controller) federation.Federator {
|
func NewTestFederator(db db.DB, tc transport.Controller) federation.Federator {
|
||||||
return federation.NewFederator(db, tc, NewTestConfig(), NewTestLog(), NewTestTypeConverter(db))
|
return federation.NewFederator(db, NewTestFederatingDB(db), tc, NewTestConfig(), NewTestLog(), NewTestTypeConverter(db))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue