summaryrefslogtreecommitdiff
path: root/internal/db
diff options
context:
space:
mode:
authorLibravatar Tobi Smethurst <31960611+tsmethurst@users.noreply.github.com>2021-05-15 11:58:11 +0200
committerLibravatar GitHub <noreply@github.com>2021-05-15 11:58:11 +0200
commitcc48294c31a76e94fa879ad0d8d5dbd7e94c651b (patch)
tree7c26d33b41bab33bbdfbba540958444f4c296602 /internal/db
parentMediahandler (#21) (diff)
downloadgotosocial-cc48294c31a76e94fa879ad0d8d5dbd7e94c651b.tar.xz
Inbox post (#22)
Inbox POST from federated servers now working for statuses and follow requests. Follow request client API added. Start work on federating outgoing messages. Other fixes and changes/tidying up.
Diffstat (limited to 'internal/db')
-rw-r--r--internal/db/db.go14
-rw-r--r--internal/db/federating_db.go359
-rw-r--r--internal/db/federating_db_test.go21
-rw-r--r--internal/db/pg/pg.go (renamed from internal/db/pg.go)94
-rw-r--r--internal/db/pg_test.go21
5 files changed, 79 insertions, 430 deletions
diff --git a/internal/db/db.go b/internal/db/db.go
index b281dd8d7..a354ddee8 100644
--- a/internal/db/db.go
+++ b/internal/db/db.go
@@ -26,7 +26,10 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
)
-const DBTypePostgres string = "POSTGRES"
+const (
+ // DBTypePostgres represents an underlying POSTGRES database type.
+ DBTypePostgres string = "POSTGRES"
+)
// ErrNoEntries is to be returned from the DB interface when no entries are found for a given query.
type ErrNoEntries struct{}
@@ -112,6 +115,10 @@ type DB interface {
HANDY SHORTCUTS
*/
+ // AcceptFollowRequest moves a follow request in the database from the follow_requests table to the follows table.
+ // In other words, it should create the follow, and delete the existing follow request.
+ AcceptFollowRequest(originAccountID string, targetAccountID string) error
+
// CreateInstanceAccount creates an account in the database with the same username as the instance host value.
// Ie., if the instance is hosted at 'example.org' the instance user will have a username of 'example.org'.
// This is needed for things like serving files that belong to the instance and not an individual user/account.
@@ -148,6 +155,11 @@ type DB interface {
// In case of no entries, a 'no entries' error will be returned
GetFollowersByAccountID(accountID string, followers *[]gtsmodel.Follow) error
+ // GetFavesByAccountID is a shortcut for the common action of fetching a list of faves made by the given accountID.
+ // The given slice 'faves' will be set to the result of the query, whatever it is.
+ // In case of no entries, a 'no entries' error will be returned
+ GetFavesByAccountID(accountID string, faves *[]gtsmodel.StatusFave) error
+
// GetStatusesByAccountID is a shortcut for the common action of fetching a list of statuses produced by accountID.
// The given slice 'statuses' will be set to the result of the query, whatever it is.
// In case of no entries, a 'no entries' error will be returned
diff --git a/internal/db/federating_db.go b/internal/db/federating_db.go
deleted file mode 100644
index ab66b19de..000000000
--- a/internal/db/federating_db.go
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- 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 db
-
-import (
- "context"
- "errors"
- "fmt"
- "net/url"
- "sync"
-
- "github.com/go-fed/activity/pub"
- "github.com/go-fed/activity/streams/vocab"
- "github.com/sirupsen/logrus"
- "github.com/superseriousbusiness/gotosocial/internal/config"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
- "github.com/superseriousbusiness/gotosocial/internal/util"
-)
-
-// 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.
-type federatingDB struct {
- locks *sync.Map
- db DB
- config *config.Config
- log *logrus.Logger
-}
-
-func NewFederatingDB(db DB, config *config.Config, log *logrus.Logger) pub.Database {
- return &federatingDB{
- locks: new(sync.Map),
- db: db,
- config: config,
- log: log,
- }
-}
-
-/*
- GO-FED DB INTERFACE-IMPLEMENTING FUNCTIONS
-*/
-
-// Lock takes a lock for the object at the specified id. If an error
-// is returned, the lock must not have been taken.
-//
-// The lock must be able to succeed for an id that does not exist in
-// the database. This means acquiring the lock does not guarantee the
-// entry exists in the database.
-//
-// Locks are encouraged to be lightweight and in the Go layer, as some
-// processes require tight loops acquiring and releasing locks.
-//
-// Used to ensure race conditions in multiple requests do not occur.
-func (f *federatingDB) Lock(c context.Context, id *url.URL) error {
- // Before any other Database methods are called, the relevant `id`
- // entries are locked to allow for fine-grained concurrency.
-
- // Strategy: create a new lock, if stored, continue. Otherwise, lock the
- // existing mutex.
- mu := &sync.Mutex{}
- mu.Lock() // Optimistically lock if we do store it.
- i, loaded := f.locks.LoadOrStore(id.String(), mu)
- if loaded {
- mu = i.(*sync.Mutex)
- mu.Lock()
- }
- return nil
-}
-
-// Unlock makes the lock for the object at the specified id available.
-// If an error is returned, the lock must have still been freed.
-//
-// Used to ensure race conditions in multiple requests do not occur.
-func (f *federatingDB) Unlock(c context.Context, id *url.URL) error {
- // Once Go-Fed is done calling Database methods, the relevant `id`
- // entries are unlocked.
-
- i, ok := f.locks.Load(id.String())
- if !ok {
- return errors.New("missing an id in unlock")
- }
- mu := i.(*sync.Mutex)
- mu.Unlock()
- return nil
-}
-
-// InboxContains returns true if the OrderedCollection at 'inbox'
-// contains the specified 'id'.
-//
-// The library makes this call only after acquiring a lock first.
-func (f *federatingDB) InboxContains(c context.Context, inbox, id *url.URL) (contains bool, err error) {
-
- if !util.IsInboxPath(inbox) {
- return false, fmt.Errorf("%s is not an inbox URI", inbox.String())
- }
-
- if !util.IsStatusesPath(id) {
- return false, fmt.Errorf("%s is not a status URI", id.String())
- }
- _, statusID, err := util.ParseStatusesPath(inbox)
- if err != nil {
- return false, fmt.Errorf("status URI %s was not parseable: %s", id.String(), err)
- }
-
- if err := f.db.GetByID(statusID, &gtsmodel.Status{}); err != nil {
- if _, ok := err.(ErrNoEntries); ok {
- // we don't have it
- return false, nil
- }
- // actual error
- return false, fmt.Errorf("error getting status from db: %s", err)
- }
-
- // we must have it
- return true, nil
-}
-
-// GetInbox 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.
-func (f *federatingDB) GetInbox(c context.Context, inboxIRI *url.URL) (inbox vocab.ActivityStreamsOrderedCollectionPage, err error) {
- return nil, nil
-}
-
-// SetInbox saves the inbox value given from GetInbox, with new items
-// prepended. Note that the new items must not be added as independent
-// database entries. Separate calls to Create will do that.
-//
-// The library makes this call only after acquiring a lock first.
-func (f *federatingDB) SetInbox(c context.Context, inbox vocab.ActivityStreamsOrderedCollectionPage) error {
- return nil
-}
-
-// Owns returns true if the IRI belongs to this instance, and if
-// the database has an entry for the IRI.
-// The library makes this call only after acquiring a lock first.
-func (f *federatingDB) Owns(c context.Context, id *url.URL) (bool, error) {
- // if the id host isn't this instance host, we don't own this IRI
- if id.Host != f.config.Host {
- return false, nil
- }
-
- // apparently we own it, so what *is* it?
-
- // check if it's a status, eg /users/example_username/statuses/SOME_UUID_OF_A_STATUS
- if util.IsStatusesPath(id) {
- _, uid, err := util.ParseStatusesPath(id)
- if err != nil {
- return false, fmt.Errorf("error parsing statuses path for url %s: %s", id.String(), err)
- }
- if err := f.db.GetWhere("uri", uid, &gtsmodel.Status{}); err != nil {
- if _, ok := err.(ErrNoEntries); ok {
- // there are no entries for this status
- return false, nil
- }
- // an actual error happened
- return false, fmt.Errorf("database error fetching status with id %s: %s", uid, err)
- }
- return true, nil
- }
-
- // check if it's a user, eg /users/example_username
- if util.IsUserPath(id) {
- username, err := util.ParseUserPath(id)
- if err != nil {
- return false, fmt.Errorf("error parsing statuses path for url %s: %s", id.String(), err)
- }
- if err := f.db.GetLocalAccountByUsername(username, &gtsmodel.Account{}); err != nil {
- if _, ok := err.(ErrNoEntries); ok {
- // there are no entries for this username
- return false, nil
- }
- // an actual error happened
- return false, fmt.Errorf("database error fetching account with username %s: %s", username, err)
- }
- return true, nil
- }
-
- return false, fmt.Errorf("could not match activityID: %s", id.String())
-}
-
-// ActorForOutbox fetches the actor's IRI for the given outbox IRI.
-//
-// The library makes this call only after acquiring a lock first.
-func (f *federatingDB) ActorForOutbox(c context.Context, outboxIRI *url.URL) (actorIRI *url.URL, err error) {
- if !util.IsOutboxPath(outboxIRI) {
- return nil, fmt.Errorf("%s is not an outbox URI", outboxIRI.String())
- }
- acct := &gtsmodel.Account{}
- if err := f.db.GetWhere("outbox_uri", outboxIRI.String(), acct); err != nil {
- if _, ok := err.(ErrNoEntries); ok {
- 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())
- }
- return url.Parse(acct.URI)
-}
-
-// ActorForInbox fetches the actor's IRI for the given outbox IRI.
-//
-// The library makes this call only after acquiring a lock first.
-func (f *federatingDB) ActorForInbox(c context.Context, inboxIRI *url.URL) (actorIRI *url.URL, err error) {
- if !util.IsInboxPath(inboxIRI) {
- return nil, fmt.Errorf("%s is not an inbox URI", inboxIRI.String())
- }
- acct := &gtsmodel.Account{}
- if err := f.db.GetWhere("inbox_uri", inboxIRI.String(), acct); err != nil {
- if _, ok := err.(ErrNoEntries); ok {
- 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())
- }
- return url.Parse(acct.URI)
-}
-
-// OutboxForInbox fetches the corresponding actor's outbox IRI for the
-// actor's inbox IRI.
-//
-// The library makes this call only after acquiring a lock first.
-func (f *federatingDB) OutboxForInbox(c context.Context, inboxIRI *url.URL) (outboxIRI *url.URL, err error) {
- if !util.IsInboxPath(inboxIRI) {
- return nil, fmt.Errorf("%s is not an inbox URI", inboxIRI.String())
- }
- acct := &gtsmodel.Account{}
- if err := f.db.GetWhere("inbox_uri", inboxIRI.String(), acct); err != nil {
- if _, ok := err.(ErrNoEntries); ok {
- 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())
- }
- return url.Parse(acct.OutboxURI)
-}
-
-// Exists returns true if the database has an entry for the specified
-// id. It may not be owned by this application instance.
-//
-// The library makes this call only after acquiring a lock first.
-func (f *federatingDB) Exists(c context.Context, id *url.URL) (exists bool, err error) {
- return false, nil
-}
-
-// Get returns the database entry for the specified id.
-//
-// The library makes this call only after acquiring a lock first.
-func (f *federatingDB) Get(c context.Context, id *url.URL) (value vocab.Type, err error) {
- return nil, nil
-}
-
-// Create adds a new entry to the database which must be able to be
-// keyed by its id.
-//
-// Note that Activity values received from federated peers may also be
-// created in the database this way if the Federating Protocol is
-// enabled. The client may freely decide to store only the id instead of
-// the entire value.
-//
-// The library makes this call only after acquiring a lock first.
-//
-// Under certain conditions and network activities, Create may be called
-// multiple times for the same ActivityStreams object.
-func (f *federatingDB) Create(c context.Context, asType vocab.Type) error {
- return nil
-}
-
-// Update sets an existing entry to the database based on the value's
-// id.
-//
-// Note that Activity values received from federated peers may also be
-// updated in the database this way if the Federating Protocol is
-// enabled. The client may freely decide to store only the id instead of
-// the entire value.
-//
-// The library makes this call only after acquiring a lock first.
-func (f *federatingDB) Update(c context.Context, asType vocab.Type) error {
- return nil
-}
-
-// Delete removes the entry with the given id.
-//
-// Delete is only called for federated objects. Deletes from the Social
-// Protocol instead call Update to create a Tombstone.
-//
-// The library makes this call only after acquiring a lock first.
-func (f *federatingDB) Delete(c context.Context, id *url.URL) error {
- return nil
-}
-
-// 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.
-func (f *federatingDB) GetOutbox(c context.Context, outboxIRI *url.URL) (inbox vocab.ActivityStreamsOrderedCollectionPage, err error) {
- return nil, nil
-}
-
-// SetOutbox saves the outbox value given from GetOutbox, with new items
-// prepended. Note that the new items must not be added as independent
-// database entries. Separate calls to Create will do that.
-//
-// The library makes this call only after acquiring a lock first.
-func (f *federatingDB) SetOutbox(c context.Context, outbox vocab.ActivityStreamsOrderedCollectionPage) error {
- return nil
-}
-
-// NewID creates a new IRI id for the provided activity or object. The
-// implementation does not need to set the 'id' property and simply
-// needs to determine the value.
-//
-// The go-fed library will handle setting the 'id' property on the
-// activity or object provided with the value returned.
-func (f *federatingDB) NewID(c context.Context, t vocab.Type) (id *url.URL, err error) {
- return nil, nil
-}
-
-// Followers obtains the Followers Collection for an actor with the
-// given id.
-//
-// If modified, the library will then call Update.
-//
-// The library makes this call only after acquiring a lock first.
-func (f *federatingDB) Followers(c context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error) {
- return nil, nil
-}
-
-// Following obtains the Following Collection for an actor with the
-// given id.
-//
-// If modified, the library will then call Update.
-//
-// The library makes this call only after acquiring a lock first.
-func (f *federatingDB) Following(c context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error) {
- return nil, nil
-}
-
-// Liked obtains the Liked Collection for an actor with the
-// given id.
-//
-// If modified, the library will then call Update.
-//
-// The library makes this call only after acquiring a lock first.
-func (f *federatingDB) Liked(c context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error) {
- return nil, nil
-}
diff --git a/internal/db/federating_db_test.go b/internal/db/federating_db_test.go
deleted file mode 100644
index 529d2efd0..000000000
--- a/internal/db/federating_db_test.go
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- 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 db
-
-// TODO: write tests for pgfed
diff --git a/internal/db/pg.go b/internal/db/pg/pg.go
index c0fbcc9e0..f8c2fdbe8 100644
--- a/internal/db/pg.go
+++ b/internal/db/pg/pg.go
@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-package db
+package pg
import (
"context"
@@ -37,6 +37,8 @@ import (
"github.com/google/uuid"
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/config"
+ "github.com/superseriousbusiness/gotosocial/internal/db"
+ "github.com/superseriousbusiness/gotosocial/internal/federation"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/util"
"golang.org/x/crypto/bcrypt"
@@ -53,7 +55,7 @@ type postgresService struct {
// NewPostgresService returns a postgresService derived from the provided config, which implements the go-fed DB interface.
// Under the hood, it uses https://github.com/go-pg/pg to create and maintain a database connection.
-func NewPostgresService(ctx context.Context, c *config.Config, log *logrus.Logger) (DB, error) {
+func NewPostgresService(ctx context.Context, c *config.Config, log *logrus.Logger) (db.DB, error) {
opts, err := derivePGOptions(c)
if err != nil {
return nil, fmt.Errorf("could not create postgres service: %s", err)
@@ -95,7 +97,7 @@ func NewPostgresService(ctx context.Context, c *config.Config, log *logrus.Logge
cancel: cancel,
}
- federatingDB := NewFederatingDB(ps, c, log)
+ federatingDB := federation.NewFederatingDB(ps, c, log)
ps.federationDB = federatingDB
// we can confidently return this useable postgres service now
@@ -109,8 +111,8 @@ func NewPostgresService(ctx context.Context, c *config.Config, log *logrus.Logge
// derivePGOptions takes an application config and returns either a ready-to-use *pg.Options
// with sensible defaults, or an error if it's not satisfied by the provided config.
func derivePGOptions(c *config.Config) (*pg.Options, error) {
- if strings.ToUpper(c.DBConfig.Type) != DBTypePostgres {
- return nil, fmt.Errorf("expected db type of %s but got %s", DBTypePostgres, c.DBConfig.Type)
+ if strings.ToUpper(c.DBConfig.Type) != db.DBTypePostgres {
+ return nil, fmt.Errorf("expected db type of %s but got %s", db.DBTypePostgres, c.DBConfig.Type)
}
// validate port
@@ -219,7 +221,7 @@ func (ps *postgresService) CreateSchema(ctx context.Context) error {
func (ps *postgresService) GetByID(id string, i interface{}) error {
if err := ps.conn.Model(i).Where("id = ?", id).Select(); err != nil {
if err == pg.ErrNoRows {
- return ErrNoEntries{}
+ return db.ErrNoEntries{}
}
return err
@@ -230,7 +232,7 @@ func (ps *postgresService) GetByID(id string, i interface{}) error {
func (ps *postgresService) GetWhere(key string, value interface{}, i interface{}) error {
if err := ps.conn.Model(i).Where("? = ?", pg.Safe(key), value).Select(); err != nil {
if err == pg.ErrNoRows {
- return ErrNoEntries{}
+ return db.ErrNoEntries{}
}
return err
}
@@ -244,7 +246,7 @@ func (ps *postgresService) GetWhere(key string, value interface{}, i interface{}
func (ps *postgresService) GetAll(i interface{}) error {
if err := ps.conn.Model(i).Select(); err != nil {
if err == pg.ErrNoRows {
- return ErrNoEntries{}
+ return db.ErrNoEntries{}
}
return err
}
@@ -259,7 +261,7 @@ func (ps *postgresService) Put(i interface{}) error {
func (ps *postgresService) Upsert(i interface{}, conflictColumn string) error {
if _, err := ps.conn.Model(i).OnConflict(fmt.Sprintf("(%s) DO UPDATE", conflictColumn)).Insert(); err != nil {
if err == pg.ErrNoRows {
- return ErrNoEntries{}
+ return db.ErrNoEntries{}
}
return err
}
@@ -269,7 +271,7 @@ func (ps *postgresService) Upsert(i interface{}, conflictColumn string) error {
func (ps *postgresService) UpdateByID(id string, i interface{}) error {
if _, err := ps.conn.Model(i).Where("id = ?", id).OnConflict("(id) DO UPDATE").Insert(); err != nil {
if err == pg.ErrNoRows {
- return ErrNoEntries{}
+ return db.ErrNoEntries{}
}
return err
}
@@ -284,7 +286,7 @@ func (ps *postgresService) UpdateOneByID(id string, key string, value interface{
func (ps *postgresService) DeleteByID(id string, i interface{}) error {
if _, err := ps.conn.Model(i).Where("id = ?", id).Delete(); err != nil {
if err == pg.ErrNoRows {
- return ErrNoEntries{}
+ return db.ErrNoEntries{}
}
return err
}
@@ -294,7 +296,7 @@ func (ps *postgresService) DeleteByID(id string, 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 == pg.ErrNoRows {
- return ErrNoEntries{}
+ return db.ErrNoEntries{}
}
return err
}
@@ -305,6 +307,32 @@ func (ps *postgresService) DeleteWhere(key string, value interface{}, i interfac
HANDY SHORTCUTS
*/
+func (ps *postgresService) AcceptFollowRequest(originAccountID string, targetAccountID string) error {
+ fr := &gtsmodel.FollowRequest{}
+ if err := ps.conn.Model(fr).Where("account_id = ?", originAccountID).Where("target_account_id = ?", targetAccountID).Select(); err != nil {
+ if err == pg.ErrMultiRows {
+ return db.ErrNoEntries{}
+ }
+ return err
+ }
+
+ follow := &gtsmodel.Follow{
+ AccountID: originAccountID,
+ TargetAccountID: targetAccountID,
+ URI: fr.URI,
+ }
+
+ if _, err := ps.conn.Model(follow).Insert(); err != nil {
+ return err
+ }
+
+ if _, err := ps.conn.Model(&gtsmodel.FollowRequest{}).Where("account_id = ?", originAccountID).Where("target_account_id = ?", targetAccountID).Delete(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
func (ps *postgresService) CreateInstanceAccount() error {
username := ps.config.Host
key, err := rsa.GenerateKey(rand.Reader, 2048)
@@ -365,13 +393,13 @@ func (ps *postgresService) GetAccountByUserID(userID string, account *gtsmodel.A
}
if err := ps.conn.Model(user).Where("id = ?", userID).Select(); err != nil {
if err == pg.ErrNoRows {
- return ErrNoEntries{}
+ return db.ErrNoEntries{}
}
return err
}
if err := ps.conn.Model(account).Where("id = ?", user.AccountID).Select(); err != nil {
if err == pg.ErrNoRows {
- return ErrNoEntries{}
+ return db.ErrNoEntries{}
}
return err
}
@@ -381,7 +409,7 @@ func (ps *postgresService) GetAccountByUserID(userID string, account *gtsmodel.A
func (ps *postgresService) GetLocalAccountByUsername(username string, account *gtsmodel.Account) error {
if err := ps.conn.Model(account).Where("username = ?", username).Where("? IS NULL", pg.Ident("domain")).Select(); err != nil {
if err == pg.ErrNoRows {
- return ErrNoEntries{}
+ return db.ErrNoEntries{}
}
return err
}
@@ -391,7 +419,7 @@ func (ps *postgresService) GetLocalAccountByUsername(username string, account *g
func (ps *postgresService) GetFollowRequestsForAccountID(accountID string, followRequests *[]gtsmodel.FollowRequest) error {
if err := ps.conn.Model(followRequests).Where("target_account_id = ?", accountID).Select(); err != nil {
if err == pg.ErrNoRows {
- return ErrNoEntries{}
+ return nil
}
return err
}
@@ -401,7 +429,7 @@ func (ps *postgresService) GetFollowRequestsForAccountID(accountID string, follo
func (ps *postgresService) GetFollowingByAccountID(accountID string, following *[]gtsmodel.Follow) error {
if err := ps.conn.Model(following).Where("account_id = ?", accountID).Select(); err != nil {
if err == pg.ErrNoRows {
- return ErrNoEntries{}
+ return nil
}
return err
}
@@ -411,7 +439,17 @@ func (ps *postgresService) GetFollowingByAccountID(accountID string, following *
func (ps *postgresService) GetFollowersByAccountID(accountID string, followers *[]gtsmodel.Follow) error {
if err := ps.conn.Model(followers).Where("target_account_id = ?", accountID).Select(); err != nil {
if err == pg.ErrNoRows {
- return ErrNoEntries{}
+ return nil
+ }
+ return err
+ }
+ return nil
+}
+
+func (ps *postgresService) GetFavesByAccountID(accountID string, faves *[]gtsmodel.StatusFave) error {
+ if err := ps.conn.Model(faves).Where("account_id = ?", accountID).Select(); err != nil {
+ if err == pg.ErrNoRows {
+ return nil
}
return err
}
@@ -421,7 +459,7 @@ func (ps *postgresService) GetFollowersByAccountID(accountID string, followers *
func (ps *postgresService) GetStatusesByAccountID(accountID string, statuses *[]gtsmodel.Status) error {
if err := ps.conn.Model(statuses).Where("account_id = ?", accountID).Select(); err != nil {
if err == pg.ErrNoRows {
- return ErrNoEntries{}
+ return db.ErrNoEntries{}
}
return err
}
@@ -438,7 +476,7 @@ func (ps *postgresService) GetStatusesByTimeDescending(accountID string, statuse
}
if err := q.Select(); err != nil {
if err == pg.ErrNoRows {
- return ErrNoEntries{}
+ return db.ErrNoEntries{}
}
return err
}
@@ -448,7 +486,7 @@ func (ps *postgresService) GetStatusesByTimeDescending(accountID string, statuse
func (ps *postgresService) GetLastStatusForAccountID(accountID string, status *gtsmodel.Status) error {
if err := ps.conn.Model(status).Order("created_at DESC").Limit(1).Where("account_id = ?", accountID).Select(); err != nil {
if err == pg.ErrNoRows {
- return ErrNoEntries{}
+ return db.ErrNoEntries{}
}
return err
}
@@ -574,18 +612,18 @@ func (ps *postgresService) GetHeaderForAccountID(header *gtsmodel.MediaAttachmen
acct := &gtsmodel.Account{}
if err := ps.conn.Model(acct).Where("id = ?", accountID).Select(); err != nil {
if err == pg.ErrNoRows {
- return ErrNoEntries{}
+ return db.ErrNoEntries{}
}
return err
}
if acct.HeaderMediaAttachmentID == "" {
- return ErrNoEntries{}
+ return db.ErrNoEntries{}
}
if err := ps.conn.Model(header).Where("id = ?", acct.HeaderMediaAttachmentID).Select(); err != nil {
if err == pg.ErrNoRows {
- return ErrNoEntries{}
+ return db.ErrNoEntries{}
}
return err
}
@@ -596,18 +634,18 @@ func (ps *postgresService) GetAvatarForAccountID(avatar *gtsmodel.MediaAttachmen
acct := &gtsmodel.Account{}
if err := ps.conn.Model(acct).Where("id = ?", accountID).Select(); err != nil {
if err == pg.ErrNoRows {
- return ErrNoEntries{}
+ return db.ErrNoEntries{}
}
return err
}
if acct.AvatarMediaAttachmentID == "" {
- return ErrNoEntries{}
+ return db.ErrNoEntries{}
}
if err := ps.conn.Model(avatar).Where("id = ?", acct.AvatarMediaAttachmentID).Select(); err != nil {
if err == pg.ErrNoRows {
- return ErrNoEntries{}
+ return db.ErrNoEntries{}
}
return err
}
@@ -645,7 +683,7 @@ func (ps *postgresService) StatusVisible(targetStatus *gtsmodel.Status, targetAc
if err := ps.conn.Model(targetUser).Where("account_id = ?", targetAccount.ID).Select(); err != nil {
l.Debug("target user could not be selected")
if err == pg.ErrNoRows {
- return false, ErrNoEntries{}
+ return false, db.ErrNoEntries{}
}
return false, err
}
diff --git a/internal/db/pg_test.go b/internal/db/pg_test.go
deleted file mode 100644
index a54784022..000000000
--- a/internal/db/pg_test.go
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- 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 db_test
-
-// TODO: write tests for postgres