stillbox/pkg/users/store.go

122 lines
2.7 KiB
Go
Raw Normal View History

package users
import (
"context"
"dynatron.me/x/stillbox/internal/cache"
"dynatron.me/x/stillbox/pkg/database"
)
type Store interface {
// GetUser gets a user by UID.
GetUser(ctx context.Context, username string) (*User, error)
// UserPrefs gets the preferences for the specified user and app name.
UserPrefs(ctx context.Context, username string, appName string) ([]byte, error)
// SetUserPrefs sets the preferences for the specified user and app name.
SetUserPrefs(ctx context.Context, username string, appName string, prefs []byte) error
// Invalidate clears the user cache.
Invalidate()
// UpdateUser updates a user's record
UpdateUser(ctx context.Context, username string, user UserUpdate) error
// GetUserByAPIKey gets a user by API key.
GetAPIKey(ctx context.Context, key string) (database.GetAPIKeyRow, error)
}
type postgresStore struct {
cache.Cache[string, *User]
db database.Store
}
func NewStore(db database.Store) *postgresStore {
return &postgresStore{
Cache: cache.New[string, *User](),
db: db,
}
}
type storeCtxKey string
const StoreCtxKey storeCtxKey = "store"
func CtxWithStore(ctx context.Context, s Store) context.Context {
return context.WithValue(ctx, StoreCtxKey, s)
}
func FromCtx(ctx context.Context) Store {
s, ok := ctx.Value(StoreCtxKey).(Store)
if !ok {
panic("no users store in context")
}
return s
}
func (s *postgresStore) Invalidate() {
s.Clear()
}
type UserUpdate struct {
Email *string `json:"email"`
IsAdmin *bool `json:"isAdmin"`
}
func (s *postgresStore) UpdateUser(ctx context.Context, username string, user UserUpdate) error {
dbu, err := s.db.UpdateUser(ctx, username, user.Email, user.IsAdmin)
if err != nil {
return err
}
s.Set(username, fromDBUser(dbu))
return nil
}
func (s *postgresStore) GetUser(ctx context.Context, username string) (*User, error) {
u, has := s.Get(username)
if has {
return u, nil
}
dbu, err := s.db.GetUserByUsername(ctx, username)
if err != nil {
return nil, err
}
u = fromDBUser(dbu)
s.Set(username, u)
return u, nil
}
func (s *postgresStore) UserPrefs(ctx context.Context, username string, appName string) ([]byte, error) {
u, err := s.GetUser(ctx, username)
if err != nil {
return nil, err
}
prefs, err := s.db.GetAppPrefs(ctx, appName, int(u.ID))
if err != nil {
return nil, err
}
return []byte(prefs), err
}
func (s *postgresStore) SetUserPrefs(ctx context.Context, username string, appName string, prefs []byte) error {
u, err := s.GetUser(ctx, username)
if err != nil {
return err
}
return s.db.SetAppPrefs(ctx, appName, prefs, int(u.ID))
}
func (s *postgresStore) GetAPIKey(ctx context.Context, b64hash string) (database.GetAPIKeyRow, error) {
return s.db.GetAPIKey(ctx, b64hash)
}