package accountapiimp import ( "context" "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/mservice" "github.com/tech/sendico/pkg/mutil/mzap" "github.com/tech/sendico/server/interface/api/sresponse" "go.mongodb.org/mongo-driver/v2/bson" "go.uber.org/zap" ) func (a *AccountAPI) deleteProfile(r *http.Request, account *model.Account, token *sresponse.TokenData) http.HandlerFunc { ctx := r.Context() // Get the current organization from the request context orgRef, err := a.getCurrentOrganizationRef(r) if err != nil { a.logger.Warn("Failed to get current organization", zap.Error(err), mzap.StorableRef(account)) return response.BadRequest(a.logger, a.Name(), "invalid_organization_context", "Invalid organization context") } // Get the organization var org model.Organization if err := a.odb.Get(ctx, *account.GetID(), orgRef, &org); err != nil { a.logger.Error("Failed to fetch organization", zap.Error(err), mzap.StorableRef(account)) return response.Auto(a.logger, a.Name(), err) } // Delete the account (this will check if it's the only member) if err := a.accService.DeleteAccount(ctx, &org, account.ID); err != nil { if errors.Is(err, merrors.ErrInvalidArg) { a.logger.Warn("Cannot delete account - validation failed", zap.Error(err), mzap.StorableRef(account)) return response.BadRequest(a.logger, a.Name(), "validation_failed", err.Error()) } a.logger.Error("Failed to delete account", zap.Error(err), mzap.StorableRef(account)) return response.Auto(a.logger, a.Name(), err) } a.logger.Info("Account deleted successfully", mzap.StorableRef(account)) return response.Success(a.logger) } func (a *AccountAPI) deleteOrganization(r *http.Request, account *model.Account, token *sresponse.TokenData) http.HandlerFunc { ctx := r.Context() // Get the current organization from the request context orgRef, err := a.getCurrentOrganizationRef(r) if err != nil { a.logger.Warn("Failed to get current organization", zap.Error(err), mzap.StorableRef(account)) return response.BadRequest(a.logger, a.Name(), "invalid_organization_context", "Invalid organization context") } // Get the organization var org model.Organization if err := a.odb.Get(ctx, *account.GetID(), orgRef, &org); err != nil { a.logger.Error("Failed to fetch organization", zap.Error(err), mzap.StorableRef(account)) return response.Auto(a.logger, a.Name(), err) } // Delete the organization and all its data if err := a.accService.DeleteOrganization(ctx, &org); err != nil { a.logger.Error("Failed to delete organization", zap.Error(err), mzap.StorableRef(&org)) return response.Auto(a.logger, a.Name(), err) } a.logger.Info("Organization deleted successfully", mzap.StorableRef(&org)) return response.Success(a.logger) } func (a *AccountAPI) deleteAll(r *http.Request, account *model.Account, token *sresponse.TokenData) http.HandlerFunc { ctx := r.Context() // Get the current organization from the request context orgRef, err := a.getCurrentOrganizationRef(r) if err != nil { a.logger.Warn("Failed to get current organization", zap.Error(err), mzap.StorableRef(account)) return response.BadRequest(a.logger, a.Name(), "invalid_organization_context", "Invalid organization context") } // Get the organization var org model.Organization if err := a.odb.Get(ctx, *account.GetID(), orgRef, &org); err != nil { a.logger.Error("Failed to fetch organization", zap.Error(err), mzap.StorableRef(account)) return response.Auto(a.logger, a.Name(), err) } // Get organization permission reference var orgPolicy model.PolicyDescription if err := a.plcdb.GetBuiltInPolicy(ctx, mservice.Organizations, &orgPolicy); err != nil { a.logger.Error("Failed to fetch organization policy", zap.Error(err), mzap.StorableRef(account)) return response.Auto(a.logger, a.Name(), err) } // Check if user has permission to delete the organization canDelete, err := a.enf.Enforce(ctx, orgPolicy.ID, account.ID, orgRef, bson.NilObjectID, model.ActionDelete) if err != nil { a.logger.Error("Failed to check delete permission", zap.Error(err), mzap.StorableRef(account)) return response.Auto(a.logger, a.Name(), err) } if !canDelete { a.logger.Warn("User does not have permission to delete organization", mzap.StorableRef(account), mzap.StorableRef(&org)) return response.AccessDenied(a.logger, a.Name(), "Insufficient permissions to delete organization") } // Delete everything (organization + account) if _, err := a.tf.CreateTransaction().Execute(ctx, func(c context.Context) (any, error) { if err := a.accService.DeleteAll(c, &org, account.ID); err != nil { a.logger.Warn("Failed to delete all data", zap.Error(err), mzap.StorableRef(&org), mzap.StorableRef(account)) return nil, err } return nil, nil }); err != nil { a.logger.Warn("Failed to execute delete transaction", zap.Error(err), mzap.StorableRef(&org), mzap.StorableRef(account)) return response.Auto(a.logger, a.Name(), err) } a.logger.Info("All data deleted successfully", mzap.StorableRef(&org), mzap.StorableRef(account)) return response.Success(a.logger) } // Helper method to get current organization reference from request context func (a *AccountAPI) getCurrentOrganizationRef(r *http.Request) (bson.ObjectID, error) { return a.oph.GetRef(r) }