move api/server to api/edge/bff

This commit is contained in:
Stephan D
2026-02-28 00:39:20 +01:00
parent 34182af3b8
commit 98db0e4e9e
248 changed files with 406 additions and 18 deletions

View 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,
}
}

View 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)
}

View 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
}

View 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)
}

View 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)
}

View 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)
}

View 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
}

View 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
}

View 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)
}

View 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())
}

View 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
}

View 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)
}