service backend
This commit is contained in:
107
api/pkg/auth/archivableimp.go
Normal file
107
api/pkg/auth/archivableimp.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/tech/sendico/pkg/db/repository"
|
||||
"github.com/tech/sendico/pkg/db/template"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// ArchivableDB implements archive operations with permission checking
|
||||
type ArchivableDBImp[T model.PermissionBoundStorable] struct {
|
||||
dbImp *template.DBImp[T]
|
||||
logger mlogger.Logger
|
||||
enforcer Enforcer
|
||||
createEmpty func() T
|
||||
getArchivable func(T) model.Archivable
|
||||
}
|
||||
|
||||
// NewArchivableDB creates a new auth.ArchivableDB instance
|
||||
func newArchivableDBImp[T model.PermissionBoundStorable](
|
||||
dbImp *template.DBImp[T],
|
||||
logger mlogger.Logger,
|
||||
enforcer Enforcer,
|
||||
createEmpty func() T,
|
||||
getArchivable func(T) model.Archivable,
|
||||
) ArchivableDB[T] {
|
||||
return &ArchivableDBImp[T]{
|
||||
dbImp: dbImp,
|
||||
logger: logger.Named("archivable"),
|
||||
enforcer: enforcer,
|
||||
createEmpty: createEmpty,
|
||||
getArchivable: getArchivable,
|
||||
}
|
||||
}
|
||||
|
||||
// SetArchived sets the archived status of an entity with permission checking
|
||||
func (db *ArchivableDBImp[T]) SetArchived(ctx context.Context, accountRef, objectRef primitive.ObjectID, archived bool) error {
|
||||
// Check permissions using enforceObject helper
|
||||
if err := enforceObjectByRef(ctx, db.dbImp, db.enforcer, model.ActionUpdate, accountRef, objectRef); err != nil {
|
||||
db.logger.Warn("Failed to enforce object permission", zap.Error(err),
|
||||
mzap.ObjRef("account_ref", accountRef), mzap.ObjRef("object_ref", objectRef), zap.Bool("archived", archived))
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the object to check current archived status
|
||||
obj := db.createEmpty()
|
||||
if err := db.dbImp.Get(ctx, objectRef, obj); err != nil {
|
||||
db.logger.Warn("Failed to get object for setting archived status", zap.Error(err),
|
||||
mzap.ObjRef("account_ref", accountRef), mzap.ObjRef("object_ref", objectRef), zap.Bool("archived", archived))
|
||||
return err
|
||||
}
|
||||
|
||||
// Extract archivable from the object
|
||||
archivable := db.getArchivable(obj)
|
||||
currentArchived := archivable.IsArchived()
|
||||
if currentArchived == archived {
|
||||
db.logger.Debug("No change needed - same archived status", mzap.ObjRef("account_ref", accountRef),
|
||||
mzap.ObjRef("object_ref", objectRef), zap.Bool("archived", archived))
|
||||
return nil // No change needed
|
||||
}
|
||||
|
||||
// Set the archived status
|
||||
patch := repository.Patch().Set(repository.IsArchivedField(), archived)
|
||||
if err := db.dbImp.Patch(ctx, objectRef, patch); err != nil {
|
||||
db.logger.Warn("Failed to set archived status on object", zap.Error(err),
|
||||
mzap.ObjRef("account_ref", accountRef), mzap.ObjRef("object_ref", objectRef), zap.Bool("archived", archived))
|
||||
return err
|
||||
}
|
||||
|
||||
db.logger.Debug("Successfully set archived status on object", mzap.ObjRef("account_ref", accountRef),
|
||||
mzap.ObjRef("object_ref", objectRef), zap.Bool("archived", archived))
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsArchived checks if an entity is archived with permission checking
|
||||
func (db *ArchivableDBImp[T]) IsArchived(ctx context.Context, accountRef, objectRef primitive.ObjectID) (bool, error) {
|
||||
// // Check permissions using single Enforce
|
||||
if err := enforceObjectByRef(ctx, db.dbImp, db.enforcer, model.ActionRead, accountRef, objectRef); err != nil {
|
||||
db.logger.Debug("Permission denied for checking archived status", mzap.ObjRef("account_ref", accountRef),
|
||||
mzap.ObjRef("object_ref", objectRef), zap.String("action", string(model.ActionRead)))
|
||||
return false, merrors.AccessDenied("read", "object", objectRef)
|
||||
}
|
||||
obj := db.createEmpty()
|
||||
if err := db.dbImp.Get(ctx, objectRef, obj); err != nil {
|
||||
db.logger.Warn("Failed to get object for checking archived status", zap.Error(err),
|
||||
mzap.ObjRef("account_ref", accountRef), mzap.ObjRef("object_ref", objectRef))
|
||||
return false, err
|
||||
}
|
||||
archivable := db.getArchivable(obj)
|
||||
return archivable.IsArchived(), nil
|
||||
}
|
||||
|
||||
// Archive archives an entity with permission checking (sets archived to true)
|
||||
func (db *ArchivableDBImp[T]) Archive(ctx context.Context, accountRef, objectRef primitive.ObjectID) error {
|
||||
return db.SetArchived(ctx, accountRef, objectRef, true)
|
||||
}
|
||||
|
||||
// Unarchive unarchives an entity with permission checking (sets archived to false)
|
||||
func (db *ArchivableDBImp[T]) Unarchive(ctx context.Context, accountRef, objectRef primitive.ObjectID) error {
|
||||
return db.SetArchived(ctx, accountRef, objectRef, false)
|
||||
}
|
||||
Reference in New Issue
Block a user