114 lines
2.6 KiB
Go
114 lines
2.6 KiB
Go
package shares
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"dynatron.me/x/stillbox/internal/jsontypes"
|
|
"dynatron.me/x/stillbox/pkg/database"
|
|
"dynatron.me/x/stillbox/pkg/rbac"
|
|
"dynatron.me/x/stillbox/pkg/rbac/entities"
|
|
"dynatron.me/x/stillbox/pkg/users"
|
|
"github.com/jackc/pgx/v5"
|
|
)
|
|
|
|
type Shares interface {
|
|
// NewShare creates a new share.
|
|
NewShare(ctx context.Context, sh CreateShareParams) (*Share, error)
|
|
|
|
// Share retreives a share record.
|
|
GetShare(ctx context.Context, id string) (*Share, error)
|
|
|
|
// Create stores a new share record.
|
|
Create(ctx context.Context, share *Share) error
|
|
|
|
// Delete deletes a share record.
|
|
Delete(ctx context.Context, id string) error
|
|
|
|
// Prune removes expired share records.
|
|
Prune(ctx context.Context) error
|
|
}
|
|
|
|
type postgresStore struct {
|
|
}
|
|
|
|
var (
|
|
ErrNoShare = errors.New("no such share")
|
|
)
|
|
|
|
func recToShare(share database.Share) *Share {
|
|
return &Share{
|
|
ID: share.ID,
|
|
Type: EntityType(share.EntityType),
|
|
EntityID: share.EntityID,
|
|
Date: jsontypes.TimePtrFromTSTZ(share.EntityDate),
|
|
Expiration: jsontypes.TimePtrFromTSTZ(share.Expiration),
|
|
Owner: users.UserID(share.Owner),
|
|
}
|
|
}
|
|
|
|
func (s *postgresStore) GetShare(ctx context.Context, id string) (*Share, error) {
|
|
db := database.FromCtx(ctx)
|
|
rec, err := db.GetShare(ctx, id)
|
|
switch err {
|
|
case nil:
|
|
return recToShare(rec), nil
|
|
case pgx.ErrNoRows:
|
|
return nil, ErrNoShare
|
|
default:
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
func (s *postgresStore) Create(ctx context.Context, share *Share) error {
|
|
sub, err := users.UserCheck(ctx, new(Share), "create")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
db := database.FromCtx(ctx)
|
|
err = db.CreateShare(ctx, database.CreateShareParams{
|
|
ID: share.ID,
|
|
EntityType: string(share.Type),
|
|
EntityID: share.EntityID,
|
|
EntityDate: share.Date.PGTypeTSTZ(),
|
|
Expiration: share.Expiration.PGTypeTSTZ(),
|
|
Owner: sub.ID.Int(),
|
|
})
|
|
|
|
return err
|
|
}
|
|
|
|
func (s *postgresStore) Delete(ctx context.Context, id string) error {
|
|
_, err := rbac.Check(ctx, new(Share), rbac.WithActions(entities.ActionDelete))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return database.FromCtx(ctx).DeleteShare(ctx, id)
|
|
}
|
|
|
|
func (s *postgresStore) Prune(ctx context.Context) error {
|
|
return database.FromCtx(ctx).PruneShares(ctx)
|
|
}
|
|
|
|
func NewStore() *postgresStore {
|
|
return new(postgresStore)
|
|
}
|
|
|
|
type storeCtxKey string
|
|
|
|
const StoreCtxKey storeCtxKey = "store"
|
|
|
|
func CtxWithStore(ctx context.Context, s Shares) context.Context {
|
|
return context.WithValue(ctx, StoreCtxKey, s)
|
|
}
|
|
|
|
func FromCtx(ctx context.Context) Shares {
|
|
s, ok := ctx.Value(StoreCtxKey).(Shares)
|
|
if !ok {
|
|
panic("no shares store in context")
|
|
}
|
|
|
|
return s
|
|
}
|