245 lines
7.2 KiB
Go
245 lines
7.2 KiB
Go
package use_cases
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/rwadurian/mpc-system/services/account/application/ports"
|
|
"github.com/rwadurian/mpc-system/services/account/domain/entities"
|
|
"github.com/rwadurian/mpc-system/services/account/domain/repositories"
|
|
"github.com/rwadurian/mpc-system/services/account/domain/services"
|
|
)
|
|
|
|
// InitiateRecoveryUseCase handles initiating account recovery
|
|
type InitiateRecoveryUseCase struct {
|
|
accountRepo repositories.AccountRepository
|
|
recoveryRepo repositories.RecoverySessionRepository
|
|
domainService *services.AccountDomainService
|
|
eventPublisher ports.EventPublisher
|
|
}
|
|
|
|
// NewInitiateRecoveryUseCase creates a new InitiateRecoveryUseCase
|
|
func NewInitiateRecoveryUseCase(
|
|
accountRepo repositories.AccountRepository,
|
|
recoveryRepo repositories.RecoverySessionRepository,
|
|
domainService *services.AccountDomainService,
|
|
eventPublisher ports.EventPublisher,
|
|
) *InitiateRecoveryUseCase {
|
|
return &InitiateRecoveryUseCase{
|
|
accountRepo: accountRepo,
|
|
recoveryRepo: recoveryRepo,
|
|
domainService: domainService,
|
|
eventPublisher: eventPublisher,
|
|
}
|
|
}
|
|
|
|
// Execute initiates account recovery
|
|
func (uc *InitiateRecoveryUseCase) Execute(ctx context.Context, input ports.InitiateRecoveryInput) (*ports.InitiateRecoveryOutput, error) {
|
|
// Check if there's already an active recovery session
|
|
existingRecovery, err := uc.recoveryRepo.GetActiveByAccountID(ctx, input.AccountID)
|
|
if err == nil && existingRecovery != nil {
|
|
return nil, &entities.AccountError{
|
|
Code: "RECOVERY_ALREADY_IN_PROGRESS",
|
|
Message: "there is already an active recovery session for this account",
|
|
}
|
|
}
|
|
|
|
// Initiate recovery using domain service
|
|
recoverySession, err := uc.domainService.InitiateRecovery(ctx, input.AccountID, input.RecoveryType, input.OldShareType)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Publish event
|
|
if uc.eventPublisher != nil {
|
|
_ = uc.eventPublisher.Publish(ctx, ports.AccountEvent{
|
|
Type: ports.EventTypeRecoveryStarted,
|
|
AccountID: input.AccountID.String(),
|
|
Data: map[string]interface{}{
|
|
"recoverySessionId": recoverySession.ID.String(),
|
|
"recoveryType": input.RecoveryType.String(),
|
|
},
|
|
})
|
|
}
|
|
|
|
return &ports.InitiateRecoveryOutput{
|
|
RecoverySession: recoverySession,
|
|
}, nil
|
|
}
|
|
|
|
// CompleteRecoveryUseCase handles completing account recovery
|
|
type CompleteRecoveryUseCase struct {
|
|
accountRepo repositories.AccountRepository
|
|
shareRepo repositories.AccountShareRepository
|
|
recoveryRepo repositories.RecoverySessionRepository
|
|
domainService *services.AccountDomainService
|
|
eventPublisher ports.EventPublisher
|
|
}
|
|
|
|
// NewCompleteRecoveryUseCase creates a new CompleteRecoveryUseCase
|
|
func NewCompleteRecoveryUseCase(
|
|
accountRepo repositories.AccountRepository,
|
|
shareRepo repositories.AccountShareRepository,
|
|
recoveryRepo repositories.RecoverySessionRepository,
|
|
domainService *services.AccountDomainService,
|
|
eventPublisher ports.EventPublisher,
|
|
) *CompleteRecoveryUseCase {
|
|
return &CompleteRecoveryUseCase{
|
|
accountRepo: accountRepo,
|
|
shareRepo: shareRepo,
|
|
recoveryRepo: recoveryRepo,
|
|
domainService: domainService,
|
|
eventPublisher: eventPublisher,
|
|
}
|
|
}
|
|
|
|
// Execute completes account recovery
|
|
func (uc *CompleteRecoveryUseCase) Execute(ctx context.Context, input ports.CompleteRecoveryInput) (*ports.CompleteRecoveryOutput, error) {
|
|
// Convert shares input
|
|
newShares := make([]services.ShareInfo, len(input.NewShares))
|
|
for i, s := range input.NewShares {
|
|
newShares[i] = services.ShareInfo{
|
|
ShareType: s.ShareType,
|
|
PartyID: s.PartyID,
|
|
PartyIndex: s.PartyIndex,
|
|
DeviceType: s.DeviceType,
|
|
DeviceID: s.DeviceID,
|
|
}
|
|
}
|
|
|
|
// Complete recovery using domain service
|
|
err := uc.domainService.CompleteRecovery(
|
|
ctx,
|
|
input.RecoverySessionID,
|
|
input.NewPublicKey,
|
|
input.NewKeygenSessionID,
|
|
newShares,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Get recovery session to get account ID
|
|
recovery, err := uc.recoveryRepo.GetByID(ctx, input.RecoverySessionID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Get updated account
|
|
account, err := uc.accountRepo.GetByID(ctx, recovery.AccountID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Publish event
|
|
if uc.eventPublisher != nil {
|
|
_ = uc.eventPublisher.Publish(ctx, ports.AccountEvent{
|
|
Type: ports.EventTypeRecoveryComplete,
|
|
AccountID: account.ID.String(),
|
|
Data: map[string]interface{}{
|
|
"recoverySessionId": input.RecoverySessionID,
|
|
"newKeygenSessionId": input.NewKeygenSessionID.String(),
|
|
},
|
|
})
|
|
}
|
|
|
|
return &ports.CompleteRecoveryOutput{
|
|
Account: account,
|
|
}, nil
|
|
}
|
|
|
|
// GetRecoveryStatusInput represents input for getting recovery status
|
|
type GetRecoveryStatusInput struct {
|
|
RecoverySessionID string
|
|
}
|
|
|
|
// GetRecoveryStatusOutput represents output from getting recovery status
|
|
type GetRecoveryStatusOutput struct {
|
|
RecoverySession *entities.RecoverySession
|
|
}
|
|
|
|
// GetRecoveryStatusUseCase handles getting recovery session status
|
|
type GetRecoveryStatusUseCase struct {
|
|
recoveryRepo repositories.RecoverySessionRepository
|
|
}
|
|
|
|
// NewGetRecoveryStatusUseCase creates a new GetRecoveryStatusUseCase
|
|
func NewGetRecoveryStatusUseCase(recoveryRepo repositories.RecoverySessionRepository) *GetRecoveryStatusUseCase {
|
|
return &GetRecoveryStatusUseCase{
|
|
recoveryRepo: recoveryRepo,
|
|
}
|
|
}
|
|
|
|
// Execute gets recovery session status
|
|
func (uc *GetRecoveryStatusUseCase) Execute(ctx context.Context, input GetRecoveryStatusInput) (*GetRecoveryStatusOutput, error) {
|
|
recovery, err := uc.recoveryRepo.GetByID(ctx, input.RecoverySessionID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &GetRecoveryStatusOutput{
|
|
RecoverySession: recovery,
|
|
}, nil
|
|
}
|
|
|
|
// CancelRecoveryInput represents input for canceling recovery
|
|
type CancelRecoveryInput struct {
|
|
RecoverySessionID string
|
|
}
|
|
|
|
// CancelRecoveryUseCase handles canceling recovery
|
|
type CancelRecoveryUseCase struct {
|
|
accountRepo repositories.AccountRepository
|
|
recoveryRepo repositories.RecoverySessionRepository
|
|
}
|
|
|
|
// NewCancelRecoveryUseCase creates a new CancelRecoveryUseCase
|
|
func NewCancelRecoveryUseCase(
|
|
accountRepo repositories.AccountRepository,
|
|
recoveryRepo repositories.RecoverySessionRepository,
|
|
) *CancelRecoveryUseCase {
|
|
return &CancelRecoveryUseCase{
|
|
accountRepo: accountRepo,
|
|
recoveryRepo: recoveryRepo,
|
|
}
|
|
}
|
|
|
|
// Execute cancels a recovery session
|
|
func (uc *CancelRecoveryUseCase) Execute(ctx context.Context, input CancelRecoveryInput) error {
|
|
// Get recovery session
|
|
recovery, err := uc.recoveryRepo.GetByID(ctx, input.RecoverySessionID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Check if recovery can be canceled
|
|
if recovery.IsCompleted() {
|
|
return &entities.AccountError{
|
|
Code: "RECOVERY_CANNOT_CANCEL",
|
|
Message: "cannot cancel completed recovery",
|
|
}
|
|
}
|
|
|
|
// Mark recovery as failed
|
|
if err := recovery.Fail(); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Update recovery session
|
|
if err := uc.recoveryRepo.Update(ctx, recovery); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Reactivate account
|
|
account, err := uc.accountRepo.GetByID(ctx, recovery.AccountID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
account.Activate()
|
|
if err := uc.accountRepo.Update(ctx, account); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|