move api/server to api/edge/bff
This commit is contained in:
130
api/edge/bff/internal/server/aapitemplate/config.go
Normal file
130
api/edge/bff/internal/server/aapitemplate/config.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package aapitemplate
|
||||
|
||||
import (
|
||||
"github.com/tech/sendico/server/interface/api/sresponse"
|
||||
)
|
||||
|
||||
type HandlerResolver func(sresponse.AccountHandlerFunc) sresponse.AccountHandlerFunc
|
||||
|
||||
type Config interface {
|
||||
WithNoCreate() Config
|
||||
WithCreateHandler(handler sresponse.AccountHandlerFunc) Config
|
||||
WithNoList() Config
|
||||
WithListHandler(handler sresponse.AccountHandlerFunc) Config
|
||||
WithNoGet() Config
|
||||
WithGetHandler(handler sresponse.AccountHandlerFunc) Config
|
||||
WithNoUpdate() Config
|
||||
WithUpdateHandler(handler sresponse.AccountHandlerFunc) Config
|
||||
WithNoDelete() Config
|
||||
WithDeleteHandler(handler sresponse.AccountHandlerFunc) Config
|
||||
WithReorderHandler(reorder ReorderConfig) Config
|
||||
}
|
||||
|
||||
type AAPIConfig struct {
|
||||
CreateResolver HandlerResolver
|
||||
ListResolver HandlerResolver
|
||||
GetResolver HandlerResolver
|
||||
UpdateResolver HandlerResolver
|
||||
DeleteResolver HandlerResolver
|
||||
ArchiveResolver HandlerResolver
|
||||
Reorder *ReorderConfig
|
||||
}
|
||||
|
||||
// WithNoCreate disables the create endpoint by replacing its resolver.
|
||||
func (cfg *AAPIConfig) WithNoCreate() *AAPIConfig {
|
||||
cfg.CreateResolver = disableResolver
|
||||
return cfg
|
||||
}
|
||||
|
||||
// WithCreateHandler overrides the create endpoint by replacing its resolver.
|
||||
func (cfg *AAPIConfig) WithCreateHandler(handler sresponse.AccountHandlerFunc) *AAPIConfig {
|
||||
cfg.CreateResolver = overrideResolver(handler)
|
||||
return cfg
|
||||
}
|
||||
|
||||
// WithNoList disables the list endpoint.
|
||||
func (cfg *AAPIConfig) WithNoList() *AAPIConfig {
|
||||
cfg.ListResolver = disableResolver
|
||||
return cfg
|
||||
}
|
||||
|
||||
// WithListHandler overrides the list endpoint.
|
||||
func (cfg *AAPIConfig) WithListHandler(handler sresponse.AccountHandlerFunc) *AAPIConfig {
|
||||
cfg.ListResolver = overrideResolver(handler)
|
||||
return cfg
|
||||
}
|
||||
|
||||
// WithNoGet disables the get endpoint.
|
||||
func (cfg *AAPIConfig) WithNoGet() *AAPIConfig {
|
||||
cfg.GetResolver = disableResolver
|
||||
return cfg
|
||||
}
|
||||
|
||||
// WithGetHandler overrides the get endpoint.
|
||||
func (cfg *AAPIConfig) WithGetHandler(handler sresponse.AccountHandlerFunc) *AAPIConfig {
|
||||
cfg.GetResolver = overrideResolver(handler)
|
||||
return cfg
|
||||
}
|
||||
|
||||
// WithNoUpdate disables the update endpoint.
|
||||
func (cfg *AAPIConfig) WithNoUpdate() *AAPIConfig {
|
||||
cfg.UpdateResolver = disableResolver
|
||||
return cfg
|
||||
}
|
||||
|
||||
// WithUpdateHandler overrides the update endpoint.
|
||||
func (cfg *AAPIConfig) WithUpdateHandler(handler sresponse.AccountHandlerFunc) *AAPIConfig {
|
||||
cfg.UpdateResolver = overrideResolver(handler)
|
||||
return cfg
|
||||
}
|
||||
|
||||
// WithNoDelete disables the delete endpoint.
|
||||
func (cfg *AAPIConfig) WithNoDelete() *AAPIConfig {
|
||||
cfg.DeleteResolver = disableResolver
|
||||
return cfg
|
||||
}
|
||||
|
||||
// WithDeleteHandler overrides the delete endpoint.
|
||||
func (cfg *AAPIConfig) WithDeleteHandler(handler sresponse.AccountHandlerFunc) *AAPIConfig {
|
||||
cfg.DeleteResolver = overrideResolver(handler)
|
||||
return cfg
|
||||
}
|
||||
|
||||
func (cfg *AAPIConfig) WithNoArchive() *AAPIConfig {
|
||||
cfg.ArchiveResolver = disableResolver
|
||||
return cfg
|
||||
}
|
||||
|
||||
func (cfg *AAPIConfig) WithArchiveHandler(handler sresponse.AccountHandlerFunc) *AAPIConfig {
|
||||
cfg.ArchiveResolver = overrideResolver(handler)
|
||||
return cfg
|
||||
}
|
||||
|
||||
// defaultResolver returns the default handler unchanged.
|
||||
func defaultResolver(defaultHandler sresponse.AccountHandlerFunc) sresponse.AccountHandlerFunc {
|
||||
return defaultHandler
|
||||
}
|
||||
|
||||
// disableResolver always returns nil, disabling the endpoint.
|
||||
func disableResolver(_ sresponse.AccountHandlerFunc) sresponse.AccountHandlerFunc {
|
||||
return nil
|
||||
}
|
||||
|
||||
// overrideResolver returns a resolver that always returns the given custom handler.
|
||||
func overrideResolver(custom sresponse.AccountHandlerFunc) HandlerResolver {
|
||||
return func(_ sresponse.AccountHandlerFunc) sresponse.AccountHandlerFunc {
|
||||
return custom
|
||||
}
|
||||
}
|
||||
|
||||
func NewConfig() *AAPIConfig {
|
||||
return &AAPIConfig{
|
||||
CreateResolver: defaultResolver,
|
||||
ListResolver: defaultResolver,
|
||||
GetResolver: defaultResolver,
|
||||
UpdateResolver: defaultResolver,
|
||||
DeleteResolver: defaultResolver,
|
||||
ArchiveResolver: defaultResolver,
|
||||
Reorder: nil,
|
||||
}
|
||||
}
|
||||
31
api/edge/bff/internal/server/aapitemplate/create.go
Normal file
31
api/edge/bff/internal/server/aapitemplate/create.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package aapitemplate
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/tech/sendico/pkg/api/http/response"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
"github.com/tech/sendico/server/interface/api/sresponse"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func (a *AccountAPI[T]) create(r *http.Request, account *model.Account, accessToken *sresponse.TokenData) http.HandlerFunc {
|
||||
var object T
|
||||
if err := json.NewDecoder(r.Body).Decode(&object); err != nil {
|
||||
a.Logger.Warn("Failed to decode object when creating", zap.Error(err), mzap.StorableRef(account))
|
||||
return response.BadPayload(a.Logger, a.Name(), err)
|
||||
}
|
||||
|
||||
if err := a.DB.Create(r.Context(), *account.GetID(), &object); err != nil {
|
||||
a.Logger.Warn("Error creating object", zap.Error(err), mzap.StorableRef(account))
|
||||
return response.Auto(a.Logger, a.Name(), err)
|
||||
}
|
||||
|
||||
if err := a.nconfig.CreateNotification(&object, *account.GetID()); err != nil {
|
||||
a.Logger.Warn("Failed to send creation notification", zap.Error(err), mzap.StorableRef(account))
|
||||
}
|
||||
|
||||
return a.ObjectCreated(&object, accessToken)
|
||||
}
|
||||
21
api/edge/bff/internal/server/aapitemplate/db.go
Normal file
21
api/edge/bff/internal/server/aapitemplate/db.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package aapitemplate
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/tech/sendico/pkg/db/repository/builder"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
)
|
||||
|
||||
type DB[T any] interface {
|
||||
Create(ctx context.Context, accountRef bson.ObjectID, object *T) error
|
||||
Get(ctx context.Context, accountRef, objectRef bson.ObjectID, result *T) error
|
||||
Update(ctx context.Context, accountRef bson.ObjectID, object *T) error
|
||||
Patch(ctx context.Context, accountRef, objectRef bson.ObjectID, patch builder.Patch) error
|
||||
Delete(ctx context.Context, accountRef, objectRef bson.ObjectID) error
|
||||
List(ctx context.Context, accountRef, organizationRef bson.ObjectID) ([]T, error)
|
||||
}
|
||||
|
||||
type ReorderDB interface {
|
||||
Reorder(ctx context.Context, accountRef, objectRef bson.ObjectID, newIndex int, filter builder.Query) error
|
||||
}
|
||||
53
api/edge/bff/internal/server/aapitemplate/delete.go
Normal file
53
api/edge/bff/internal/server/aapitemplate/delete.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package aapitemplate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/tech/sendico/pkg/api/http/response"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
"github.com/tech/sendico/server/interface/api/sresponse"
|
||||
mutil "github.com/tech/sendico/server/internal/mutil/param"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func (a *AccountAPI[T]) deleteImp(ctx context.Context, account *model.Account, objectRef bson.ObjectID) error {
|
||||
if err := a.DB.Delete(ctx, *account.GetID(), objectRef); err != nil {
|
||||
a.Logger.Warn("Error deleting object", zap.Error(err), mzap.StorableRef(account), mzap.ObjRef("object_ref", objectRef))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *AccountAPI[T]) delete(r *http.Request, account *model.Account, accessToken *sresponse.TokenData) http.HandlerFunc {
|
||||
objectRef, err := a.Oph.GetRef(r)
|
||||
if err != nil {
|
||||
a.Logger.Warn("Failed to restore object reference", zap.Error(err), mutil.PLog(a.Oph, r))
|
||||
return response.BadReference(a.Logger, a.Name(), a.Oph.Name(), a.Oph.GetID(r), err)
|
||||
}
|
||||
|
||||
var objPtr *T
|
||||
if a.nconfig.NeedDeleteNotification {
|
||||
var object T
|
||||
if err := a.DB.Get(r.Context(), *account.GetID(), objectRef, &object); err != nil {
|
||||
a.Logger.Warn("Failed to fetch object for notification", zap.Error(err), mzap.StorableRef(account), mutil.PLog(a.Oph, r))
|
||||
} else {
|
||||
objPtr = &object
|
||||
}
|
||||
}
|
||||
|
||||
if err := a.deleteImp(r.Context(), account, objectRef); err != nil {
|
||||
a.Logger.Warn("Error deleting object", zap.Error(err), mzap.StorableRef(account), mutil.PLog(a.Oph, r))
|
||||
return response.Auto(a.Logger, a.Name(), err)
|
||||
}
|
||||
|
||||
if objPtr != nil {
|
||||
if err := a.nconfig.DeleteNotification(objPtr, *account.GetID()); err != nil {
|
||||
a.Logger.Warn("Failed to send deletion notification", zap.Error(err), mzap.StorableRef(account), mutil.PLog(a.Oph, r))
|
||||
}
|
||||
}
|
||||
|
||||
return a.Objects([]T{}, accessToken)
|
||||
}
|
||||
29
api/edge/bff/internal/server/aapitemplate/get.go
Normal file
29
api/edge/bff/internal/server/aapitemplate/get.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package aapitemplate
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/tech/sendico/pkg/api/http/response"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
"github.com/tech/sendico/server/interface/api/sresponse"
|
||||
mutil "github.com/tech/sendico/server/internal/mutil/param"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func (a *AccountAPI[T]) get(r *http.Request, account *model.Account, accessToken *sresponse.TokenData) http.HandlerFunc {
|
||||
ctx := r.Context()
|
||||
objectRef, err := a.Oph.GetRef(r)
|
||||
if err != nil {
|
||||
a.Logger.Warn("Failed to restore object reference", zap.Error(err), mutil.PLog(a.Oph, r))
|
||||
return response.BadReference(a.Logger, a.Name(), a.Oph.Name(), a.Oph.GetID(r), err)
|
||||
}
|
||||
|
||||
var object T
|
||||
if err := a.DB.Get(ctx, *account.GetID(), objectRef, &object); err != nil {
|
||||
a.Logger.Warn("Failed to fetch object", zap.Error(err), mzap.StorableRef(account), mutil.PLog(a.Oph, r))
|
||||
return response.Auto(a.Logger, a.Name(), err)
|
||||
}
|
||||
|
||||
return a.Object(&object, accessToken)
|
||||
}
|
||||
33
api/edge/bff/internal/server/aapitemplate/list.go
Normal file
33
api/edge/bff/internal/server/aapitemplate/list.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package aapitemplate
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/tech/sendico/pkg/api/http/response"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
"github.com/tech/sendico/server/interface/api/sresponse"
|
||||
mutil "github.com/tech/sendico/server/internal/mutil/param"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func (a *AccountAPI[T]) list(r *http.Request, account *model.Account, accessToken *sresponse.TokenData) http.HandlerFunc {
|
||||
ctx := r.Context()
|
||||
organizationRef, err := a.Orgph.GetRef(r)
|
||||
if err != nil {
|
||||
a.Logger.Warn("Failed to restore organization reference", zap.Error(err), mutil.PLog(a.Orgph, r))
|
||||
return response.BadReference(a.Logger, a.Name(), a.Orgph.Name(), a.Orgph.GetID(r), err)
|
||||
}
|
||||
objects, err := a.DB.List(ctx, *account.GetID(), organizationRef)
|
||||
if err != nil {
|
||||
if !errors.Is(err, merrors.ErrNoData) {
|
||||
a.Logger.Warn("Failed to list objects", zap.Error(err), mzap.StorableRef(account))
|
||||
return response.Auto(a.Logger, a.Name(), err)
|
||||
} else {
|
||||
a.Logger.Debug("No objects available", zap.Error(err), mzap.StorableRef(account))
|
||||
}
|
||||
}
|
||||
return a.Objects(objects, accessToken)
|
||||
}
|
||||
88
api/edge/bff/internal/server/aapitemplate/nconfig.go
Normal file
88
api/edge/bff/internal/server/aapitemplate/nconfig.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package aapitemplate
|
||||
|
||||
import (
|
||||
"github.com/tech/sendico/pkg/messaging"
|
||||
notifications "github.com/tech/sendico/pkg/messaging/envelope"
|
||||
model "github.com/tech/sendico/pkg/model/notification"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
)
|
||||
|
||||
// NotificationHandler is a function that processes an object of type T and returns an error.
|
||||
type NotificationHandler[T any] func(template T, actorAccountRef bson.ObjectID) error
|
||||
|
||||
// sinkNotification is the default no-op strategy.
|
||||
func sinkNotification[T any](_ T, _ bson.ObjectID) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NotificationConfig manages notifications for Create, Update, and Delete operations.
|
||||
type NotificationConfig[T any] struct {
|
||||
producer messaging.Producer
|
||||
// The factory now receives a NotificationAction so it knows which event is being processed.
|
||||
factory func(template T, actorAccountRef bson.ObjectID, t model.NotificationAction) notifications.Envelope
|
||||
CreateNotification NotificationHandler[T]
|
||||
UpdateNotification NotificationHandler[T]
|
||||
NeedArchiveNotification bool
|
||||
ArchiveNotification NotificationHandler[T]
|
||||
NeedDeleteNotification bool
|
||||
DeleteNotification NotificationHandler[T]
|
||||
}
|
||||
|
||||
// NewNotificationConfig creates a new NotificationConfig with default (no-op) strategies.
|
||||
func NewNotificationConfig[T any](producer messaging.Producer) *NotificationConfig[T] {
|
||||
return &NotificationConfig[T]{
|
||||
producer: producer,
|
||||
factory: nil, // no factory by default
|
||||
CreateNotification: sinkNotification[T],
|
||||
UpdateNotification: sinkNotification[T],
|
||||
ArchiveNotification: sinkNotification[T],
|
||||
NeedArchiveNotification: false,
|
||||
DeleteNotification: sinkNotification[T],
|
||||
NeedDeleteNotification: false,
|
||||
}
|
||||
}
|
||||
|
||||
// WithNotifications sets the notification factory and switches all endpoints to the sending strategy.
|
||||
func (nc *NotificationConfig[T]) WithNotifications(factory func(template T, actorAccountRef bson.ObjectID, typ model.NotificationAction) notifications.Envelope) *NotificationConfig[T] {
|
||||
nc.factory = factory
|
||||
// Build sending functions for each notification type.
|
||||
nc.CreateNotification = func(template T, actorAccountRef bson.ObjectID) error {
|
||||
return nc.producer.SendMessage(factory(template, actorAccountRef, model.NACreated))
|
||||
}
|
||||
nc.UpdateNotification = func(template T, actorAccountRef bson.ObjectID) error {
|
||||
return nc.producer.SendMessage(factory(template, actorAccountRef, model.NAUpdated))
|
||||
}
|
||||
nc.ArchiveNotification = func(template T, actorAccountRef bson.ObjectID) error {
|
||||
return nc.producer.SendMessage(factory(template, actorAccountRef, model.NAArchived))
|
||||
}
|
||||
nc.NeedArchiveNotification = true
|
||||
nc.DeleteNotification = func(template T, actorAccountRef bson.ObjectID) error {
|
||||
return nc.producer.SendMessage(factory(template, actorAccountRef, model.NADeleted))
|
||||
}
|
||||
nc.NeedDeleteNotification = true
|
||||
return nc
|
||||
}
|
||||
|
||||
// WithNoCreateNotification disables the create notification.
|
||||
func (nc *NotificationConfig[T]) WithNoCreateNotification() *NotificationConfig[T] {
|
||||
nc.CreateNotification = sinkNotification[T]
|
||||
return nc
|
||||
}
|
||||
|
||||
// WithNoUpdateNotification disables the update notification.
|
||||
func (nc *NotificationConfig[T]) WithNoUpdateNotification() *NotificationConfig[T] {
|
||||
nc.UpdateNotification = sinkNotification[T]
|
||||
return nc
|
||||
}
|
||||
|
||||
func (nc *NotificationConfig[T]) WithNoArchiveNotification() *NotificationConfig[T] {
|
||||
nc.ArchiveNotification = sinkNotification[T]
|
||||
return nc
|
||||
}
|
||||
|
||||
// WithNoDeleteNotification disables the delete notification.
|
||||
func (nc *NotificationConfig[T]) WithNoDeleteNotification() *NotificationConfig[T] {
|
||||
nc.DeleteNotification = sinkNotification[T]
|
||||
nc.NeedDeleteNotification = false
|
||||
return nc
|
||||
}
|
||||
33
api/edge/bff/internal/server/aapitemplate/rconfig.go
Normal file
33
api/edge/bff/internal/server/aapitemplate/rconfig.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package aapitemplate
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/tech/sendico/pkg/db/repository"
|
||||
"github.com/tech/sendico/pkg/db/repository/builder"
|
||||
"github.com/tech/sendico/server/interface/api/srequest"
|
||||
)
|
||||
|
||||
type ReorderRequestProcessor func(r *http.Request) (*srequest.ReorderX, builder.Query, error)
|
||||
|
||||
type ReorderConfig struct {
|
||||
DB ReorderDB
|
||||
ReqProcessor ReorderRequestProcessor
|
||||
}
|
||||
|
||||
func (cfg *AAPIConfig) WithReorderHandler(reorder ReorderConfig) *AAPIConfig {
|
||||
cfg.Reorder = &reorder
|
||||
if cfg.Reorder.ReqProcessor == nil {
|
||||
cfg.Reorder.ReqProcessor = defaultRequestProcessor
|
||||
}
|
||||
return cfg
|
||||
}
|
||||
|
||||
func defaultRequestProcessor(r *http.Request) (*srequest.ReorderX, builder.Query, error) {
|
||||
var req srequest.ReorderXDefault
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return &req.ReorderX, repository.OrgFilter(req.ParentRef), nil
|
||||
}
|
||||
33
api/edge/bff/internal/server/aapitemplate/reorder.go
Normal file
33
api/edge/bff/internal/server/aapitemplate/reorder.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package aapitemplate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/tech/sendico/pkg/api/http/response"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
"github.com/tech/sendico/server/interface/api/sresponse"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func (a *AccountAPI[T]) reorder(r *http.Request, account *model.Account, _ *sresponse.TokenData) http.HandlerFunc {
|
||||
a.Logger.Debug("Processing reorder request...")
|
||||
req, filter, err := a.config.Reorder.ReqProcessor(r)
|
||||
if err != nil {
|
||||
a.Logger.Warn("Failed to decode tasks reorder request", zap.Error(err), mzap.StorableRef(account))
|
||||
return response.BadPayload(a.Logger, a.Name(), err)
|
||||
}
|
||||
a.Logger.Debug("Moving objects", mzap.ObjRef("object_ref", req.ObjectRef), zap.Int("new_index", req.To))
|
||||
|
||||
if _, err := a.a.DBFactory().TransactionFactory().CreateTransaction().Execute(r.Context(), func(ctx context.Context) (any, error) {
|
||||
// reorder is not atomic, so wrappping into transaction
|
||||
return nil, a.config.Reorder.DB.Reorder(ctx, account.ID, req.ObjectRef, req.To, filter)
|
||||
}); err != nil {
|
||||
a.Logger.Warn("Failed to reorder tasks", zap.Error(err), mzap.ObjRef("object_ref", req.ObjectRef), zap.Int("to", req.To))
|
||||
return response.Auto(a.Logger, a.Name(), err)
|
||||
}
|
||||
|
||||
a.Logger.Debug("Reorder request processing complete")
|
||||
return response.Success(a.Logger)
|
||||
}
|
||||
19
api/edge/bff/internal/server/aapitemplate/responses.go
Normal file
19
api/edge/bff/internal/server/aapitemplate/responses.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package aapitemplate
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/tech/sendico/server/interface/api/sresponse"
|
||||
)
|
||||
|
||||
func (a *AccountAPI[T]) Objects(items []T, accessToken *sresponse.TokenData) http.HandlerFunc {
|
||||
return sresponse.ObjectsAuth(a.Logger, items, accessToken, a.Name())
|
||||
}
|
||||
|
||||
func (a *AccountAPI[T]) Object(item *T, accessToken *sresponse.TokenData) http.HandlerFunc {
|
||||
return sresponse.ObjectAuth(a.Logger, item, accessToken, a.Name())
|
||||
}
|
||||
|
||||
func (a *AccountAPI[T]) ObjectCreated(item *T, accessToken *sresponse.TokenData) http.HandlerFunc {
|
||||
return sresponse.ObjectAuthCreated(a.Logger, item, accessToken, a.Name())
|
||||
}
|
||||
181
api/edge/bff/internal/server/aapitemplate/service.go
Normal file
181
api/edge/bff/internal/server/aapitemplate/service.go
Normal file
@@ -0,0 +1,181 @@
|
||||
package aapitemplate
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
api "github.com/tech/sendico/pkg/api/http"
|
||||
notifications "github.com/tech/sendico/pkg/messaging/envelope"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
model "github.com/tech/sendico/pkg/model/notification"
|
||||
"github.com/tech/sendico/pkg/mservice"
|
||||
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"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type AccountAPI[T any] struct {
|
||||
Logger mlogger.Logger
|
||||
DB DB[T]
|
||||
Oph mutil.ParamHelper // object param handler
|
||||
Orgph mutil.ParamHelper // organization param handler
|
||||
a eapi.API
|
||||
config *AAPIConfig
|
||||
nconfig *NotificationConfig[*T]
|
||||
resource mservice.Type
|
||||
}
|
||||
|
||||
func (a *AccountAPI[_]) Name() mservice.Type {
|
||||
return a.resource
|
||||
}
|
||||
|
||||
func (_ *AccountAPI[_]) Finish(_ context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *AccountAPI[T]) Build() *AccountAPI[T] {
|
||||
createHandler := a.config.CreateResolver(a.create)
|
||||
if createHandler != nil {
|
||||
a.a.Register().AccountHandler(a.Name(), "/", api.Post, createHandler)
|
||||
}
|
||||
|
||||
listHandler := a.config.ListResolver(a.list)
|
||||
if listHandler != nil {
|
||||
a.a.Register().AccountHandler(a.Name(), a.Orgph.AddRef("/list"), api.Get, listHandler)
|
||||
}
|
||||
|
||||
getHandler := a.config.GetResolver(a.get)
|
||||
if getHandler != nil {
|
||||
a.a.Register().AccountHandler(a.Name(), a.Oph.AddRef("/"), api.Get, getHandler)
|
||||
}
|
||||
|
||||
updateHandler := a.config.UpdateResolver(a.update)
|
||||
if updateHandler != nil {
|
||||
a.a.Register().AccountHandler(a.Name(), "/", api.Put, updateHandler)
|
||||
}
|
||||
|
||||
deleteHandler := a.config.DeleteResolver(a.delete)
|
||||
if deleteHandler != nil {
|
||||
a.a.Register().AccountHandler(a.Name(), a.Oph.AddRef("/"), api.Delete, deleteHandler)
|
||||
}
|
||||
|
||||
if a.config.Reorder != nil {
|
||||
a.a.Register().AccountHandler(a.Name(), "/reorder", api.Post, a.reorder)
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *AccountAPI[T]) WithNotifications(factory func(template *T, actorAccountRef bson.ObjectID, t model.NotificationAction) notifications.Envelope) *AccountAPI[T] {
|
||||
a.nconfig.WithNotifications(factory)
|
||||
a.Logger.Info("Notificatons handler installed")
|
||||
return a
|
||||
}
|
||||
|
||||
// WithNoCreateNotification disables the create notification.
|
||||
func (a *AccountAPI[T]) WithNoCreateNotification() *AccountAPI[T] {
|
||||
a.nconfig.WithNoCreateNotification()
|
||||
a.Logger.Info("Object creation notificaton disabled")
|
||||
return a
|
||||
}
|
||||
|
||||
// WithNoUpdateNotification disables the update notification.
|
||||
func (a *AccountAPI[T]) WithNoUpdateNotification() *AccountAPI[T] {
|
||||
a.nconfig.WithNoUpdateNotification()
|
||||
a.Logger.Info("Object update notificaton disabled")
|
||||
return a
|
||||
}
|
||||
|
||||
// WithNoDeleteNotification disables the delete notification.
|
||||
func (a *AccountAPI[T]) WithNoDeleteNotification() *AccountAPI[T] {
|
||||
a.nconfig.WithNoDeleteNotification()
|
||||
a.Logger.Info("Object deletion notificaton disabled")
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *AccountAPI[T]) WithNoCreate() *AccountAPI[T] {
|
||||
a.config.WithNoCreate()
|
||||
a.Logger.Info("Create handler disabled")
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *AccountAPI[T]) WithCreateHandler(handler sresponse.AccountHandlerFunc) *AccountAPI[T] {
|
||||
a.config.WithCreateHandler(handler)
|
||||
a.Logger.Info("Create handler overridden")
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *AccountAPI[T]) WithNoList() *AccountAPI[T] {
|
||||
a.config.WithNoList()
|
||||
a.Logger.Info("List handler disabled")
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *AccountAPI[T]) WithListHandler(handler sresponse.AccountHandlerFunc) *AccountAPI[T] {
|
||||
a.config.WithListHandler(handler)
|
||||
a.Logger.Info("List handler overridden")
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *AccountAPI[T]) WithNoGet() *AccountAPI[T] {
|
||||
a.config.WithNoGet()
|
||||
a.Logger.Info("Get handler disabled")
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *AccountAPI[T]) WithGetHandler(handler sresponse.AccountHandlerFunc) *AccountAPI[T] {
|
||||
a.config.WithGetHandler(handler)
|
||||
a.Logger.Info("Get handler overridden")
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *AccountAPI[T]) WithReorderHandler(reorder ReorderConfig) *AccountAPI[T] {
|
||||
a.config.WithReorderHandler(reorder)
|
||||
a.Logger.Info("Reorder handler installed")
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *AccountAPI[T]) WithNoUpdate() *AccountAPI[T] {
|
||||
a.config.WithNoUpdate()
|
||||
a.Logger.Info("Update handler disabled")
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *AccountAPI[T]) WithUpdateHandler(handler sresponse.AccountHandlerFunc) *AccountAPI[T] {
|
||||
a.config.WithUpdateHandler(handler)
|
||||
a.Logger.Info("Update handler overridden")
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *AccountAPI[T]) WithNoDelete() *AccountAPI[T] {
|
||||
a.config.WithNoDelete()
|
||||
a.Logger.Info("Delete handler disabled")
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *AccountAPI[T]) WithDeleteHandler(handler sresponse.AccountHandlerFunc) *AccountAPI[T] {
|
||||
a.config.WithDeleteHandler(handler)
|
||||
a.Logger.Info("Delete handler overriden")
|
||||
return a
|
||||
}
|
||||
|
||||
func CreateAPI[T any](a eapi.API, dbFactory func() (DB[T], error), resource mservice.Type) (*AccountAPI[T], error) {
|
||||
p := &AccountAPI[T]{
|
||||
Logger: a.Logger().Named(resource),
|
||||
Oph: mutil.CreatePH("obj"), // to avoid collision with object_ref
|
||||
Orgph: mutil.CreatePH("org"), // to avoid collision with organizaitons_ref
|
||||
a: a,
|
||||
config: NewConfig(),
|
||||
resource: resource,
|
||||
nconfig: NewNotificationConfig[*T](a.Register().Messaging().Producer()),
|
||||
}
|
||||
|
||||
var err error
|
||||
if p.DB, err = dbFactory(); err != nil {
|
||||
p.Logger.Error("Failed to create protected database", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
31
api/edge/bff/internal/server/aapitemplate/update.go
Normal file
31
api/edge/bff/internal/server/aapitemplate/update.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package aapitemplate
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/tech/sendico/pkg/api/http/response"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
"github.com/tech/sendico/server/interface/api/sresponse"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func (a *AccountAPI[T]) update(r *http.Request, account *model.Account, accessToken *sresponse.TokenData) http.HandlerFunc {
|
||||
var object T
|
||||
if err := json.NewDecoder(r.Body).Decode(&object); err != nil {
|
||||
a.Logger.Warn("Failed to decode object when updating settings", zap.Error(err), mzap.StorableRef(account))
|
||||
return response.BadPayload(a.Logger, a.Name(), err)
|
||||
}
|
||||
|
||||
if err := a.DB.Update(r.Context(), *account.GetID(), &object); err != nil {
|
||||
a.Logger.Warn("Error updating object", zap.Error(err), mzap.StorableRef(account))
|
||||
return response.Auto(a.Logger, a.Name(), err)
|
||||
}
|
||||
|
||||
if err := a.nconfig.UpdateNotification(&object, *account.GetID()); err != nil {
|
||||
a.Logger.Warn("Failed to send creation notification", zap.Error(err))
|
||||
}
|
||||
|
||||
return a.Object(&object, accessToken)
|
||||
}
|
||||
Reference in New Issue
Block a user