summaryrefslogtreecommitdiff
path: root/internal/db/db.go
diff options
context:
space:
mode:
authorLibravatar Tobi Smethurst <31960611+tsmethurst@users.noreply.github.com>2021-04-01 20:46:45 +0200
committerLibravatar GitHub <noreply@github.com>2021-04-01 20:46:45 +0200
commit71a49e2b43218d34f97b2276c43bdeb2df4a53d2 (patch)
tree201c370b16cc5446740660f81f342e8171e9903f /internal/db/db.go
parentOauth/token (#7) (diff)
downloadgotosocial-71a49e2b43218d34f97b2276c43bdeb2df4a53d2.tar.xz
Api/v1/accounts (#8)
* start work on accounts module * plodding away on the accounts endpoint * groundwork for other account routes * add password validator * validation utils * require account approval flags * comments * comments * go fmt * comments * add distributor stub * rename api to federator * tidy a bit * validate new account requests * rename r router * comments * add domain blocks * add some more shortcuts * add some more shortcuts * check email + username availability * email block checking for signups * chunking away at it * tick off a few more things * some fiddling with tests * add mock package * relocate repo * move mocks around * set app id on new signups * initialize oauth server properly * rename oauth server * proper mocking tests * go fmt ./... * add required fields * change name of func * move validation to account.go * more tests! * add some file utility tools * add mediaconfig * new shortcut * add some more fields * add followrequest model * add notify * update mastotypes * mock out storage interface * start building media interface * start on update credentials * mess about with media a bit more * test image manipulation * media more or less working * account update nearly working * rearranging my package ;) ;) ;) * phew big stuff!!!! * fix type checking * *fiddles* * Add CreateTables func * account registration flow working * tidy * script to step through auth flow * add a lil helper for generating user uris * fiddling with federation a bit * update progress * Tidying and linting
Diffstat (limited to 'internal/db/db.go')
-rw-r--r--internal/db/db.go138
1 files changed, 126 insertions, 12 deletions
diff --git a/internal/db/db.go b/internal/db/db.go
index 9952e5e97..4921270e7 100644
--- a/internal/db/db.go
+++ b/internal/db/db.go
@@ -21,53 +21,167 @@ package db
import (
"context"
"fmt"
+ "net"
"strings"
"github.com/go-fed/activity/pub"
- "github.com/gotosocial/gotosocial/internal/config"
"github.com/sirupsen/logrus"
+ "github.com/superseriousbusiness/gotosocial/internal/config"
+ "github.com/superseriousbusiness/gotosocial/internal/db/model"
+ "github.com/superseriousbusiness/gotosocial/pkg/mastotypes"
)
const dbTypePostgres string = "POSTGRES"
+// ErrNoEntries is to be returned from the DB interface when no entries are found for a given query.
+type ErrNoEntries struct{}
+
+func (e ErrNoEntries) Error() string {
+ return "no entries"
+}
+
// DB provides methods for interacting with an underlying database or other storage mechanism (for now, just postgres).
+// Note that in all of the functions below, the passed interface should be a pointer or a slice, which will then be populated
+// by whatever is returned from the database.
type DB interface {
// 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
Federation() pub.Database
- // CreateTable creates a table for the given interface
+ /*
+ BASIC DB FUNCTIONALITY
+ */
+
+ // CreateTable creates a table for the given interface.
+ // For implementations that don't use tables, this can just return nil.
CreateTable(i interface{}) error
- // DropTable drops the table for the given interface
+ // DropTable drops the table for the given interface.
+ // For implementations that don't use tables, this can just return nil.
DropTable(i interface{}) error
- // Stop should stop and close the database connection cleanly, returning an error if this is not possible
+ // Stop should stop and close the database connection cleanly, returning an error if this is not possible.
+ // If the database implementation doesn't need to be stopped, this can just return nil.
Stop(ctx context.Context) error
- // IsHealthy should return nil if the database connection is healthy, or an error if not
+ // IsHealthy should return nil if the database connection is healthy, or an error if not.
IsHealthy(ctx context.Context) error
- // GetByID gets one entry by its id.
+ // GetByID gets one entry by its id. In a database like postgres, this might be the 'id' field of the entry,
+ // for other implementations (for example, in-memory) it might just be the key of a map.
+ // The given interface i will be set to the result of the query, whatever it is. Use a pointer or a slice.
+ // In case of no entries, a 'no entries' error will be returned
GetByID(id string, i interface{}) error
- // GetWhere gets one entry where key = value
+ // GetWhere gets one entry where key = value. This is similar to GetByID but allows the caller to specify the
+ // name of the key to select from.
+ // The given interface i will be set to the result of the query, whatever it is. Use a pointer or a slice.
+ // In case of no entries, a 'no entries' error will be returned
GetWhere(key string, value interface{}, i interface{}) error
- // GetAll gets all entries of interface type i
+ // GetAll will try to get all entries of type i.
+ // The given interface i will be set to the result of the query, whatever it is. Use a pointer or a slice.
+ // In case of no entries, a 'no entries' error will be returned
GetAll(i interface{}) error
- // Put stores i
+ // Put simply stores i. It is up to the implementation to figure out how to store it, and using what key.
+ // The given interface i will be set to the result of the query, whatever it is. Use a pointer or a slice.
Put(i interface{}) error
- // Update by id updates i with id id
+ // UpdateByID updates i with id id.
+ // The given interface i will be set to the result of the query, whatever it is. Use a pointer or a slice.
UpdateByID(id string, i interface{}) error
- // Delete by id removes i with id id
+ // UpdateOneByID updates interface i with database the given database id. It will update one field of key key and value value.
+ UpdateOneByID(id string, key string, value interface{}, i interface{}) error
+
+ // DeleteByID removes i with id id.
+ // If i didn't exist anyway, then no error should be returned.
DeleteByID(id string, i interface{}) error
- // Delete where deletes i where key = value
+ // DeleteWhere deletes i where key = value
+ // If i didn't exist anyway, then no error should be returned.
DeleteWhere(key string, value interface{}, i interface{}) error
+
+ /*
+ HANDY SHORTCUTS
+ */
+
+ // GetAccountByUserID is a shortcut for the common action of fetching an account corresponding to a user ID.
+ // The given account pointer will be set to the result of the query, whatever it is.
+ // In case of no entries, a 'no entries' error will be returned
+ GetAccountByUserID(userID string, account *model.Account) error
+
+ // GetFollowRequestsForAccountID is a shortcut for the common action of fetching a list of follow requests targeting the given account ID.
+ // The given slice 'followRequests' will be set to the result of the query, whatever it is.
+ // In case of no entries, a 'no entries' error will be returned
+ GetFollowRequestsForAccountID(accountID string, followRequests *[]model.FollowRequest) error
+
+ // GetFollowingByAccountID is a shortcut for the common action of fetching a list of accounts that accountID is following.
+ // The given slice 'following' will be set to the result of the query, whatever it is.
+ // In case of no entries, a 'no entries' error will be returned
+ GetFollowingByAccountID(accountID string, following *[]model.Follow) error
+
+ // GetFollowersByAccountID is a shortcut for the common action of fetching a list of accounts that accountID is followed by.
+ // The given slice 'followers' will be set to the result of the query, whatever it is.
+ // In case of no entries, a 'no entries' error will be returned
+ GetFollowersByAccountID(accountID string, followers *[]model.Follow) 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
+ GetStatusesByAccountID(accountID string, statuses *[]model.Status) error
+
+ // GetStatusesByTimeDescending is a shortcut for getting the most recent statuses. accountID is optional, if not provided
+ // then all statuses will be returned. If limit is set to 0, the size of the returned slice will not be limited. This can
+ // be very memory intensive so you probably shouldn't do this!
+ // In case of no entries, a 'no entries' error will be returned
+ GetStatusesByTimeDescending(accountID string, statuses *[]model.Status, limit int) error
+
+ // GetLastStatusForAccountID simply gets the most recent status by the given account.
+ // The given slice 'status' pointer will be set to the result of the query, whatever it is.
+ // In case of no entries, a 'no entries' error will be returned
+ GetLastStatusForAccountID(accountID string, status *model.Status) error
+
+ // IsUsernameAvailable checks whether a given username is available on our domain.
+ // Returns an error if the username is already taken, or something went wrong in the db.
+ IsUsernameAvailable(username string) error
+
+ // IsEmailAvailable checks whether a given email address for a new account is available to be used on our domain.
+ // Return an error if:
+ // A) the email is already associated with an account
+ // B) we block signups from this email domain
+ // C) something went wrong in the db
+ IsEmailAvailable(email string) error
+
+ // NewSignup creates a new user in the database with the given parameters, with an *unconfirmed* email address.
+ // By the time this function is called, it should be assumed that all the parameters have passed validation!
+ NewSignup(username string, reason string, requireApproval bool, email string, password string, signUpIP net.IP, locale string, appID string) (*model.User, error)
+
+ // SetHeaderOrAvatarForAccountID sets the header or avatar for the given accountID to the given media attachment.
+ SetHeaderOrAvatarForAccountID(mediaAttachment *model.MediaAttachment, accountID string) error
+
+ // GetHeaderAvatarForAccountID gets the current avatar for the given account ID.
+ // The passed mediaAttachment pointer will be populated with the value of the avatar, if it exists.
+ GetAvatarForAccountID(avatar *model.MediaAttachment, accountID string) error
+
+ // GetHeaderForAccountID gets the current header for the given account ID.
+ // The passed mediaAttachment pointer will be populated with the value of the header, if it exists.
+ GetHeaderForAccountID(header *model.MediaAttachment, accountID string) error
+
+ /*
+ USEFUL CONVERSION FUNCTIONS
+ */
+
+ // AccountToMastoSensitive takes a db model account as a param, and returns a populated mastotype account, or an error
+ // if something goes wrong. The returned account should be ready to serialize on an API level, and may have sensitive fields,
+ // so serve it only to an authorized user who should have permission to see it.
+ AccountToMastoSensitive(account *model.Account) (*mastotypes.Account, error)
+
+ // AccountToMastoPublic takes a db model account as a param, and returns a populated mastotype account, or an error
+ // if something goes wrong. The returned account should be ready to serialize on an API level, and may NOT have sensitive fields.
+ // In other words, this is the public record that the server has of an account.
+ AccountToMastoPublic(account *model.Account) (*mastotypes.Account, error)
}
// New returns a new database service that satisfies the DB interface and, by extension,