rwadurian/backend/mpc-system/services/account/application/use_cases/create_account.go

334 lines
9.0 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)
}
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
}