roomdb: flesh out alias service
* update interface * update mockdb * update models * implement sqlite implementation
This commit is contained in:
parent
04104c0f9e
commit
e6c3305229
|
@ -53,7 +53,22 @@ type AllowListService interface {
|
|||
}
|
||||
|
||||
// AliasService manages alias handle registration and lookup
|
||||
type AliasService interface{}
|
||||
type AliasService interface {
|
||||
// Resolve returns all the relevant information for that alias or an error if it doesnt exist
|
||||
Resolve(context.Context, string) (Alias, error)
|
||||
|
||||
// GetByID returns the alias for that ID or an error
|
||||
GetByID(context.Context, int64) (Alias, error)
|
||||
|
||||
// List returns a list of all registerd aliases
|
||||
List(ctx context.Context) ([]Alias, error)
|
||||
|
||||
// Register receives an alias and signature for it. Validation needs to happen before this.
|
||||
Register(ctx context.Context, alias string, userFeed refs.FeedRef, signature []byte) error
|
||||
|
||||
// Revoke removes an alias from the system
|
||||
Revoke(ctx context.Context, alias string) error
|
||||
}
|
||||
|
||||
// InviteService manages creation and consumption of invite tokens for joining the room.
|
||||
type InviteService interface {
|
||||
|
|
|
@ -2,19 +2,423 @@
|
|||
package mockdb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/roomdb"
|
||||
refs "go.mindeco.de/ssb-refs"
|
||||
)
|
||||
|
||||
type FakeAliasService struct {
|
||||
GetByIDStub func(context.Context, int64) (roomdb.Alias, error)
|
||||
getByIDMutex sync.RWMutex
|
||||
getByIDArgsForCall []struct {
|
||||
arg1 context.Context
|
||||
arg2 int64
|
||||
}
|
||||
getByIDReturns struct {
|
||||
result1 roomdb.Alias
|
||||
result2 error
|
||||
}
|
||||
getByIDReturnsOnCall map[int]struct {
|
||||
result1 roomdb.Alias
|
||||
result2 error
|
||||
}
|
||||
ListStub func(context.Context) ([]roomdb.Alias, error)
|
||||
listMutex sync.RWMutex
|
||||
listArgsForCall []struct {
|
||||
arg1 context.Context
|
||||
}
|
||||
listReturns struct {
|
||||
result1 []roomdb.Alias
|
||||
result2 error
|
||||
}
|
||||
listReturnsOnCall map[int]struct {
|
||||
result1 []roomdb.Alias
|
||||
result2 error
|
||||
}
|
||||
RegisterStub func(context.Context, string, refs.FeedRef, []byte) error
|
||||
registerMutex sync.RWMutex
|
||||
registerArgsForCall []struct {
|
||||
arg1 context.Context
|
||||
arg2 string
|
||||
arg3 refs.FeedRef
|
||||
arg4 []byte
|
||||
}
|
||||
registerReturns struct {
|
||||
result1 error
|
||||
}
|
||||
registerReturnsOnCall map[int]struct {
|
||||
result1 error
|
||||
}
|
||||
ResolveStub func(context.Context, string) (roomdb.Alias, error)
|
||||
resolveMutex sync.RWMutex
|
||||
resolveArgsForCall []struct {
|
||||
arg1 context.Context
|
||||
arg2 string
|
||||
}
|
||||
resolveReturns struct {
|
||||
result1 roomdb.Alias
|
||||
result2 error
|
||||
}
|
||||
resolveReturnsOnCall map[int]struct {
|
||||
result1 roomdb.Alias
|
||||
result2 error
|
||||
}
|
||||
RevokeStub func(context.Context, string) error
|
||||
revokeMutex sync.RWMutex
|
||||
revokeArgsForCall []struct {
|
||||
arg1 context.Context
|
||||
arg2 string
|
||||
}
|
||||
revokeReturns struct {
|
||||
result1 error
|
||||
}
|
||||
revokeReturnsOnCall map[int]struct {
|
||||
result1 error
|
||||
}
|
||||
invocations map[string][][]interface{}
|
||||
invocationsMutex sync.RWMutex
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) GetByID(arg1 context.Context, arg2 int64) (roomdb.Alias, error) {
|
||||
fake.getByIDMutex.Lock()
|
||||
ret, specificReturn := fake.getByIDReturnsOnCall[len(fake.getByIDArgsForCall)]
|
||||
fake.getByIDArgsForCall = append(fake.getByIDArgsForCall, struct {
|
||||
arg1 context.Context
|
||||
arg2 int64
|
||||
}{arg1, arg2})
|
||||
stub := fake.GetByIDStub
|
||||
fakeReturns := fake.getByIDReturns
|
||||
fake.recordInvocation("GetByID", []interface{}{arg1, arg2})
|
||||
fake.getByIDMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) GetByIDCallCount() int {
|
||||
fake.getByIDMutex.RLock()
|
||||
defer fake.getByIDMutex.RUnlock()
|
||||
return len(fake.getByIDArgsForCall)
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) GetByIDCalls(stub func(context.Context, int64) (roomdb.Alias, error)) {
|
||||
fake.getByIDMutex.Lock()
|
||||
defer fake.getByIDMutex.Unlock()
|
||||
fake.GetByIDStub = stub
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) GetByIDArgsForCall(i int) (context.Context, int64) {
|
||||
fake.getByIDMutex.RLock()
|
||||
defer fake.getByIDMutex.RUnlock()
|
||||
argsForCall := fake.getByIDArgsForCall[i]
|
||||
return argsForCall.arg1, argsForCall.arg2
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) GetByIDReturns(result1 roomdb.Alias, result2 error) {
|
||||
fake.getByIDMutex.Lock()
|
||||
defer fake.getByIDMutex.Unlock()
|
||||
fake.GetByIDStub = nil
|
||||
fake.getByIDReturns = struct {
|
||||
result1 roomdb.Alias
|
||||
result2 error
|
||||
}{result1, result2}
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) GetByIDReturnsOnCall(i int, result1 roomdb.Alias, result2 error) {
|
||||
fake.getByIDMutex.Lock()
|
||||
defer fake.getByIDMutex.Unlock()
|
||||
fake.GetByIDStub = nil
|
||||
if fake.getByIDReturnsOnCall == nil {
|
||||
fake.getByIDReturnsOnCall = make(map[int]struct {
|
||||
result1 roomdb.Alias
|
||||
result2 error
|
||||
})
|
||||
}
|
||||
fake.getByIDReturnsOnCall[i] = struct {
|
||||
result1 roomdb.Alias
|
||||
result2 error
|
||||
}{result1, result2}
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) List(arg1 context.Context) ([]roomdb.Alias, error) {
|
||||
fake.listMutex.Lock()
|
||||
ret, specificReturn := fake.listReturnsOnCall[len(fake.listArgsForCall)]
|
||||
fake.listArgsForCall = append(fake.listArgsForCall, struct {
|
||||
arg1 context.Context
|
||||
}{arg1})
|
||||
stub := fake.ListStub
|
||||
fakeReturns := fake.listReturns
|
||||
fake.recordInvocation("List", []interface{}{arg1})
|
||||
fake.listMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) ListCallCount() int {
|
||||
fake.listMutex.RLock()
|
||||
defer fake.listMutex.RUnlock()
|
||||
return len(fake.listArgsForCall)
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) ListCalls(stub func(context.Context) ([]roomdb.Alias, error)) {
|
||||
fake.listMutex.Lock()
|
||||
defer fake.listMutex.Unlock()
|
||||
fake.ListStub = stub
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) ListArgsForCall(i int) context.Context {
|
||||
fake.listMutex.RLock()
|
||||
defer fake.listMutex.RUnlock()
|
||||
argsForCall := fake.listArgsForCall[i]
|
||||
return argsForCall.arg1
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) ListReturns(result1 []roomdb.Alias, result2 error) {
|
||||
fake.listMutex.Lock()
|
||||
defer fake.listMutex.Unlock()
|
||||
fake.ListStub = nil
|
||||
fake.listReturns = struct {
|
||||
result1 []roomdb.Alias
|
||||
result2 error
|
||||
}{result1, result2}
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) ListReturnsOnCall(i int, result1 []roomdb.Alias, result2 error) {
|
||||
fake.listMutex.Lock()
|
||||
defer fake.listMutex.Unlock()
|
||||
fake.ListStub = nil
|
||||
if fake.listReturnsOnCall == nil {
|
||||
fake.listReturnsOnCall = make(map[int]struct {
|
||||
result1 []roomdb.Alias
|
||||
result2 error
|
||||
})
|
||||
}
|
||||
fake.listReturnsOnCall[i] = struct {
|
||||
result1 []roomdb.Alias
|
||||
result2 error
|
||||
}{result1, result2}
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) Register(arg1 context.Context, arg2 string, arg3 refs.FeedRef, arg4 []byte) error {
|
||||
var arg4Copy []byte
|
||||
if arg4 != nil {
|
||||
arg4Copy = make([]byte, len(arg4))
|
||||
copy(arg4Copy, arg4)
|
||||
}
|
||||
fake.registerMutex.Lock()
|
||||
ret, specificReturn := fake.registerReturnsOnCall[len(fake.registerArgsForCall)]
|
||||
fake.registerArgsForCall = append(fake.registerArgsForCall, struct {
|
||||
arg1 context.Context
|
||||
arg2 string
|
||||
arg3 refs.FeedRef
|
||||
arg4 []byte
|
||||
}{arg1, arg2, arg3, arg4Copy})
|
||||
stub := fake.RegisterStub
|
||||
fakeReturns := fake.registerReturns
|
||||
fake.recordInvocation("Register", []interface{}{arg1, arg2, arg3, arg4Copy})
|
||||
fake.registerMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2, arg3, arg4)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1
|
||||
}
|
||||
return fakeReturns.result1
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) RegisterCallCount() int {
|
||||
fake.registerMutex.RLock()
|
||||
defer fake.registerMutex.RUnlock()
|
||||
return len(fake.registerArgsForCall)
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) RegisterCalls(stub func(context.Context, string, refs.FeedRef, []byte) error) {
|
||||
fake.registerMutex.Lock()
|
||||
defer fake.registerMutex.Unlock()
|
||||
fake.RegisterStub = stub
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) RegisterArgsForCall(i int) (context.Context, string, refs.FeedRef, []byte) {
|
||||
fake.registerMutex.RLock()
|
||||
defer fake.registerMutex.RUnlock()
|
||||
argsForCall := fake.registerArgsForCall[i]
|
||||
return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) RegisterReturns(result1 error) {
|
||||
fake.registerMutex.Lock()
|
||||
defer fake.registerMutex.Unlock()
|
||||
fake.RegisterStub = nil
|
||||
fake.registerReturns = struct {
|
||||
result1 error
|
||||
}{result1}
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) RegisterReturnsOnCall(i int, result1 error) {
|
||||
fake.registerMutex.Lock()
|
||||
defer fake.registerMutex.Unlock()
|
||||
fake.RegisterStub = nil
|
||||
if fake.registerReturnsOnCall == nil {
|
||||
fake.registerReturnsOnCall = make(map[int]struct {
|
||||
result1 error
|
||||
})
|
||||
}
|
||||
fake.registerReturnsOnCall[i] = struct {
|
||||
result1 error
|
||||
}{result1}
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) Resolve(arg1 context.Context, arg2 string) (roomdb.Alias, error) {
|
||||
fake.resolveMutex.Lock()
|
||||
ret, specificReturn := fake.resolveReturnsOnCall[len(fake.resolveArgsForCall)]
|
||||
fake.resolveArgsForCall = append(fake.resolveArgsForCall, struct {
|
||||
arg1 context.Context
|
||||
arg2 string
|
||||
}{arg1, arg2})
|
||||
stub := fake.ResolveStub
|
||||
fakeReturns := fake.resolveReturns
|
||||
fake.recordInvocation("Resolve", []interface{}{arg1, arg2})
|
||||
fake.resolveMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) ResolveCallCount() int {
|
||||
fake.resolveMutex.RLock()
|
||||
defer fake.resolveMutex.RUnlock()
|
||||
return len(fake.resolveArgsForCall)
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) ResolveCalls(stub func(context.Context, string) (roomdb.Alias, error)) {
|
||||
fake.resolveMutex.Lock()
|
||||
defer fake.resolveMutex.Unlock()
|
||||
fake.ResolveStub = stub
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) ResolveArgsForCall(i int) (context.Context, string) {
|
||||
fake.resolveMutex.RLock()
|
||||
defer fake.resolveMutex.RUnlock()
|
||||
argsForCall := fake.resolveArgsForCall[i]
|
||||
return argsForCall.arg1, argsForCall.arg2
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) ResolveReturns(result1 roomdb.Alias, result2 error) {
|
||||
fake.resolveMutex.Lock()
|
||||
defer fake.resolveMutex.Unlock()
|
||||
fake.ResolveStub = nil
|
||||
fake.resolveReturns = struct {
|
||||
result1 roomdb.Alias
|
||||
result2 error
|
||||
}{result1, result2}
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) ResolveReturnsOnCall(i int, result1 roomdb.Alias, result2 error) {
|
||||
fake.resolveMutex.Lock()
|
||||
defer fake.resolveMutex.Unlock()
|
||||
fake.ResolveStub = nil
|
||||
if fake.resolveReturnsOnCall == nil {
|
||||
fake.resolveReturnsOnCall = make(map[int]struct {
|
||||
result1 roomdb.Alias
|
||||
result2 error
|
||||
})
|
||||
}
|
||||
fake.resolveReturnsOnCall[i] = struct {
|
||||
result1 roomdb.Alias
|
||||
result2 error
|
||||
}{result1, result2}
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) Revoke(arg1 context.Context, arg2 string) error {
|
||||
fake.revokeMutex.Lock()
|
||||
ret, specificReturn := fake.revokeReturnsOnCall[len(fake.revokeArgsForCall)]
|
||||
fake.revokeArgsForCall = append(fake.revokeArgsForCall, struct {
|
||||
arg1 context.Context
|
||||
arg2 string
|
||||
}{arg1, arg2})
|
||||
stub := fake.RevokeStub
|
||||
fakeReturns := fake.revokeReturns
|
||||
fake.recordInvocation("Revoke", []interface{}{arg1, arg2})
|
||||
fake.revokeMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1
|
||||
}
|
||||
return fakeReturns.result1
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) RevokeCallCount() int {
|
||||
fake.revokeMutex.RLock()
|
||||
defer fake.revokeMutex.RUnlock()
|
||||
return len(fake.revokeArgsForCall)
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) RevokeCalls(stub func(context.Context, string) error) {
|
||||
fake.revokeMutex.Lock()
|
||||
defer fake.revokeMutex.Unlock()
|
||||
fake.RevokeStub = stub
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) RevokeArgsForCall(i int) (context.Context, string) {
|
||||
fake.revokeMutex.RLock()
|
||||
defer fake.revokeMutex.RUnlock()
|
||||
argsForCall := fake.revokeArgsForCall[i]
|
||||
return argsForCall.arg1, argsForCall.arg2
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) RevokeReturns(result1 error) {
|
||||
fake.revokeMutex.Lock()
|
||||
defer fake.revokeMutex.Unlock()
|
||||
fake.RevokeStub = nil
|
||||
fake.revokeReturns = struct {
|
||||
result1 error
|
||||
}{result1}
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) RevokeReturnsOnCall(i int, result1 error) {
|
||||
fake.revokeMutex.Lock()
|
||||
defer fake.revokeMutex.Unlock()
|
||||
fake.RevokeStub = nil
|
||||
if fake.revokeReturnsOnCall == nil {
|
||||
fake.revokeReturnsOnCall = make(map[int]struct {
|
||||
result1 error
|
||||
})
|
||||
}
|
||||
fake.revokeReturnsOnCall[i] = struct {
|
||||
result1 error
|
||||
}{result1}
|
||||
}
|
||||
|
||||
func (fake *FakeAliasService) Invocations() map[string][][]interface{} {
|
||||
fake.invocationsMutex.RLock()
|
||||
defer fake.invocationsMutex.RUnlock()
|
||||
fake.getByIDMutex.RLock()
|
||||
defer fake.getByIDMutex.RUnlock()
|
||||
fake.listMutex.RLock()
|
||||
defer fake.listMutex.RUnlock()
|
||||
fake.registerMutex.RLock()
|
||||
defer fake.registerMutex.RUnlock()
|
||||
fake.resolveMutex.RLock()
|
||||
defer fake.resolveMutex.RUnlock()
|
||||
fake.revokeMutex.RLock()
|
||||
defer fake.revokeMutex.RUnlock()
|
||||
copiedInvocations := map[string][][]interface{}{}
|
||||
for key, value := range fake.invocations {
|
||||
copiedInvocations[key] = value
|
||||
|
|
|
@ -3,9 +3,16 @@
|
|||
package sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/friendsofgo/errors"
|
||||
"github.com/volatiletech/sqlboiler/v4/boil"
|
||||
"github.com/volatiletech/sqlboiler/v4/queries/qm"
|
||||
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/roomdb"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/roomdb/sqlite/models"
|
||||
refs "go.mindeco.de/ssb-refs"
|
||||
)
|
||||
|
||||
// compiler assertion to ensure the struct fullfills the interface
|
||||
|
@ -14,3 +21,98 @@ var _ roomdb.AliasService = (*Aliases)(nil)
|
|||
type Aliases struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
// Resolve returns all the relevant information for that alias or an error if it doesnt exist
|
||||
func (a Aliases) Resolve(ctx context.Context, name string) (roomdb.Alias, error) {
|
||||
return a.findOne(ctx, qm.Where("name = ?", name))
|
||||
}
|
||||
|
||||
// GetByID returns the alias for that ID or an error
|
||||
func (a Aliases) GetByID(ctx context.Context, id int64) (roomdb.Alias, error) {
|
||||
return a.findOne(ctx, qm.Where("id = ?", id))
|
||||
}
|
||||
|
||||
func (a Aliases) findOne(ctx context.Context, by qm.QueryMod) (roomdb.Alias, error) {
|
||||
var found roomdb.Alias
|
||||
|
||||
// construct query which resolves the User relation and by which we shoudl look for it
|
||||
qry := append([]qm.QueryMod{qm.Load("User")}, by)
|
||||
|
||||
entry, err := models.Aliases(qry...).One(ctx, a.db)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return found, roomdb.ErrNotFound
|
||||
}
|
||||
return found, err
|
||||
}
|
||||
|
||||
// unpack models into roomdb type
|
||||
found.ID = entry.ID
|
||||
found.Name = entry.Name
|
||||
found.Signature = entry.Signature
|
||||
found.Feed = entry.R.User.PubKey.FeedRef
|
||||
|
||||
return found, nil
|
||||
}
|
||||
|
||||
// List returns a list of all registerd aliases
|
||||
func (a Aliases) List(ctx context.Context) ([]roomdb.Alias, error) {
|
||||
all, err := models.Aliases(qm.Load("User")).All(ctx, a.db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var aliases = make([]roomdb.Alias, len(all))
|
||||
for i, entry := range all {
|
||||
|
||||
aliases[i] = roomdb.Alias{
|
||||
ID: entry.ID,
|
||||
Name: entry.Name,
|
||||
Feed: entry.R.User.PubKey.FeedRef,
|
||||
Signature: entry.Signature,
|
||||
}
|
||||
}
|
||||
|
||||
return aliases, nil
|
||||
}
|
||||
|
||||
// Register receives an alias and signature for it. Validation needs to happen before this.
|
||||
func (a Aliases) Register(ctx context.Context, alias string, userFeed refs.FeedRef, signature []byte) error {
|
||||
return transact(a.db, func(tx *sql.Tx) error {
|
||||
// check we have a members entry for the feed and load it to get its ID
|
||||
allowListEntry, err := models.AllowLists(qm.Where("pub_key = ?", userFeed.Ref())).One(ctx, tx)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return roomdb.ErrNotFound
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
var newEntry models.Alias
|
||||
newEntry.Name = alias
|
||||
newEntry.UserID = allowListEntry.ID
|
||||
newEntry.Signature = signature
|
||||
|
||||
err = newEntry.Insert(ctx, tx, boil.Infer())
|
||||
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
// Revoke removes an alias from the system
|
||||
func (a Aliases) Revoke(ctx context.Context, alias string) error {
|
||||
return transact(a.db, func(tx *sql.Tx) error {
|
||||
qry := append([]qm.QueryMod{qm.Load("User")}, qm.Where("name = ?", alias))
|
||||
|
||||
entry, err := models.Aliases(qry...).One(ctx, a.db)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return roomdb.ErrNotFound
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = entry.Delete(ctx, tx)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
package sqlite
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/internal/repo"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/roomdb"
|
||||
"github.com/stretchr/testify/require"
|
||||
refs "go.mindeco.de/ssb-refs"
|
||||
)
|
||||
|
||||
func TestAliases(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
testRepo := filepath.Join("testrun", t.Name())
|
||||
os.RemoveAll(testRepo)
|
||||
tr := repo.New(testRepo)
|
||||
|
||||
// fake feed for testing, looks ok at least
|
||||
newMember := refs.FeedRef{ID: bytes.Repeat([]byte("acab"), 8), Algo: refs.RefAlgoFeedSSB1}
|
||||
|
||||
// 64 bytes of random for testing (validation is handled by the handlers)
|
||||
testSig := make([]byte, 64)
|
||||
rand.Read(testSig)
|
||||
|
||||
db, err := Open(tr)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("not found", func(t *testing.T) {
|
||||
r := require.New(t)
|
||||
|
||||
lst, err := db.Aliases.List(ctx)
|
||||
r.NoError(err)
|
||||
r.Len(lst, 0)
|
||||
|
||||
_, err = db.Aliases.GetByID(ctx, 9999)
|
||||
r.Error(err)
|
||||
r.EqualError(err, roomdb.ErrNotFound.Error())
|
||||
|
||||
_, err = db.Aliases.Resolve(ctx, "unknown")
|
||||
r.Error(err)
|
||||
r.EqualError(err, roomdb.ErrNotFound.Error())
|
||||
|
||||
err = db.Aliases.Revoke(ctx, "unknown")
|
||||
r.Error(err)
|
||||
r.EqualError(errors.Unwrap(err), roomdb.ErrNotFound.Error())
|
||||
})
|
||||
|
||||
t.Run("register and revoke again", func(t *testing.T) {
|
||||
r := require.New(t)
|
||||
|
||||
testName := "flaky"
|
||||
|
||||
// shouldnt work while not a member
|
||||
err = db.Aliases.Register(ctx, testName, newMember, testSig)
|
||||
r.Error(err)
|
||||
|
||||
// allow the member
|
||||
err = db.AllowList.Add(ctx, newMember)
|
||||
r.NoError(err)
|
||||
|
||||
err = db.Aliases.Register(ctx, testName, newMember, testSig)
|
||||
r.NoError(err)
|
||||
|
||||
// should have one member now
|
||||
lst, err := db.Aliases.List(ctx)
|
||||
r.NoError(err)
|
||||
r.Len(lst, 1)
|
||||
|
||||
aliasByID, err := db.Aliases.GetByID(ctx, lst[0].ID)
|
||||
r.NoError(err)
|
||||
r.Equal(testName, aliasByID.Name)
|
||||
r.Equal(testSig, aliasByID.Signature)
|
||||
|
||||
resolvedAlias, err := db.Aliases.Resolve(ctx, testName)
|
||||
r.NoError(err)
|
||||
r.Equal(aliasByID, resolvedAlias)
|
||||
|
||||
err = db.Aliases.Revoke(ctx, testName)
|
||||
r.NoError(err)
|
||||
|
||||
_, err = db.Aliases.GetByID(ctx, lst[0].ID)
|
||||
r.Error(err)
|
||||
r.EqualError(err, roomdb.ErrNotFound.Error())
|
||||
|
||||
_, err = db.Aliases.Resolve(ctx, testName)
|
||||
r.Error(err)
|
||||
r.EqualError(err, roomdb.ErrNotFound.Error())
|
||||
})
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
-- +migrate Up
|
||||
CREATE TABLE aliases (
|
||||
id integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
name text UNIQUE NOT NULL,
|
||||
user_id integer NOT NULL,
|
||||
signature blob not null,
|
||||
|
||||
FOREIGN KEY ( user_id ) REFERENCES allow_list( "id" )
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX aliases_ids ON aliases(id);
|
||||
CREATE UNIQUE INDEX aliases_names ON aliases(name);
|
||||
|
||||
-- +migrate Down
|
||||
DROP TABLE aliases;
|
||||
|
||||
DROP INDEX aliases_ids;
|
||||
DROP INDEX aliases_names;
|
File diff suppressed because it is too large
Load Diff
|
@ -23,7 +23,7 @@ import (
|
|||
|
||||
// AllowList is an object representing the database table.
|
||||
type AllowList struct {
|
||||
ID int64 `boil:"id" json:"id" toml:"id" yaml:"id"`
|
||||
ID int64 `boil:"id" json:"id" toml:"id" yaml:"id"`
|
||||
PubKey roomdb.DBFeedRef `boil:"pub_key" json:"pub_key" toml:"pub_key" yaml:"pub_key"`
|
||||
|
||||
R *allowListR `boil:"-" json:"-" toml:"-" yaml:"-"`
|
||||
|
@ -40,64 +40,45 @@ var AllowListColumns = struct {
|
|||
|
||||
// Generated where
|
||||
|
||||
type whereHelperint64 struct{ field string }
|
||||
type whereHelperroomdb_DBFeedRef struct{ field string }
|
||||
|
||||
func (w whereHelperint64) EQ(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.EQ, x) }
|
||||
func (w whereHelperint64) NEQ(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.NEQ, x) }
|
||||
func (w whereHelperint64) LT(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LT, x) }
|
||||
func (w whereHelperint64) LTE(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LTE, x) }
|
||||
func (w whereHelperint64) GT(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GT, x) }
|
||||
func (w whereHelperint64) GTE(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GTE, x) }
|
||||
func (w whereHelperint64) IN(slice []int64) qm.QueryMod {
|
||||
values := make([]interface{}, 0, len(slice))
|
||||
for _, value := range slice {
|
||||
values = append(values, value)
|
||||
}
|
||||
return qm.WhereIn(fmt.Sprintf("%s IN ?", w.field), values...)
|
||||
}
|
||||
func (w whereHelperint64) NIN(slice []int64) qm.QueryMod {
|
||||
values := make([]interface{}, 0, len(slice))
|
||||
for _, value := range slice {
|
||||
values = append(values, value)
|
||||
}
|
||||
return qm.WhereNotIn(fmt.Sprintf("%s NOT IN ?", w.field), values...)
|
||||
}
|
||||
|
||||
type whereHelperadmindb_DBFeedRef struct{ field string }
|
||||
|
||||
func (w whereHelperadmindb_DBFeedRef) EQ(x roomdb.DBFeedRef) qm.QueryMod {
|
||||
func (w whereHelperroomdb_DBFeedRef) EQ(x roomdb.DBFeedRef) qm.QueryMod {
|
||||
return qmhelper.Where(w.field, qmhelper.EQ, x)
|
||||
}
|
||||
func (w whereHelperadmindb_DBFeedRef) NEQ(x roomdb.DBFeedRef) qm.QueryMod {
|
||||
func (w whereHelperroomdb_DBFeedRef) NEQ(x roomdb.DBFeedRef) qm.QueryMod {
|
||||
return qmhelper.Where(w.field, qmhelper.NEQ, x)
|
||||
}
|
||||
func (w whereHelperadmindb_DBFeedRef) LT(x roomdb.DBFeedRef) qm.QueryMod {
|
||||
func (w whereHelperroomdb_DBFeedRef) LT(x roomdb.DBFeedRef) qm.QueryMod {
|
||||
return qmhelper.Where(w.field, qmhelper.LT, x)
|
||||
}
|
||||
func (w whereHelperadmindb_DBFeedRef) LTE(x roomdb.DBFeedRef) qm.QueryMod {
|
||||
func (w whereHelperroomdb_DBFeedRef) LTE(x roomdb.DBFeedRef) qm.QueryMod {
|
||||
return qmhelper.Where(w.field, qmhelper.LTE, x)
|
||||
}
|
||||
func (w whereHelperadmindb_DBFeedRef) GT(x roomdb.DBFeedRef) qm.QueryMod {
|
||||
func (w whereHelperroomdb_DBFeedRef) GT(x roomdb.DBFeedRef) qm.QueryMod {
|
||||
return qmhelper.Where(w.field, qmhelper.GT, x)
|
||||
}
|
||||
func (w whereHelperadmindb_DBFeedRef) GTE(x roomdb.DBFeedRef) qm.QueryMod {
|
||||
func (w whereHelperroomdb_DBFeedRef) GTE(x roomdb.DBFeedRef) qm.QueryMod {
|
||||
return qmhelper.Where(w.field, qmhelper.GTE, x)
|
||||
}
|
||||
|
||||
var AllowListWhere = struct {
|
||||
ID whereHelperint64
|
||||
PubKey whereHelperadmindb_DBFeedRef
|
||||
PubKey whereHelperroomdb_DBFeedRef
|
||||
}{
|
||||
ID: whereHelperint64{field: "\"allow_list\".\"id\""},
|
||||
PubKey: whereHelperadmindb_DBFeedRef{field: "\"allow_list\".\"pub_key\""},
|
||||
PubKey: whereHelperroomdb_DBFeedRef{field: "\"allow_list\".\"pub_key\""},
|
||||
}
|
||||
|
||||
// AllowListRels is where relationship names are stored.
|
||||
var AllowListRels = struct {
|
||||
}{}
|
||||
UserAliases string
|
||||
}{
|
||||
UserAliases: "UserAliases",
|
||||
}
|
||||
|
||||
// allowListR is where relationships are stored.
|
||||
type allowListR struct {
|
||||
UserAliases AliasSlice `boil:"UserAliases" json:"UserAliases" toml:"UserAliases" yaml:"UserAliases"`
|
||||
}
|
||||
|
||||
// NewStruct creates a new relationship struct
|
||||
|
@ -390,6 +371,178 @@ func (q allowListQuery) Exists(ctx context.Context, exec boil.ContextExecutor) (
|
|||
return count > 0, nil
|
||||
}
|
||||
|
||||
// UserAliases retrieves all the alias's Aliases with an executor via user_id column.
|
||||
func (o *AllowList) UserAliases(mods ...qm.QueryMod) aliasQuery {
|
||||
var queryMods []qm.QueryMod
|
||||
if len(mods) != 0 {
|
||||
queryMods = append(queryMods, mods...)
|
||||
}
|
||||
|
||||
queryMods = append(queryMods,
|
||||
qm.Where("\"aliases\".\"user_id\"=?", o.ID),
|
||||
)
|
||||
|
||||
query := Aliases(queryMods...)
|
||||
queries.SetFrom(query.Query, "\"aliases\"")
|
||||
|
||||
if len(queries.GetSelect(query.Query)) == 0 {
|
||||
queries.SetSelect(query.Query, []string{"\"aliases\".*"})
|
||||
}
|
||||
|
||||
return query
|
||||
}
|
||||
|
||||
// LoadUserAliases allows an eager lookup of values, cached into the
|
||||
// loaded structs of the objects. This is for a 1-M or N-M relationship.
|
||||
func (allowListL) LoadUserAliases(ctx context.Context, e boil.ContextExecutor, singular bool, maybeAllowList interface{}, mods queries.Applicator) error {
|
||||
var slice []*AllowList
|
||||
var object *AllowList
|
||||
|
||||
if singular {
|
||||
object = maybeAllowList.(*AllowList)
|
||||
} else {
|
||||
slice = *maybeAllowList.(*[]*AllowList)
|
||||
}
|
||||
|
||||
args := make([]interface{}, 0, 1)
|
||||
if singular {
|
||||
if object.R == nil {
|
||||
object.R = &allowListR{}
|
||||
}
|
||||
args = append(args, object.ID)
|
||||
} else {
|
||||
Outer:
|
||||
for _, obj := range slice {
|
||||
if obj.R == nil {
|
||||
obj.R = &allowListR{}
|
||||
}
|
||||
|
||||
for _, a := range args {
|
||||
if a == obj.ID {
|
||||
continue Outer
|
||||
}
|
||||
}
|
||||
|
||||
args = append(args, obj.ID)
|
||||
}
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
query := NewQuery(
|
||||
qm.From(`aliases`),
|
||||
qm.WhereIn(`aliases.user_id in ?`, args...),
|
||||
)
|
||||
if mods != nil {
|
||||
mods.Apply(query)
|
||||
}
|
||||
|
||||
results, err := query.QueryContext(ctx, e)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to eager load aliases")
|
||||
}
|
||||
|
||||
var resultSlice []*Alias
|
||||
if err = queries.Bind(results, &resultSlice); err != nil {
|
||||
return errors.Wrap(err, "failed to bind eager loaded slice aliases")
|
||||
}
|
||||
|
||||
if err = results.Close(); err != nil {
|
||||
return errors.Wrap(err, "failed to close results in eager load on aliases")
|
||||
}
|
||||
if err = results.Err(); err != nil {
|
||||
return errors.Wrap(err, "error occurred during iteration of eager loaded relations for aliases")
|
||||
}
|
||||
|
||||
if len(aliasAfterSelectHooks) != 0 {
|
||||
for _, obj := range resultSlice {
|
||||
if err := obj.doAfterSelectHooks(ctx, e); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if singular {
|
||||
object.R.UserAliases = resultSlice
|
||||
for _, foreign := range resultSlice {
|
||||
if foreign.R == nil {
|
||||
foreign.R = &aliasR{}
|
||||
}
|
||||
foreign.R.User = object
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, foreign := range resultSlice {
|
||||
for _, local := range slice {
|
||||
if local.ID == foreign.UserID {
|
||||
local.R.UserAliases = append(local.R.UserAliases, foreign)
|
||||
if foreign.R == nil {
|
||||
foreign.R = &aliasR{}
|
||||
}
|
||||
foreign.R.User = local
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddUserAliases adds the given related objects to the existing relationships
|
||||
// of the allow_list, optionally inserting them as new records.
|
||||
// Appends related to o.R.UserAliases.
|
||||
// Sets related.R.User appropriately.
|
||||
func (o *AllowList) AddUserAliases(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*Alias) error {
|
||||
var err error
|
||||
for _, rel := range related {
|
||||
if insert {
|
||||
rel.UserID = o.ID
|
||||
if err = rel.Insert(ctx, exec, boil.Infer()); err != nil {
|
||||
return errors.Wrap(err, "failed to insert into foreign table")
|
||||
}
|
||||
} else {
|
||||
updateQuery := fmt.Sprintf(
|
||||
"UPDATE \"aliases\" SET %s WHERE %s",
|
||||
strmangle.SetParamNames("\"", "\"", 0, []string{"user_id"}),
|
||||
strmangle.WhereClause("\"", "\"", 0, aliasPrimaryKeyColumns),
|
||||
)
|
||||
values := []interface{}{o.ID, rel.ID}
|
||||
|
||||
if boil.IsDebug(ctx) {
|
||||
writer := boil.DebugWriterFrom(ctx)
|
||||
fmt.Fprintln(writer, updateQuery)
|
||||
fmt.Fprintln(writer, values)
|
||||
}
|
||||
if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil {
|
||||
return errors.Wrap(err, "failed to update foreign table")
|
||||
}
|
||||
|
||||
rel.UserID = o.ID
|
||||
}
|
||||
}
|
||||
|
||||
if o.R == nil {
|
||||
o.R = &allowListR{
|
||||
UserAliases: related,
|
||||
}
|
||||
} else {
|
||||
o.R.UserAliases = append(o.R.UserAliases, related...)
|
||||
}
|
||||
|
||||
for _, rel := range related {
|
||||
if rel.R == nil {
|
||||
rel.R = &aliasR{
|
||||
User: o,
|
||||
}
|
||||
} else {
|
||||
rel.R.User = o
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AllowLists retrieves all the records using an executor.
|
||||
func AllowLists(mods ...qm.QueryMod) allowListQuery {
|
||||
mods = append(mods, qm.From("\"allow_list\""))
|
||||
|
|
|
@ -42,38 +42,6 @@ var AuthFallbackColumns = struct {
|
|||
|
||||
// Generated where
|
||||
|
||||
type whereHelperstring struct{ field string }
|
||||
|
||||
func (w whereHelperstring) EQ(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.EQ, x) }
|
||||
func (w whereHelperstring) NEQ(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.NEQ, x) }
|
||||
func (w whereHelperstring) LT(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LT, x) }
|
||||
func (w whereHelperstring) LTE(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LTE, x) }
|
||||
func (w whereHelperstring) GT(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GT, x) }
|
||||
func (w whereHelperstring) GTE(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GTE, x) }
|
||||
func (w whereHelperstring) IN(slice []string) qm.QueryMod {
|
||||
values := make([]interface{}, 0, len(slice))
|
||||
for _, value := range slice {
|
||||
values = append(values, value)
|
||||
}
|
||||
return qm.WhereIn(fmt.Sprintf("%s IN ?", w.field), values...)
|
||||
}
|
||||
func (w whereHelperstring) NIN(slice []string) qm.QueryMod {
|
||||
values := make([]interface{}, 0, len(slice))
|
||||
for _, value := range slice {
|
||||
values = append(values, value)
|
||||
}
|
||||
return qm.WhereNotIn(fmt.Sprintf("%s NOT IN ?", w.field), values...)
|
||||
}
|
||||
|
||||
type whereHelper__byte struct{ field string }
|
||||
|
||||
func (w whereHelper__byte) EQ(x []byte) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.EQ, x) }
|
||||
func (w whereHelper__byte) NEQ(x []byte) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.NEQ, x) }
|
||||
func (w whereHelper__byte) LT(x []byte) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LT, x) }
|
||||
func (w whereHelper__byte) LTE(x []byte) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LTE, x) }
|
||||
func (w whereHelper__byte) GT(x []byte) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GT, x) }
|
||||
func (w whereHelper__byte) GTE(x []byte) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GTE, x) }
|
||||
|
||||
var AuthFallbackWhere = struct {
|
||||
ID whereHelperint64
|
||||
Name whereHelperstring
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
package models
|
||||
|
||||
var TableNames = struct {
|
||||
Aliases string
|
||||
AllowList string
|
||||
AuthFallback string
|
||||
Invites string
|
||||
|
@ -11,6 +12,7 @@ var TableNames = struct {
|
|||
PinNotices string
|
||||
Pins string
|
||||
}{
|
||||
Aliases: "aliases",
|
||||
AllowList: "allow_list",
|
||||
AuthFallback: "auth_fallback",
|
||||
Invites: "invites",
|
||||
|
|
|
@ -26,8 +26,8 @@ import (
|
|||
|
||||
migrate "github.com/rubenv/sql-migrate"
|
||||
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/roomdb"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/internal/repo"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/roomdb"
|
||||
)
|
||||
|
||||
type Database struct {
|
||||
|
|
|
@ -40,8 +40,8 @@ func (al AllowList) add(ctx context.Context, tx *sql.Tx, a refs.FeedRef) error {
|
|||
}
|
||||
|
||||
var entry models.AllowList
|
||||
|
||||
entry.PubKey.FeedRef = a
|
||||
|
||||
err := entry.Insert(ctx, tx, boil.Whitelist("pub_key"))
|
||||
if err != nil {
|
||||
var sqlErr sqlite3.Error
|
||||
|
@ -99,7 +99,6 @@ func (al AllowList) List(ctx context.Context) (roomdb.ListEntries, error) {
|
|||
|
||||
var asRefs = make(roomdb.ListEntries, len(all))
|
||||
for i, allowed := range all {
|
||||
|
||||
asRefs[i] = roomdb.ListEntry{
|
||||
ID: allowed.ID,
|
||||
PubKey: allowed.PubKey.FeedRef,
|
||||
|
|
|
@ -14,6 +14,17 @@ import (
|
|||
// ErrNotFound is returned by the admin db if an object couldn't be found.
|
||||
var ErrNotFound = errors.New("roomdb: object not found")
|
||||
|
||||
// Alias is how the roomdb stores an alias.
|
||||
type Alias struct {
|
||||
ID int64
|
||||
|
||||
Name string // or "alias string" as the docs call it
|
||||
|
||||
Feed refs.FeedRef // the ssb identity that belongs to the user
|
||||
|
||||
Signature []byte
|
||||
}
|
||||
|
||||
// User holds all the information an authenticated user of the site has.
|
||||
type User struct {
|
||||
ID int64
|
||||
|
|
Loading…
Reference in New Issue