move api/server to api/edge/bff
This commit is contained in:
621
api/edge/bff/internal/server/paymethodsimp/service.go
Normal file
621
api/edge/bff/internal/server/paymethodsimp/service.go
Normal file
@@ -0,0 +1,621 @@
|
||||
package paymethodsimp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
methodsclient "github.com/tech/sendico/payments/methods/client"
|
||||
api "github.com/tech/sendico/pkg/api/http"
|
||||
"github.com/tech/sendico/pkg/api/http/response"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/mservice"
|
||||
archivablev1 "github.com/tech/sendico/pkg/proto/common/archivable/v1"
|
||||
describablev1 "github.com/tech/sendico/pkg/proto/common/describable/v1"
|
||||
oboundv1 "github.com/tech/sendico/pkg/proto/common/organization_bound/v1"
|
||||
paginationv2 "github.com/tech/sendico/pkg/proto/common/pagination/v2"
|
||||
pboundv1 "github.com/tech/sendico/pkg/proto/common/permission_bound/v1"
|
||||
storablev1 "github.com/tech/sendico/pkg/proto/common/storable/v1"
|
||||
endpointv1 "github.com/tech/sendico/pkg/proto/payments/endpoint/v1"
|
||||
methodsv1 "github.com/tech/sendico/pkg/proto/payments/methods/v1"
|
||||
eapi "github.com/tech/sendico/server/interface/api"
|
||||
"github.com/tech/sendico/server/interface/api/sresponse"
|
||||
mutil "github.com/tech/sendico/server/internal/mutil/param"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
)
|
||||
|
||||
type PaymentMethodsAPI struct {
|
||||
logger mlogger.Logger
|
||||
client methodsclient.Client
|
||||
oph mutil.ParamHelper
|
||||
rph mutil.ParamHelper
|
||||
mph mutil.ParamHelper
|
||||
}
|
||||
|
||||
func (a *PaymentMethodsAPI) Name() mservice.Type {
|
||||
return mservice.PaymentMethods
|
||||
}
|
||||
|
||||
func (a *PaymentMethodsAPI) Finish(_ context.Context) error {
|
||||
if a.client != nil {
|
||||
return a.client.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateAPI(apiCtx eapi.API) (*PaymentMethodsAPI, error) {
|
||||
logger := apiCtx.Logger().Named(mservice.PaymentMethods)
|
||||
|
||||
cfg := apiCtx.Config().PaymentMethods
|
||||
if cfg == nil {
|
||||
return nil, merrors.InvalidArgument("payment methods configuration is not provided")
|
||||
}
|
||||
|
||||
address, err := resolveClientAddress("payment methods", cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
clientCfg := methodsclient.Config{
|
||||
Address: address,
|
||||
DialTimeout: time.Duration(cfg.DialTimeoutSeconds) * time.Second,
|
||||
CallTimeout: time.Duration(cfg.CallTimeoutSeconds) * time.Second,
|
||||
Insecure: cfg.Insecure,
|
||||
}
|
||||
|
||||
client, err := methodsclient.New(context.Background(), clientCfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := &PaymentMethodsAPI{
|
||||
logger: logger,
|
||||
client: client,
|
||||
oph: mutil.CreatePH(mservice.Organizations),
|
||||
rph: mutil.CreatePH(mservice.Recipients),
|
||||
mph: mutil.CreatePH(mservice.PaymentMethods),
|
||||
}
|
||||
|
||||
apiCtx.Register().AccountHandler(res.Name(), res.oph.AddRef("/"), api.Post, res.create)
|
||||
apiCtx.Register().AccountHandler(res.Name(), res.rph.AddRef(res.oph.AddRef("/list")), api.Get, res.list)
|
||||
apiCtx.Register().AccountHandler(res.Name(), res.mph.AddRef("/"), api.Get, res.get)
|
||||
apiCtx.Register().AccountHandler(res.Name(), "/", api.Put, res.update)
|
||||
apiCtx.Register().AccountHandler(res.Name(), res.mph.AddRef("/"), api.Delete, res.delete)
|
||||
apiCtx.Register().AccountHandler(res.Name(), res.mph.AddRef(res.oph.AddRef("/archive")), api.Get, res.archive)
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (a *PaymentMethodsAPI) create(r *http.Request, account *model.Account, token *sresponse.TokenData) http.HandlerFunc {
|
||||
orgRef, err := a.oph.GetRef(r)
|
||||
if err != nil {
|
||||
return response.BadReference(a.logger, a.Name(), a.oph.Name(), a.oph.GetID(r), err)
|
||||
}
|
||||
|
||||
payload, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return response.BadPayload(a.logger, a.Name(), err)
|
||||
}
|
||||
pm, err := decodePaymentMethodJSON(payload)
|
||||
if err != nil {
|
||||
return response.BadPayload(a.logger, a.Name(), err)
|
||||
}
|
||||
method, err := encodePaymentMethodProto(pm)
|
||||
if err != nil {
|
||||
return response.Internal(a.logger, a.Name(), err)
|
||||
}
|
||||
|
||||
resp, err := a.client.CreatePaymentMethod(r.Context(), &methodsv1.CreatePaymentMethodRequest{
|
||||
AccountRef: account.ID.Hex(),
|
||||
OrganizationRef: orgRef.Hex(),
|
||||
PaymentMethod: method,
|
||||
})
|
||||
if err != nil {
|
||||
return grpcErrorResponse(a.logger, a.Name(), err)
|
||||
}
|
||||
|
||||
pm, err = decodePaymentMethodRecord(resp.GetPaymentMethodRecord())
|
||||
if err != nil {
|
||||
return response.Internal(a.logger, a.Name(), err)
|
||||
}
|
||||
return sresponse.ObjectAuthCreated(a.logger, pm, token, a.Name())
|
||||
}
|
||||
|
||||
func (a *PaymentMethodsAPI) list(r *http.Request, account *model.Account, token *sresponse.TokenData) http.HandlerFunc {
|
||||
orgRef, err := a.oph.GetRef(r)
|
||||
if err != nil {
|
||||
return response.BadReference(a.logger, a.Name(), a.oph.Name(), a.oph.GetID(r), err)
|
||||
}
|
||||
recipientRef, err := a.rph.GetRef(r)
|
||||
if err != nil {
|
||||
return response.BadReference(a.logger, a.Name(), a.rph.Name(), a.rph.GetID(r), err)
|
||||
}
|
||||
|
||||
cursor, err := mutil.GetViewCursor(a.logger, r)
|
||||
if err != nil {
|
||||
return response.Auto(a.logger, a.Name(), err)
|
||||
}
|
||||
|
||||
resp, err := a.client.ListPaymentMethods(r.Context(), &methodsv1.ListPaymentMethodsRequest{
|
||||
AccountRef: account.ID.Hex(),
|
||||
OrganizationRef: orgRef.Hex(),
|
||||
RecipientRef: recipientRef.Hex(),
|
||||
Cursor: toProtoCursor(cursor),
|
||||
})
|
||||
if err != nil {
|
||||
return grpcErrorResponse(a.logger, a.Name(), err)
|
||||
}
|
||||
|
||||
items, err := decodePaymentMethods(resp.GetPaymentMethods())
|
||||
if err != nil {
|
||||
return response.Internal(a.logger, a.Name(), err)
|
||||
}
|
||||
return sresponse.ObjectsAuth(a.logger, items, token, a.Name())
|
||||
}
|
||||
|
||||
func (a *PaymentMethodsAPI) get(r *http.Request, account *model.Account, token *sresponse.TokenData) http.HandlerFunc {
|
||||
methodRef, err := a.mph.GetRef(r)
|
||||
if err != nil {
|
||||
return response.BadReference(a.logger, a.Name(), a.mph.Name(), a.mph.GetID(r), err)
|
||||
}
|
||||
|
||||
resp, err := a.client.GetPaymentMethod(r.Context(), &methodsv1.GetPaymentMethodRequest{
|
||||
AccountRef: account.ID.Hex(),
|
||||
PaymentMethodRef: methodRef.Hex(),
|
||||
})
|
||||
if err != nil {
|
||||
return grpcErrorResponse(a.logger, a.Name(), err)
|
||||
}
|
||||
|
||||
pm, err := decodePaymentMethodRecord(resp.GetPaymentMethodRecord())
|
||||
if err != nil {
|
||||
return response.Internal(a.logger, a.Name(), err)
|
||||
}
|
||||
return sresponse.ObjectAuth(a.logger, pm, token, a.Name())
|
||||
}
|
||||
|
||||
func (a *PaymentMethodsAPI) update(r *http.Request, account *model.Account, token *sresponse.TokenData) http.HandlerFunc {
|
||||
payload, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return response.BadPayload(a.logger, a.Name(), err)
|
||||
}
|
||||
pm, err := decodePaymentMethodJSON(payload)
|
||||
if err != nil {
|
||||
return response.BadPayload(a.logger, a.Name(), err)
|
||||
}
|
||||
record, err := encodePaymentMethodRecord(pm)
|
||||
if err != nil {
|
||||
return response.Internal(a.logger, a.Name(), err)
|
||||
}
|
||||
|
||||
resp, err := a.client.UpdatePaymentMethod(r.Context(), &methodsv1.UpdatePaymentMethodRequest{
|
||||
AccountRef: account.ID.Hex(),
|
||||
PaymentMethodRecord: record,
|
||||
})
|
||||
if err != nil {
|
||||
return grpcErrorResponse(a.logger, a.Name(), err)
|
||||
}
|
||||
|
||||
pm, err = decodePaymentMethodRecord(resp.GetPaymentMethodRecord())
|
||||
if err != nil {
|
||||
return response.Internal(a.logger, a.Name(), err)
|
||||
}
|
||||
return sresponse.ObjectAuth(a.logger, pm, token, a.Name())
|
||||
}
|
||||
|
||||
func (a *PaymentMethodsAPI) delete(r *http.Request, account *model.Account, token *sresponse.TokenData) http.HandlerFunc {
|
||||
methodRef, err := a.mph.GetRef(r)
|
||||
if err != nil {
|
||||
return response.BadReference(a.logger, a.Name(), a.mph.Name(), a.mph.GetID(r), err)
|
||||
}
|
||||
|
||||
cascade, err := mutil.GetCascadeParam(a.logger, r)
|
||||
if err != nil {
|
||||
return response.Auto(a.logger, a.Name(), err)
|
||||
}
|
||||
|
||||
cascadeValue := false
|
||||
if cascade != nil {
|
||||
cascadeValue = *cascade
|
||||
}
|
||||
|
||||
_, err = a.client.DeletePaymentMethod(r.Context(), &methodsv1.DeletePaymentMethodRequest{
|
||||
AccountRef: account.ID.Hex(),
|
||||
PaymentMethodRef: methodRef.Hex(),
|
||||
Cascade: cascadeValue,
|
||||
})
|
||||
if err != nil {
|
||||
return grpcErrorResponse(a.logger, a.Name(), err)
|
||||
}
|
||||
|
||||
return sresponse.ObjectsAuth(a.logger, []model.PaymentMethod{}, token, a.Name())
|
||||
}
|
||||
|
||||
func (a *PaymentMethodsAPI) archive(r *http.Request, account *model.Account, token *sresponse.TokenData) http.HandlerFunc {
|
||||
methodRef, err := a.mph.GetRef(r)
|
||||
if err != nil {
|
||||
return response.BadReference(a.logger, a.Name(), a.mph.Name(), a.mph.GetID(r), err)
|
||||
}
|
||||
orgRef, err := a.oph.GetRef(r)
|
||||
if err != nil {
|
||||
return response.BadReference(a.logger, a.Name(), a.oph.Name(), a.oph.GetID(r), err)
|
||||
}
|
||||
|
||||
archived, err := mutil.GetArchiveParam(a.logger, r)
|
||||
if err != nil {
|
||||
return response.Auto(a.logger, a.Name(), err)
|
||||
}
|
||||
if archived == nil {
|
||||
return response.BadRequest(a.logger, a.Name(), "invalid_query_parameter", "'archived' param must be present")
|
||||
}
|
||||
|
||||
cascade, err := mutil.GetCascadeParam(a.logger, r)
|
||||
if err != nil {
|
||||
return response.Auto(a.logger, a.Name(), err)
|
||||
}
|
||||
cascadeValue := false
|
||||
if cascade != nil {
|
||||
cascadeValue = *cascade
|
||||
}
|
||||
|
||||
_, err = a.client.SetPaymentMethodArchived(r.Context(), &methodsv1.SetPaymentMethodArchivedRequest{
|
||||
AccountRef: account.ID.Hex(),
|
||||
OrganizationRef: orgRef.Hex(),
|
||||
PaymentMethodRef: methodRef.Hex(),
|
||||
Archived: *archived,
|
||||
Cascade: cascadeValue,
|
||||
})
|
||||
if err != nil {
|
||||
return grpcErrorResponse(a.logger, a.Name(), err)
|
||||
}
|
||||
|
||||
return sresponse.ObjectsAuth(a.logger, []model.PaymentMethod{}, token, a.Name())
|
||||
}
|
||||
|
||||
func resolveClientAddress(service string, cfg *eapi.PaymentOrchestratorConfig) (string, error) {
|
||||
if cfg == nil {
|
||||
return "", merrors.InvalidArgument(strings.TrimSpace(service) + " configuration is not provided")
|
||||
}
|
||||
address := strings.TrimSpace(cfg.Address)
|
||||
if address != "" {
|
||||
return address, nil
|
||||
}
|
||||
if env := strings.TrimSpace(cfg.AddressEnv); env != "" {
|
||||
if resolved := strings.TrimSpace(os.Getenv(env)); resolved != "" {
|
||||
return resolved, nil
|
||||
}
|
||||
return "", merrors.InvalidArgument(service + " address is not specified and address env " + env + " is empty")
|
||||
}
|
||||
return "", merrors.InvalidArgument(strings.TrimSpace(service) + " address is not specified")
|
||||
}
|
||||
|
||||
func toProtoCursor(cursor *model.ViewCursor) *paginationv2.ViewCursor {
|
||||
if cursor == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
res := &paginationv2.ViewCursor{}
|
||||
hasAny := false
|
||||
if cursor.Limit != nil {
|
||||
res.Limit = wrapperspb.Int64(*cursor.Limit)
|
||||
hasAny = true
|
||||
}
|
||||
if cursor.Offset != nil {
|
||||
res.Offset = wrapperspb.Int64(*cursor.Offset)
|
||||
hasAny = true
|
||||
}
|
||||
if cursor.IsArchived != nil {
|
||||
res.IsArchived = wrapperspb.Bool(*cursor.IsArchived)
|
||||
hasAny = true
|
||||
}
|
||||
if !hasAny {
|
||||
return nil
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func decodePaymentMethodJSON(payload []byte) (*model.PaymentMethod, error) {
|
||||
var pm model.PaymentMethod
|
||||
if err := json.Unmarshal(payload, &pm); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pm, nil
|
||||
}
|
||||
|
||||
func decodePaymentMethodRecord(record *endpointv1.PaymentMethodRecord) (*model.PaymentMethod, error) {
|
||||
if record == nil {
|
||||
return nil, merrors.InvalidArgument("payment_method_record is required")
|
||||
}
|
||||
pm, err := decodePaymentMethodProto(record.GetPaymentMethod())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := applyPermissionBound(pm, record.GetPermissionBound()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pm, nil
|
||||
}
|
||||
|
||||
func decodePaymentMethodProto(method *endpointv1.PaymentMethod) (*model.PaymentMethod, error) {
|
||||
if method == nil {
|
||||
return nil, merrors.InvalidArgument("payment_method is required")
|
||||
}
|
||||
|
||||
recipientRef, err := parseRequiredObjectID(method.GetRecipientRef(), "payment_method.recipient_ref")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pt, err := paymentTypeFromProto(method.GetType(), "payment_method.type")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &model.PaymentMethod{
|
||||
Describable: describableFromProto(method.GetDescribable()),
|
||||
RecipientRef: recipientRef,
|
||||
Type: pt,
|
||||
Data: cloneBytes(method.GetData()),
|
||||
IsMain: method.GetIsMain(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func encodePaymentMethodProto(pm *model.PaymentMethod) (*endpointv1.PaymentMethod, error) {
|
||||
if pm == nil {
|
||||
return nil, merrors.InvalidArgument("payment method is required")
|
||||
}
|
||||
pt, err := paymentTypeToProto(pm.Type)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &endpointv1.PaymentMethod{
|
||||
Describable: describableToProto(pm.Describable),
|
||||
RecipientRef: toObjectHex(pm.RecipientRef),
|
||||
Type: pt,
|
||||
Data: cloneBytes(pm.Data),
|
||||
IsMain: pm.IsMain,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func encodePaymentMethodRecord(pm *model.PaymentMethod) (*endpointv1.PaymentMethodRecord, error) {
|
||||
method, err := encodePaymentMethodProto(pm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &endpointv1.PaymentMethodRecord{
|
||||
PermissionBound: permissionBoundFromModel(pm),
|
||||
PaymentMethod: method,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func decodePaymentMethods(items []*endpointv1.PaymentMethodRecord) ([]model.PaymentMethod, error) {
|
||||
if len(items) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
res := make([]model.PaymentMethod, 0, len(items))
|
||||
for i := range items {
|
||||
pm, err := decodePaymentMethodRecord(items[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = append(res, *pm)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func paymentTypeFromProto(value endpointv1.PaymentMethodType, field string) (model.PaymentType, error) {
|
||||
switch value {
|
||||
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_IBAN:
|
||||
return model.PaymentTypeIban, nil
|
||||
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_CARD:
|
||||
return model.PaymentTypeCard, nil
|
||||
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_CARD_TOKEN:
|
||||
return model.PaymentTypeCardToken, nil
|
||||
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_BANK_ACCOUNT:
|
||||
return model.PaymentTypeBankAccount, nil
|
||||
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_WALLET:
|
||||
return model.PaymentTypeWallet, nil
|
||||
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_CRYPTO_ADDRESS:
|
||||
return model.PaymentTypeCryptoAddress, nil
|
||||
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_LEDGER:
|
||||
return model.PaymentTypeLedger, nil
|
||||
default:
|
||||
return model.PaymentTypeIban, merrors.InvalidArgument(fmt.Sprintf("%s has unsupported value: %s", field, value.String()), field)
|
||||
}
|
||||
}
|
||||
|
||||
func paymentTypeToProto(value model.PaymentType) (endpointv1.PaymentMethodType, error) {
|
||||
switch value {
|
||||
case model.PaymentTypeIban:
|
||||
return endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_IBAN, nil
|
||||
case model.PaymentTypeCard:
|
||||
return endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_CARD, nil
|
||||
case model.PaymentTypeCardToken:
|
||||
return endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_CARD_TOKEN, nil
|
||||
case model.PaymentTypeBankAccount:
|
||||
return endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_BANK_ACCOUNT, nil
|
||||
case model.PaymentTypeWallet:
|
||||
return endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_WALLET, nil
|
||||
case model.PaymentTypeCryptoAddress:
|
||||
return endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_CRYPTO_ADDRESS, nil
|
||||
case model.PaymentTypeLedger:
|
||||
return endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_LEDGER, nil
|
||||
default:
|
||||
return endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_UNSPECIFIED, merrors.InvalidArgument(fmt.Sprintf("unsupported payment method type: %s", value.String()), "type")
|
||||
}
|
||||
}
|
||||
|
||||
func describableFromProto(src *describablev1.Describable) model.Describable {
|
||||
if src == nil {
|
||||
return model.Describable{}
|
||||
}
|
||||
res := model.Describable{Name: src.GetName()}
|
||||
if src.Description != nil {
|
||||
v := src.GetDescription()
|
||||
res.Description = &v
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func describableToProto(src model.Describable) *describablev1.Describable {
|
||||
if strings.TrimSpace(src.Name) == "" && src.Description == nil {
|
||||
return nil
|
||||
}
|
||||
res := &describablev1.Describable{
|
||||
Name: src.Name,
|
||||
}
|
||||
if src.Description != nil {
|
||||
v := *src.Description
|
||||
res.Description = &v
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func cloneBytes(src []byte) []byte {
|
||||
if len(src) == 0 {
|
||||
return nil
|
||||
}
|
||||
dst := make([]byte, len(src))
|
||||
copy(dst, src)
|
||||
return dst
|
||||
}
|
||||
|
||||
func permissionBoundFromModel(pm *model.PaymentMethod) *pboundv1.PermissionBound {
|
||||
if pm == nil {
|
||||
return nil
|
||||
}
|
||||
return &pboundv1.PermissionBound{
|
||||
Storable: &storablev1.Storable{
|
||||
Id: toObjectHex(pm.ID),
|
||||
CreatedAt: toProtoTime(pm.CreatedAt),
|
||||
UpdatedAt: toProtoTime(pm.UpdatedAt),
|
||||
},
|
||||
Archivable: &archivablev1.Archivable{
|
||||
IsArchived: pm.Archived,
|
||||
},
|
||||
OrganizationBound: &oboundv1.OrganizationBound{
|
||||
OrganizationRef: toObjectHex(pm.GetOrganizationRef()),
|
||||
},
|
||||
PermissionRef: toObjectHex(pm.GetPermissionRef()),
|
||||
}
|
||||
}
|
||||
|
||||
func applyPermissionBound(pm *model.PaymentMethod, src *pboundv1.PermissionBound) error {
|
||||
if pm == nil || src == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if storable := src.GetStorable(); storable != nil {
|
||||
if methodRef, err := parseOptionalObjectID(storable.GetId(), "payment_method_record.permission_bound.storable.id"); err != nil {
|
||||
return err
|
||||
} else if methodRef != bson.NilObjectID {
|
||||
pm.ID = methodRef
|
||||
}
|
||||
pm.CreatedAt = fromProtoTime(storable.GetCreatedAt())
|
||||
pm.UpdatedAt = fromProtoTime(storable.GetUpdatedAt())
|
||||
}
|
||||
|
||||
if archivable := src.GetArchivable(); archivable != nil {
|
||||
pm.Archived = archivable.GetIsArchived()
|
||||
}
|
||||
|
||||
if orgBound := src.GetOrganizationBound(); orgBound != nil {
|
||||
if orgRef, err := parseOptionalObjectID(orgBound.GetOrganizationRef(), "payment_method_record.permission_bound.organization_bound.organization_ref"); err != nil {
|
||||
return err
|
||||
} else if orgRef != bson.NilObjectID {
|
||||
pm.SetOrganizationRef(orgRef)
|
||||
}
|
||||
}
|
||||
|
||||
if permissionRef, err := parseOptionalObjectID(src.GetPermissionRef(), "payment_method_record.permission_bound.permission_ref"); err != nil {
|
||||
return err
|
||||
} else if permissionRef != bson.NilObjectID {
|
||||
pm.SetPermissionRef(permissionRef)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseOptionalObjectID(value, field string) (bson.ObjectID, error) {
|
||||
trimmed := strings.TrimSpace(value)
|
||||
if trimmed == "" {
|
||||
return bson.NilObjectID, nil
|
||||
}
|
||||
ref, err := bson.ObjectIDFromHex(trimmed)
|
||||
if err != nil {
|
||||
return bson.NilObjectID, merrors.InvalidArgument(fmt.Sprintf("%s must be a valid object id", field), field)
|
||||
}
|
||||
return ref, nil
|
||||
}
|
||||
|
||||
func parseRequiredObjectID(value, field string) (bson.ObjectID, error) {
|
||||
ref, err := parseOptionalObjectID(value, field)
|
||||
if err != nil {
|
||||
return bson.NilObjectID, err
|
||||
}
|
||||
if ref == bson.NilObjectID {
|
||||
return bson.NilObjectID, merrors.InvalidArgument(field+" is required", field)
|
||||
}
|
||||
return ref, nil
|
||||
}
|
||||
|
||||
func toObjectHex(value bson.ObjectID) string {
|
||||
if value == bson.NilObjectID {
|
||||
return ""
|
||||
}
|
||||
return value.Hex()
|
||||
}
|
||||
|
||||
func toProtoTime(value time.Time) *timestamppb.Timestamp {
|
||||
if value.IsZero() {
|
||||
return nil
|
||||
}
|
||||
return timestamppb.New(value)
|
||||
}
|
||||
|
||||
func fromProtoTime(value *timestamppb.Timestamp) time.Time {
|
||||
if value == nil {
|
||||
return time.Time{}
|
||||
}
|
||||
return value.AsTime()
|
||||
}
|
||||
|
||||
func grpcErrorResponse(logger mlogger.Logger, source mservice.Type, err error) http.HandlerFunc {
|
||||
statusErr, ok := status.FromError(err)
|
||||
if !ok {
|
||||
return response.Internal(logger, source, err)
|
||||
}
|
||||
|
||||
switch statusErr.Code() {
|
||||
case codes.InvalidArgument:
|
||||
return response.BadRequest(logger, source, "invalid_argument", statusErr.Message())
|
||||
case codes.NotFound:
|
||||
return response.NotFound(logger, source, statusErr.Message())
|
||||
case codes.PermissionDenied:
|
||||
return response.AccessDenied(logger, source, statusErr.Message())
|
||||
case codes.Unauthenticated:
|
||||
return response.Unauthorized(logger, source, statusErr.Message())
|
||||
case codes.AlreadyExists, codes.Aborted:
|
||||
return response.DataConflict(logger, source, statusErr.Message())
|
||||
case codes.Unimplemented:
|
||||
return response.NotImplemented(logger, source, statusErr.Message())
|
||||
case codes.FailedPrecondition:
|
||||
return response.Error(logger, source, http.StatusPreconditionFailed, "failed_precondition", statusErr.Message())
|
||||
case codes.DeadlineExceeded:
|
||||
return response.Error(logger, source, http.StatusGatewayTimeout, "deadline_exceeded", statusErr.Message())
|
||||
case codes.Unavailable:
|
||||
return response.Error(logger, source, http.StatusServiceUnavailable, "service_unavailable", statusErr.Message())
|
||||
default:
|
||||
return response.Internal(logger, source, err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user