343 lines
9.2 KiB
Go
343 lines
9.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"
|
|
"github.com/rwadurian/mpc-system/services/account/domain/value_objects"
|
|
)
|
|
|
|
// CreateAccountUseCase handles account creation
|
|
type CreateAccountUseCase struct {
|
|
accountRepo repositories.AccountRepository
|
|
shareRepo repositories.AccountShareRepository
|
|
domainService *services.AccountDomainService
|
|
eventPublisher ports.EventPublisher
|
|
}
|
|
|
|
// NewCreateAccountUseCase creates a new CreateAccountUseCase
|
|
func NewCreateAccountUseCase(
|
|
accountRepo repositories.AccountRepository,
|
|
shareRepo repositories.AccountShareRepository,
|
|
domainService *services.AccountDomainService,
|
|
eventPublisher ports.EventPublisher,
|
|
) *CreateAccountUseCase {
|
|
return &CreateAccountUseCase{
|
|
accountRepo: accountRepo,
|
|
shareRepo: shareRepo,
|
|
domainService: domainService,
|
|
eventPublisher: eventPublisher,
|
|
}
|
|
}
|
|
|
|
// Execute creates a new account
|
|
func (uc *CreateAccountUseCase) Execute(ctx context.Context, input ports.CreateAccountInput) (*ports.CreateAccountOutput, error) {
|
|
// Convert shares input
|
|
shares := make([]services.ShareInfo, len(input.Shares))
|
|
for i, s := range input.Shares {
|
|
shares[i] = services.ShareInfo{
|
|
ShareType: s.ShareType,
|
|
PartyID: s.PartyID,
|
|
PartyIndex: s.PartyIndex,
|
|
DeviceType: s.DeviceType,
|
|
DeviceID: s.DeviceID,
|
|
}
|
|
}
|
|
|
|
// Create account using domain service
|
|
account, err := uc.domainService.CreateAccount(ctx, services.CreateAccountInput{
|
|
Username: input.Username,
|
|
Email: input.Email,
|
|
Phone: input.Phone,
|
|
PublicKey: input.PublicKey,
|
|
KeygenSessionID: input.KeygenSessionID,
|
|
ThresholdN: input.ThresholdN,
|
|
ThresholdT: input.ThresholdT,
|
|
Shares: shares,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Get created shares
|
|
accountShares, err := uc.shareRepo.GetByAccountID(ctx, account.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Publish event
|
|
if uc.eventPublisher != nil {
|
|
_ = uc.eventPublisher.Publish(ctx, ports.AccountEvent{
|
|
Type: ports.EventTypeAccountCreated,
|
|
AccountID: account.ID.String(),
|
|
Data: map[string]interface{}{
|
|
"username": account.Username,
|
|
"email": account.Email,
|
|
"thresholdN": account.ThresholdN,
|
|
"thresholdT": account.ThresholdT,
|
|
},
|
|
})
|
|
}
|
|
|
|
return &ports.CreateAccountOutput{
|
|
Account: account,
|
|
Shares: accountShares,
|
|
}, nil
|
|
}
|
|
|
|
// GetAccountUseCase handles getting account information
|
|
type GetAccountUseCase struct {
|
|
accountRepo repositories.AccountRepository
|
|
shareRepo repositories.AccountShareRepository
|
|
}
|
|
|
|
// NewGetAccountUseCase creates a new GetAccountUseCase
|
|
func NewGetAccountUseCase(
|
|
accountRepo repositories.AccountRepository,
|
|
shareRepo repositories.AccountShareRepository,
|
|
) *GetAccountUseCase {
|
|
return &GetAccountUseCase{
|
|
accountRepo: accountRepo,
|
|
shareRepo: shareRepo,
|
|
}
|
|
}
|
|
|
|
// Execute gets account information
|
|
func (uc *GetAccountUseCase) Execute(ctx context.Context, input ports.GetAccountInput) (*ports.GetAccountOutput, error) {
|
|
var account *entities.Account
|
|
var err error
|
|
|
|
switch {
|
|
case input.AccountID != nil:
|
|
account, err = uc.accountRepo.GetByID(ctx, *input.AccountID)
|
|
case input.Username != nil:
|
|
account, err = uc.accountRepo.GetByUsername(ctx, *input.Username)
|
|
case input.Email != nil:
|
|
account, err = uc.accountRepo.GetByEmail(ctx, *input.Email)
|
|
default:
|
|
return nil, entities.ErrAccountNotFound
|
|
}
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Get shares
|
|
shares, err := uc.shareRepo.GetActiveByAccountID(ctx, account.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &ports.GetAccountOutput{
|
|
Account: account,
|
|
Shares: shares,
|
|
}, nil
|
|
}
|
|
|
|
// UpdateAccountUseCase handles account updates
|
|
type UpdateAccountUseCase struct {
|
|
accountRepo repositories.AccountRepository
|
|
eventPublisher ports.EventPublisher
|
|
}
|
|
|
|
// NewUpdateAccountUseCase creates a new UpdateAccountUseCase
|
|
func NewUpdateAccountUseCase(
|
|
accountRepo repositories.AccountRepository,
|
|
eventPublisher ports.EventPublisher,
|
|
) *UpdateAccountUseCase {
|
|
return &UpdateAccountUseCase{
|
|
accountRepo: accountRepo,
|
|
eventPublisher: eventPublisher,
|
|
}
|
|
}
|
|
|
|
// Execute updates an account
|
|
func (uc *UpdateAccountUseCase) Execute(ctx context.Context, input ports.UpdateAccountInput) (*ports.UpdateAccountOutput, error) {
|
|
account, err := uc.accountRepo.GetByID(ctx, input.AccountID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if input.Phone != nil {
|
|
account.SetPhone(*input.Phone)
|
|
}
|
|
|
|
// Handle signing parties update
|
|
if input.ClearSigningParties {
|
|
account.ClearSigningParties()
|
|
} else if len(input.SigningParties) > 0 {
|
|
if err := account.SetSigningParties(input.SigningParties); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if err := uc.accountRepo.Update(ctx, account); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Publish event
|
|
if uc.eventPublisher != nil {
|
|
_ = uc.eventPublisher.Publish(ctx, ports.AccountEvent{
|
|
Type: ports.EventTypeAccountUpdated,
|
|
AccountID: account.ID.String(),
|
|
Data: map[string]interface{}{},
|
|
})
|
|
}
|
|
|
|
return &ports.UpdateAccountOutput{
|
|
Account: account,
|
|
}, nil
|
|
}
|
|
|
|
// DeactivateShareUseCase handles share deactivation
|
|
type DeactivateShareUseCase struct {
|
|
accountRepo repositories.AccountRepository
|
|
shareRepo repositories.AccountShareRepository
|
|
eventPublisher ports.EventPublisher
|
|
}
|
|
|
|
// NewDeactivateShareUseCase creates a new DeactivateShareUseCase
|
|
func NewDeactivateShareUseCase(
|
|
accountRepo repositories.AccountRepository,
|
|
shareRepo repositories.AccountShareRepository,
|
|
eventPublisher ports.EventPublisher,
|
|
) *DeactivateShareUseCase {
|
|
return &DeactivateShareUseCase{
|
|
accountRepo: accountRepo,
|
|
shareRepo: shareRepo,
|
|
eventPublisher: eventPublisher,
|
|
}
|
|
}
|
|
|
|
// Execute deactivates a share
|
|
func (uc *DeactivateShareUseCase) Execute(ctx context.Context, input ports.DeactivateShareInput) error {
|
|
// Verify account exists
|
|
_, err := uc.accountRepo.GetByID(ctx, input.AccountID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Get share
|
|
share, err := uc.shareRepo.GetByID(ctx, input.ShareID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Verify share belongs to account
|
|
if !share.AccountID.Equals(input.AccountID) {
|
|
return entities.ErrShareNotFound
|
|
}
|
|
|
|
// Deactivate share
|
|
share.Deactivate()
|
|
if err := uc.shareRepo.Update(ctx, share); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Publish event
|
|
if uc.eventPublisher != nil {
|
|
_ = uc.eventPublisher.Publish(ctx, ports.AccountEvent{
|
|
Type: ports.EventTypeShareDeactivated,
|
|
AccountID: input.AccountID.String(),
|
|
Data: map[string]interface{}{
|
|
"shareId": input.ShareID,
|
|
"shareType": share.ShareType.String(),
|
|
},
|
|
})
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ListAccountsInput represents input for listing accounts
|
|
type ListAccountsInput struct {
|
|
Offset int
|
|
Limit int
|
|
}
|
|
|
|
// ListAccountsOutput represents output from listing accounts
|
|
type ListAccountsOutput struct {
|
|
Accounts []*entities.Account
|
|
Total int64
|
|
}
|
|
|
|
// ListAccountsUseCase handles listing accounts
|
|
type ListAccountsUseCase struct {
|
|
accountRepo repositories.AccountRepository
|
|
}
|
|
|
|
// NewListAccountsUseCase creates a new ListAccountsUseCase
|
|
func NewListAccountsUseCase(accountRepo repositories.AccountRepository) *ListAccountsUseCase {
|
|
return &ListAccountsUseCase{
|
|
accountRepo: accountRepo,
|
|
}
|
|
}
|
|
|
|
// Execute lists accounts with pagination
|
|
func (uc *ListAccountsUseCase) Execute(ctx context.Context, input ListAccountsInput) (*ListAccountsOutput, error) {
|
|
if input.Limit <= 0 {
|
|
input.Limit = 20
|
|
}
|
|
if input.Limit > 100 {
|
|
input.Limit = 100
|
|
}
|
|
|
|
accounts, err := uc.accountRepo.List(ctx, input.Offset, input.Limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
total, err := uc.accountRepo.Count(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &ListAccountsOutput{
|
|
Accounts: accounts,
|
|
Total: total,
|
|
}, nil
|
|
}
|
|
|
|
// GetAccountSharesUseCase handles getting account shares
|
|
type GetAccountSharesUseCase struct {
|
|
accountRepo repositories.AccountRepository
|
|
shareRepo repositories.AccountShareRepository
|
|
}
|
|
|
|
// NewGetAccountSharesUseCase creates a new GetAccountSharesUseCase
|
|
func NewGetAccountSharesUseCase(
|
|
accountRepo repositories.AccountRepository,
|
|
shareRepo repositories.AccountShareRepository,
|
|
) *GetAccountSharesUseCase {
|
|
return &GetAccountSharesUseCase{
|
|
accountRepo: accountRepo,
|
|
shareRepo: shareRepo,
|
|
}
|
|
}
|
|
|
|
// GetAccountSharesOutput represents output from getting account shares
|
|
type GetAccountSharesOutput struct {
|
|
Shares []*entities.AccountShare
|
|
}
|
|
|
|
// Execute gets shares for an account
|
|
func (uc *GetAccountSharesUseCase) Execute(ctx context.Context, accountID value_objects.AccountID) (*GetAccountSharesOutput, error) {
|
|
// Verify account exists
|
|
_, err := uc.accountRepo.GetByID(ctx, accountID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
shares, err := uc.shareRepo.GetByAccountID(ctx, accountID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &GetAccountSharesOutput{
|
|
Shares: shares,
|
|
}, nil
|
|
}
|