new payment methods service
This commit is contained in:
235
api/payments/storage/mongo/store/payment_methods.go
Normal file
235
api/payments/storage/mongo/store/payment_methods.go
Normal file
@@ -0,0 +1,235 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/tech/sendico/payments/storage"
|
||||
"github.com/tech/sendico/pkg/auth"
|
||||
"github.com/tech/sendico/pkg/db/repository"
|
||||
ri "github.com/tech/sendico/pkg/db/repository/index"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
pkgmodel "github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/mservice"
|
||||
mauth "github.com/tech/sendico/pkg/mutil/db/auth"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type PaymentMethods struct {
|
||||
logger mlogger.Logger
|
||||
repo repository.Repository
|
||||
enforcer auth.Enforcer
|
||||
permissionRef bson.ObjectID
|
||||
}
|
||||
|
||||
// NewPaymentMethods constructs a Mongo-backed payment-methods store.
|
||||
func NewPaymentMethods(logger mlogger.Logger, repo repository.Repository, enforcer auth.Enforcer, permissionRef bson.ObjectID) (*PaymentMethods, error) {
|
||||
if repo == nil {
|
||||
return nil, merrors.InvalidArgument("paymentMethodsStore: repository is nil")
|
||||
}
|
||||
if enforcer == nil {
|
||||
return nil, merrors.InvalidArgument("paymentMethodsStore: enforcer is nil")
|
||||
}
|
||||
if permissionRef == bson.NilObjectID {
|
||||
return nil, merrors.InvalidArgument("paymentMethodsStore: permission reference is required")
|
||||
}
|
||||
|
||||
indexes := []*ri.Definition{
|
||||
{
|
||||
Keys: []ri.Key{
|
||||
{Field: "organizationRef", Sort: ri.Asc},
|
||||
{Field: "recipientRef", Sort: ri.Asc},
|
||||
},
|
||||
},
|
||||
{
|
||||
Keys: []ri.Key{{Field: "recipientRef", Sort: ri.Asc}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, def := range indexes {
|
||||
if err := repo.CreateIndex(def); err != nil {
|
||||
logger.Error("failed to ensure payment methods index", zap.Error(err), zap.String("collection", repo.Collection()))
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &PaymentMethods{
|
||||
logger: logger.Named("payment_methods"),
|
||||
repo: repo,
|
||||
enforcer: enforcer,
|
||||
permissionRef: permissionRef,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *PaymentMethods) Create(ctx context.Context, accountRef, organizationRef bson.ObjectID, method *pkgmodel.PaymentMethod) error {
|
||||
if method == nil {
|
||||
return merrors.InvalidArgument("paymentMethodsStore: nil payment method")
|
||||
}
|
||||
if accountRef == bson.NilObjectID {
|
||||
return merrors.InvalidArgument("paymentMethodsStore: account_ref is required")
|
||||
}
|
||||
if organizationRef == bson.NilObjectID {
|
||||
return merrors.InvalidArgument("paymentMethodsStore: organization_ref is required")
|
||||
}
|
||||
if method.RecipientRef == bson.NilObjectID {
|
||||
return merrors.InvalidArgument("paymentMethodsStore: recipient_ref is required")
|
||||
}
|
||||
|
||||
if method.GetPermissionRef() == bson.NilObjectID {
|
||||
method.SetPermissionRef(p.permissionRef)
|
||||
}
|
||||
method.SetOrganizationRef(organizationRef)
|
||||
|
||||
allowed, err := p.enforcer.Enforce(ctx, method.GetPermissionRef(), accountRef, organizationRef, bson.NilObjectID, pkgmodel.ActionCreate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !allowed {
|
||||
return merrors.AccessDenied(mservice.PaymentMethods, string(pkgmodel.ActionCreate), bson.NilObjectID)
|
||||
}
|
||||
|
||||
return p.repo.Insert(ctx, method, nil)
|
||||
}
|
||||
|
||||
func (p *PaymentMethods) Get(ctx context.Context, accountRef, methodRef bson.ObjectID) (*pkgmodel.PaymentMethod, error) {
|
||||
if accountRef == bson.NilObjectID {
|
||||
return nil, merrors.InvalidArgument("paymentMethodsStore: account_ref is required")
|
||||
}
|
||||
if methodRef == bson.NilObjectID {
|
||||
return nil, merrors.InvalidArgument("paymentMethodsStore: method_ref is required")
|
||||
}
|
||||
|
||||
if err := p.enforceObject(ctx, accountRef, methodRef, pkgmodel.ActionRead); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
method := &pkgmodel.PaymentMethod{}
|
||||
if err := p.repo.Get(ctx, methodRef, method); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return method, nil
|
||||
}
|
||||
|
||||
func (p *PaymentMethods) Update(ctx context.Context, accountRef bson.ObjectID, method *pkgmodel.PaymentMethod) error {
|
||||
if method == nil {
|
||||
return merrors.InvalidArgument("paymentMethodsStore: nil payment method")
|
||||
}
|
||||
if accountRef == bson.NilObjectID {
|
||||
return merrors.InvalidArgument("paymentMethodsStore: account_ref is required")
|
||||
}
|
||||
if method.GetID() == nil || method.GetID().IsZero() {
|
||||
return merrors.InvalidArgument("paymentMethodsStore: method id is required")
|
||||
}
|
||||
|
||||
if err := p.enforceObject(ctx, accountRef, *method.GetID(), pkgmodel.ActionUpdate); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return p.repo.Update(ctx, method)
|
||||
}
|
||||
|
||||
func (p *PaymentMethods) Delete(ctx context.Context, accountRef, methodRef bson.ObjectID) error {
|
||||
if accountRef == bson.NilObjectID {
|
||||
return merrors.InvalidArgument("paymentMethodsStore: account_ref is required")
|
||||
}
|
||||
if methodRef == bson.NilObjectID {
|
||||
return merrors.InvalidArgument("paymentMethodsStore: method_ref is required")
|
||||
}
|
||||
|
||||
if err := p.enforceObject(ctx, accountRef, methodRef, pkgmodel.ActionDelete); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return p.repo.Delete(ctx, methodRef)
|
||||
}
|
||||
|
||||
func (p *PaymentMethods) DeleteCascade(ctx context.Context, accountRef, methodRef bson.ObjectID) error {
|
||||
return p.Delete(ctx, accountRef, methodRef)
|
||||
}
|
||||
|
||||
func (p *PaymentMethods) SetArchived(ctx context.Context, accountRef, _ bson.ObjectID, methodRef bson.ObjectID, archived, _ bool) error {
|
||||
if accountRef == bson.NilObjectID {
|
||||
return merrors.InvalidArgument("paymentMethodsStore: account_ref is required")
|
||||
}
|
||||
if methodRef == bson.NilObjectID {
|
||||
return merrors.InvalidArgument("paymentMethodsStore: method_ref is required")
|
||||
}
|
||||
|
||||
if err := p.enforceObject(ctx, accountRef, methodRef, pkgmodel.ActionUpdate); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
patch := repository.Patch().Set(repository.Field("isArchived"), archived)
|
||||
return p.repo.Patch(ctx, methodRef, patch)
|
||||
}
|
||||
|
||||
func (p *PaymentMethods) List(ctx context.Context, accountRef, organizationRef, recipientRef bson.ObjectID, cursor *pkgmodel.ViewCursor) ([]pkgmodel.PaymentMethod, error) {
|
||||
if accountRef == bson.NilObjectID {
|
||||
return nil, merrors.InvalidArgument("paymentMethodsStore: account_ref is required")
|
||||
}
|
||||
if organizationRef == bson.NilObjectID {
|
||||
return nil, merrors.InvalidArgument("paymentMethodsStore: organization_ref is required")
|
||||
}
|
||||
if recipientRef == bson.NilObjectID {
|
||||
return nil, merrors.InvalidArgument("paymentMethodsStore: recipient_ref is required")
|
||||
}
|
||||
|
||||
items, err := mauth.GetProtectedObjects[pkgmodel.PaymentMethod](
|
||||
ctx,
|
||||
p.logger,
|
||||
accountRef,
|
||||
organizationRef,
|
||||
pkgmodel.ActionRead,
|
||||
repository.OrgFilter(organizationRef).And(repository.Filter("recipientRef", recipientRef)),
|
||||
cursor,
|
||||
p.enforcer,
|
||||
p.repo,
|
||||
)
|
||||
if errors.Is(err, merrors.ErrNoData) {
|
||||
return []pkgmodel.PaymentMethod{}, nil
|
||||
}
|
||||
return items, err
|
||||
}
|
||||
|
||||
func (p *PaymentMethods) SetArchivedByRecipient(ctx context.Context, recipientRef bson.ObjectID, archived bool) (int, error) {
|
||||
if recipientRef == bson.NilObjectID {
|
||||
return 0, merrors.InvalidArgument("paymentMethodsStore: recipient_ref is required")
|
||||
}
|
||||
|
||||
filter := repository.Filter("recipientRef", recipientRef)
|
||||
patch := repository.Patch().Set(repository.Field("isArchived"), archived)
|
||||
return p.repo.PatchMany(ctx, filter, patch)
|
||||
}
|
||||
|
||||
func (p *PaymentMethods) DeleteByRecipient(ctx context.Context, recipientRef bson.ObjectID) error {
|
||||
if recipientRef == bson.NilObjectID {
|
||||
return merrors.InvalidArgument("paymentMethodsStore: recipient_ref is required")
|
||||
}
|
||||
return p.repo.DeleteMany(ctx, repository.Filter("recipientRef", recipientRef))
|
||||
}
|
||||
|
||||
func (p *PaymentMethods) enforceObject(ctx context.Context, accountRef, methodRef bson.ObjectID, action pkgmodel.Action) error {
|
||||
refs, err := p.repo.ListPermissionBound(ctx, repository.IDFilter(methodRef))
|
||||
if err != nil {
|
||||
if errors.Is(err, merrors.ErrNoData) {
|
||||
return merrors.AccessDenied(mservice.PaymentMethods, string(action), methodRef)
|
||||
}
|
||||
return err
|
||||
}
|
||||
if len(refs) == 0 {
|
||||
return merrors.AccessDenied(mservice.PaymentMethods, string(action), methodRef)
|
||||
}
|
||||
|
||||
allowed, err := p.enforcer.Enforce(ctx, refs[0].GetPermissionRef(), accountRef, refs[0].GetOrganizationRef(), methodRef, action)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !allowed {
|
||||
return merrors.AccessDenied(mservice.PaymentMethods, string(action), methodRef)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ storage.PaymentMethodsStore = (*PaymentMethods)(nil)
|
||||
Reference in New Issue
Block a user