rwadurian/backend/services/identity-service/src/application/commands/recover-by-mnemonic/recover-by-mnemonic.handler.ts

85 lines
3.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Injectable, Inject, Logger } from '@nestjs/common';
import { RecoverByMnemonicCommand } from './recover-by-mnemonic.command';
import { UserAccountRepository, USER_ACCOUNT_REPOSITORY } from '@/domain/repositories/user-account.repository.interface';
import { AccountSequence } from '@/domain/value-objects';
import { TokenService } from '@/application/services/token.service';
import { EventPublisherService } from '@/infrastructure/kafka/event-publisher.service';
import { BlockchainClientService } from '@/infrastructure/external/blockchain/blockchain-client.service';
import { ApplicationError } from '@/shared/exceptions/domain.exception';
import { RecoverAccountResult } from '../index';
import { generateRandomAvatarSvg } from '@/shared/utils/random-identity.util';
@Injectable()
export class RecoverByMnemonicHandler {
private readonly logger = new Logger(RecoverByMnemonicHandler.name);
constructor(
@Inject(USER_ACCOUNT_REPOSITORY)
private readonly userRepository: UserAccountRepository,
private readonly tokenService: TokenService,
private readonly eventPublisher: EventPublisherService,
private readonly blockchainClient: BlockchainClientService,
) {}
async execute(command: RecoverByMnemonicCommand): Promise<RecoverAccountResult> {
const accountSequence = AccountSequence.create(command.accountSequence);
const account = await this.userRepository.findByAccountSequence(accountSequence);
if (!account) throw new ApplicationError('账户序列号不存在');
if (!account.isActive) throw new ApplicationError('账户已冻结或注销');
// 调用 blockchain-service 验证助记词blockchain-service 内部查询哈希并验证)
this.logger.log(`Verifying mnemonic for account ${command.accountSequence}`);
const verifyResult = await this.blockchainClient.verifyMnemonicByAccount({
accountSequence: command.accountSequence,
mnemonic: command.mnemonic,
});
if (!verifyResult.valid) {
this.logger.warn(`Mnemonic verification failed for account ${command.accountSequence}: ${verifyResult.message}`);
throw new ApplicationError(verifyResult.message || '助记词错误');
}
this.logger.log(`Mnemonic verified successfully for account ${command.accountSequence}`);
// 如果头像为空,重新生成一个
let avatarUrl = account.avatarUrl;
this.logger.log(`Account ${command.accountSequence} avatarUrl from DB: ${avatarUrl ? `长度=${avatarUrl.length}` : 'null'}`);
if (avatarUrl) {
this.logger.log(`Account ${command.accountSequence} avatarUrl前50字符: ${avatarUrl.substring(0, 50)}`);
}
if (!avatarUrl) {
this.logger.log(`Account ${command.accountSequence} has no avatar, generating new one`);
avatarUrl = generateRandomAvatarSvg();
account.updateProfile({ avatarUrl });
}
account.addDevice(command.newDeviceId, command.deviceName);
account.recordLogin();
await this.userRepository.save(account);
const tokens = await this.tokenService.generateTokenPair({
userId: account.userId.toString(),
accountSequence: account.accountSequence.value,
deviceId: command.newDeviceId,
});
await this.eventPublisher.publishAll(account.domainEvents);
account.clearDomainEvents();
const result = {
userId: account.userId.toString(),
accountSequence: account.accountSequence.value,
nickname: account.nickname,
avatarUrl,
referralCode: account.referralCode.value,
accessToken: tokens.accessToken,
refreshToken: tokens.refreshToken,
};
this.logger.log(`RecoverByMnemonic result - accountSequence: ${result.accountSequence}, nickname: ${result.nickname}`);
this.logger.log(`RecoverByMnemonic result - avatarUrl: ${result.avatarUrl ? `长度=${result.avatarUrl.length}` : 'null'}`);
return result;
}
}