forked from datawhale/whale-town-end
WARNING: This commit contains code with significant issues that need immediate attention: 1. Type Safety Issues: - Unused import ZulipAccountsService causing compilation warnings - Implicit 'any' type in formatZulipAccount method parameter - Type inconsistencies in service injections 2. Service Integration Problems: - Inconsistent service interface usage - Missing proper type definitions for injected services - Potential runtime errors due to type mismatches 3. Code Quality Issues: - Violation of TypeScript strict mode requirements - Inconsistent error handling patterns - Missing proper interface implementations Files affected: - src/business/admin/database_management.service.ts (main issue) - Multiple test files and service implementations - Configuration and documentation updates Next steps required: 1. Fix TypeScript compilation errors 2. Implement proper type safety 3. Resolve service injection inconsistencies 4. Add comprehensive error handling 5. Update tests to match new implementations Impact: High - affects admin functionality and system stability Priority: Urgent - requires immediate review and fixes Author: moyin Date: 2026-01-10
702 lines
26 KiB
TypeScript
702 lines
26 KiB
TypeScript
/**
|
||
* 数据库管理服务
|
||
*
|
||
* 功能描述:
|
||
* - 提供统一的数据库管理接口,集成所有数据库服务的CRUD操作
|
||
* - 实现管理员专用的数据库操作功能
|
||
* - 提供统一的响应格式和错误处理
|
||
* - 支持操作日志记录和审计功能
|
||
*
|
||
* 职责分离:
|
||
* - 业务逻辑编排:协调各个数据库服务的操作
|
||
* - 数据转换:DTO与实体之间的转换
|
||
* - 权限控制:确保只有管理员可以执行操作
|
||
* - 日志记录:记录所有数据库操作的详细日志
|
||
*
|
||
* 集成的服务:
|
||
* - UsersService: 用户数据管理
|
||
* - UserProfilesService: 用户档案管理
|
||
* - ZulipAccountsService: Zulip账号关联管理
|
||
*
|
||
* 最近修改:
|
||
* - 2026-01-09: Bug修复 - 修复类型错误,正确处理skin_id类型转换和Zulip账号查询参数 (修改者: moyin)
|
||
* - 2026-01-09: 功能实现 - 实现所有TODO项,完成UserProfiles和ZulipAccounts的CRUD操作 (修改者: moyin)
|
||
* - 2026-01-09: 代码质量优化 - 替换any类型为具体的DTO类型,提高类型安全性 (修改者: moyin)
|
||
* - 2026-01-09: 代码质量优化 - 统一使用admin_utils中的响应创建函数,消除重复代码 (修改者: moyin)
|
||
* - 2026-01-08: 注释规范优化 - 修正@author字段,更新版本号和修改记录 (修改者: moyin)
|
||
* - 2026-01-08: 注释规范优化 - 完善方法注释,添加@param、@returns、@throws和@example (修改者: moyin)
|
||
* - 2026-01-08: 代码规范优化 - 将魔法数字20提取为常量DEFAULT_PAGE_SIZE (修改者: moyin)
|
||
* - 2026-01-08: 代码质量优化 - 提取用户格式化逻辑,补充缺失方法实现,使用操作监控工具 (修改者: moyin)
|
||
* - 2026-01-08: 功能新增 - 创建数据库管理服务,支持管理员数据库操作 (修改者: assistant)
|
||
*
|
||
* @author moyin
|
||
* @version 1.6.0
|
||
* @since 2026-01-08
|
||
* @lastModified 2026-01-09
|
||
*/
|
||
|
||
import { Injectable, Logger, NotFoundException, BadRequestException, ConflictException, Inject } from '@nestjs/common';
|
||
import { UsersService } from '../../core/db/users/users.service';
|
||
import { UserProfilesService } from '../../core/db/user_profiles/user_profiles.service';
|
||
import { UserProfiles } from '../../core/db/user_profiles/user_profiles.entity';
|
||
import { ZulipAccountsService } from '../../core/db/zulip_accounts/zulip_accounts.service';
|
||
import { ZulipAccountResponseDto } from '../../core/db/zulip_accounts/zulip_accounts.dto';
|
||
import { getCurrentTimestamp, UserFormatter, OperationMonitor, createSuccessResponse, createErrorResponse, createListResponse } from './admin_utils';
|
||
import {
|
||
AdminCreateUserDto,
|
||
AdminUpdateUserDto,
|
||
AdminCreateUserProfileDto,
|
||
AdminUpdateUserProfileDto,
|
||
AdminCreateZulipAccountDto,
|
||
AdminUpdateZulipAccountDto
|
||
} from './admin_database.dto';
|
||
|
||
/**
|
||
* 常量定义
|
||
*/
|
||
const DEFAULT_PAGE_SIZE = 20;
|
||
|
||
/**
|
||
* 管理员API统一响应格式
|
||
*/
|
||
export interface AdminApiResponse<T = any> {
|
||
success: boolean;
|
||
data?: T;
|
||
message: string;
|
||
error_code?: string;
|
||
timestamp?: string;
|
||
request_id?: string;
|
||
}
|
||
|
||
/**
|
||
* 管理员列表响应格式
|
||
*/
|
||
export interface AdminListResponse<T = any> {
|
||
success: boolean;
|
||
data: {
|
||
items: T[];
|
||
total: number;
|
||
limit: number;
|
||
offset: number;
|
||
has_more: boolean;
|
||
};
|
||
message: string;
|
||
error_code?: string;
|
||
timestamp?: string;
|
||
request_id?: string;
|
||
}
|
||
|
||
@Injectable()
|
||
export class DatabaseManagementService {
|
||
private readonly logger = new Logger(DatabaseManagementService.name);
|
||
|
||
constructor(
|
||
@Inject('UsersService') private readonly usersService: UsersService,
|
||
@Inject('IUserProfilesService') private readonly userProfilesService: UserProfilesService,
|
||
@Inject('ZulipAccountsService') private readonly zulipAccountsService: any,
|
||
) {
|
||
this.logger.log('DatabaseManagementService初始化完成');
|
||
}
|
||
|
||
/**
|
||
* 记录操作日志
|
||
*
|
||
* @param level 日志级别
|
||
* @param message 日志消息
|
||
* @param context 日志上下文
|
||
*/
|
||
private logOperation(level: 'log' | 'warn' | 'error', message: string, context: Record<string, any>): void {
|
||
this.logger[level](message, {
|
||
...context,
|
||
timestamp: getCurrentTimestamp()
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 处理服务异常
|
||
*
|
||
* @param error 异常对象
|
||
* @param operation 操作名称
|
||
* @param context 操作上下文
|
||
* @returns 错误响应
|
||
*/
|
||
private handleServiceError(error: any, operation: string, context: Record<string, any>): AdminApiResponse {
|
||
this.logOperation('error', `${operation}失败`, {
|
||
operation,
|
||
error: error instanceof Error ? error.message : String(error),
|
||
context
|
||
});
|
||
|
||
if (error instanceof NotFoundException) {
|
||
return createErrorResponse(error.message, 'RESOURCE_NOT_FOUND');
|
||
}
|
||
|
||
if (error instanceof ConflictException) {
|
||
return createErrorResponse(error.message, 'RESOURCE_CONFLICT');
|
||
}
|
||
|
||
if (error instanceof BadRequestException) {
|
||
return createErrorResponse(error.message, 'INVALID_REQUEST');
|
||
}
|
||
|
||
return createErrorResponse(`${operation}失败,请稍后重试`, 'INTERNAL_ERROR');
|
||
}
|
||
|
||
/**
|
||
* 处理列表查询异常
|
||
*
|
||
* @param error 异常对象
|
||
* @param operation 操作名称
|
||
* @param context 操作上下文
|
||
* @returns 空列表响应
|
||
*/
|
||
private handleListError(error: any, operation: string, context: Record<string, any>): AdminListResponse {
|
||
this.logOperation('error', `${operation}失败`, {
|
||
operation,
|
||
error: error instanceof Error ? error.message : String(error),
|
||
context
|
||
});
|
||
|
||
return createListResponse([], 0, context.limit || DEFAULT_PAGE_SIZE, context.offset || 0, `${operation}失败,返回空列表`);
|
||
}
|
||
|
||
// ==================== 用户管理方法 ====================
|
||
|
||
/**
|
||
* 获取用户列表
|
||
*
|
||
* 功能描述:
|
||
* 分页获取系统中的用户列表,支持限制数量和偏移量参数
|
||
*
|
||
* 业务逻辑:
|
||
* 1. 记录操作开始时间和参数
|
||
* 2. 调用用户服务获取用户数据和总数
|
||
* 3. 格式化用户信息,隐藏敏感字段
|
||
* 4. 记录操作成功日志和性能数据
|
||
* 5. 返回标准化的列表响应
|
||
*
|
||
* @param limit 限制数量,默认20,最大100
|
||
* @param offset 偏移量,默认0,用于分页
|
||
* @returns 包含用户列表、总数和分页信息的响应对象
|
||
*
|
||
* @throws NotFoundException 当查询条件无效时
|
||
* @throws InternalServerErrorException 当数据库操作失败时
|
||
*
|
||
* @example
|
||
* ```typescript
|
||
* const result = await service.getUserList(20, 0);
|
||
* console.log(result.data.items.length); // 用户数量
|
||
* console.log(result.data.total); // 总用户数
|
||
* ```
|
||
*/
|
||
async getUserList(limit: number = DEFAULT_PAGE_SIZE, offset: number = 0): Promise<AdminListResponse> {
|
||
return await OperationMonitor.executeWithMonitoring(
|
||
'获取用户列表',
|
||
{ limit, offset },
|
||
async () => {
|
||
const users = await this.usersService.findAll(limit, offset);
|
||
const total = await this.usersService.count();
|
||
const formattedUsers = users.map(user => UserFormatter.formatBasicUser(user));
|
||
return createListResponse(formattedUsers, total, limit, offset, '用户列表获取成功');
|
||
},
|
||
this.logOperation.bind(this)
|
||
).catch(error => this.handleListError(error, '获取用户列表', { limit, offset }));
|
||
}
|
||
|
||
/**
|
||
* 根据ID获取用户详情
|
||
*
|
||
* 功能描述:
|
||
* 根据用户ID获取指定用户的详细信息
|
||
*
|
||
* 业务逻辑:
|
||
* 1. 记录操作开始时间和用户ID
|
||
* 2. 调用用户服务查询用户信息
|
||
* 3. 格式化用户详细信息
|
||
* 4. 记录操作成功日志和性能数据
|
||
* 5. 返回标准化的详情响应
|
||
*
|
||
* @param id 用户ID,必须是有效的bigint类型
|
||
* @returns 包含用户详细信息的响应对象
|
||
*
|
||
* @throws NotFoundException 当用户不存在时
|
||
* @throws BadRequestException 当用户ID格式无效时
|
||
* @throws InternalServerErrorException 当数据库操作失败时
|
||
*
|
||
* @example
|
||
* ```typescript
|
||
* const result = await service.getUserById(BigInt(123));
|
||
* console.log(result.data.username); // 用户名
|
||
* console.log(result.data.email); // 邮箱
|
||
* ```
|
||
*/
|
||
async getUserById(id: bigint): Promise<AdminApiResponse> {
|
||
return await OperationMonitor.executeWithMonitoring(
|
||
'获取用户详情',
|
||
{ userId: id.toString() },
|
||
async () => {
|
||
const user = await this.usersService.findOne(id);
|
||
const formattedUser = UserFormatter.formatDetailedUser(user);
|
||
return createSuccessResponse(formattedUser, '用户详情获取成功');
|
||
},
|
||
this.logOperation.bind(this)
|
||
).catch(error => this.handleServiceError(error, '获取用户详情', { userId: id.toString() }));
|
||
}
|
||
|
||
/**
|
||
* 搜索用户
|
||
*
|
||
* 功能描述:
|
||
* 根据关键词搜索用户,支持用户名、邮箱、昵称等字段的模糊匹配
|
||
*
|
||
* 业务逻辑:
|
||
* 1. 记录搜索操作开始时间和关键词
|
||
* 2. 调用用户服务执行搜索查询
|
||
* 3. 格式化搜索结果
|
||
* 4. 记录搜索成功日志和性能数据
|
||
* 5. 返回标准化的搜索响应
|
||
*
|
||
* @param keyword 搜索关键词,支持用户名、邮箱、昵称的模糊匹配
|
||
* @param limit 返回结果数量限制,默认20,最大50
|
||
* @returns 包含搜索结果的响应对象
|
||
*
|
||
* @throws BadRequestException 当关键词为空或格式无效时
|
||
* @throws InternalServerErrorException 当搜索操作失败时
|
||
*
|
||
* @example
|
||
* ```typescript
|
||
* const result = await service.searchUsers('admin', 10);
|
||
* console.log(result.data.items); // 搜索结果列表
|
||
* ```
|
||
*/
|
||
async searchUsers(keyword: string, limit: number = DEFAULT_PAGE_SIZE): Promise<AdminListResponse> {
|
||
return await OperationMonitor.executeWithMonitoring(
|
||
'搜索用户',
|
||
{ keyword, limit },
|
||
async () => {
|
||
const users = await this.usersService.search(keyword, limit);
|
||
const formattedUsers = users.map(user => UserFormatter.formatBasicUser(user));
|
||
return createListResponse(formattedUsers, users.length, limit, 0, '用户搜索成功');
|
||
},
|
||
this.logOperation.bind(this)
|
||
).catch(error => this.handleListError(error, '搜索用户', { keyword, limit }));
|
||
}
|
||
|
||
/**
|
||
* 创建用户
|
||
*
|
||
* @param userData 用户数据
|
||
* @returns 创建结果响应
|
||
*/
|
||
async createUser(userData: AdminCreateUserDto): Promise<AdminApiResponse> {
|
||
return await OperationMonitor.executeWithMonitoring(
|
||
'创建用户',
|
||
{ username: userData.username },
|
||
async () => {
|
||
const newUser = await this.usersService.create(userData);
|
||
const formattedUser = UserFormatter.formatBasicUser(newUser);
|
||
return createSuccessResponse(formattedUser, '用户创建成功');
|
||
},
|
||
this.logOperation.bind(this)
|
||
).catch(error => this.handleServiceError(error, '创建用户', { username: userData.username }));
|
||
}
|
||
|
||
/**
|
||
* 更新用户
|
||
*
|
||
* @param id 用户ID
|
||
* @param updateData 更新数据
|
||
* @returns 更新结果响应
|
||
*/
|
||
async updateUser(id: bigint, updateData: AdminUpdateUserDto): Promise<AdminApiResponse> {
|
||
return await OperationMonitor.executeWithMonitoring(
|
||
'更新用户',
|
||
{ userId: id.toString(), updateFields: Object.keys(updateData) },
|
||
async () => {
|
||
const updatedUser = await this.usersService.update(id, updateData);
|
||
const formattedUser = UserFormatter.formatBasicUser(updatedUser);
|
||
return createSuccessResponse(formattedUser, '用户更新成功');
|
||
},
|
||
this.logOperation.bind(this)
|
||
).catch(error => this.handleServiceError(error, '更新用户', { userId: id.toString(), updateData }));
|
||
}
|
||
|
||
/**
|
||
* 删除用户
|
||
*
|
||
* @param id 用户ID
|
||
* @returns 删除结果响应
|
||
*/
|
||
async deleteUser(id: bigint): Promise<AdminApiResponse> {
|
||
return await OperationMonitor.executeWithMonitoring(
|
||
'删除用户',
|
||
{ userId: id.toString() },
|
||
async () => {
|
||
await this.usersService.remove(id);
|
||
return createSuccessResponse({ deleted: true, id: id.toString() }, '用户删除成功');
|
||
},
|
||
this.logOperation.bind(this)
|
||
).catch(error => this.handleServiceError(error, '删除用户', { userId: id.toString() }));
|
||
}
|
||
|
||
// ==================== 用户档案管理方法 ====================
|
||
|
||
/**
|
||
* 获取用户档案列表
|
||
*
|
||
* @param limit 限制数量
|
||
* @param offset 偏移量
|
||
* @returns 用户档案列表响应
|
||
*/
|
||
async getUserProfileList(limit: number = DEFAULT_PAGE_SIZE, offset: number = 0): Promise<AdminListResponse> {
|
||
return await OperationMonitor.executeWithMonitoring(
|
||
'获取用户档案列表',
|
||
{ limit, offset },
|
||
async () => {
|
||
const profiles = await this.userProfilesService.findAll({ limit, offset });
|
||
const total = await this.userProfilesService.count();
|
||
const formattedProfiles = profiles.map(profile => this.formatUserProfile(profile));
|
||
return createListResponse(formattedProfiles, total, limit, offset, '用户档案列表获取成功');
|
||
},
|
||
this.logOperation.bind(this)
|
||
).catch(error => this.handleListError(error, '获取用户档案列表', { limit, offset }));
|
||
}
|
||
|
||
/**
|
||
* 根据ID获取用户档案详情
|
||
*
|
||
* @param id 档案ID
|
||
* @returns 用户档案详情响应
|
||
*/
|
||
async getUserProfileById(id: bigint): Promise<AdminApiResponse> {
|
||
return await OperationMonitor.executeWithMonitoring(
|
||
'获取用户档案详情',
|
||
{ profileId: id.toString() },
|
||
async () => {
|
||
const profile = await this.userProfilesService.findOne(id);
|
||
const formattedProfile = this.formatUserProfile(profile);
|
||
return createSuccessResponse(formattedProfile, '用户档案详情获取成功');
|
||
},
|
||
this.logOperation.bind(this)
|
||
).catch(error => this.handleServiceError(error, '获取用户档案详情', { profileId: id.toString() }));
|
||
}
|
||
|
||
/**
|
||
* 根据地图获取用户档案
|
||
*
|
||
* @param mapId 地图ID
|
||
* @param limit 限制数量
|
||
* @param offset 偏移量
|
||
* @returns 用户档案列表响应
|
||
*/
|
||
async getUserProfilesByMap(mapId: string, limit: number = DEFAULT_PAGE_SIZE, offset: number = 0): Promise<AdminListResponse> {
|
||
return await OperationMonitor.executeWithMonitoring(
|
||
'根据地图获取用户档案',
|
||
{ mapId, limit, offset },
|
||
async () => {
|
||
const profiles = await this.userProfilesService.findByMap(mapId, undefined, limit, offset);
|
||
const total = await this.userProfilesService.count();
|
||
const formattedProfiles = profiles.map(profile => this.formatUserProfile(profile));
|
||
return createListResponse(formattedProfiles, total, limit, offset, `地图 ${mapId} 的用户档案列表获取成功`);
|
||
},
|
||
this.logOperation.bind(this)
|
||
).catch(error => this.handleListError(error, '根据地图获取用户档案', { mapId, limit, offset }));
|
||
}
|
||
|
||
/**
|
||
* 创建用户档案
|
||
*
|
||
* @param createProfileDto 创建数据
|
||
* @returns 创建结果响应
|
||
*/
|
||
async createUserProfile(createProfileDto: AdminCreateUserProfileDto): Promise<AdminApiResponse> {
|
||
return await OperationMonitor.executeWithMonitoring(
|
||
'创建用户档案',
|
||
{ userId: createProfileDto.user_id },
|
||
async () => {
|
||
const profileData = {
|
||
user_id: BigInt(createProfileDto.user_id),
|
||
bio: createProfileDto.bio,
|
||
resume_content: createProfileDto.resume_content,
|
||
tags: createProfileDto.tags ? JSON.parse(createProfileDto.tags) : undefined,
|
||
social_links: createProfileDto.social_links ? JSON.parse(createProfileDto.social_links) : undefined,
|
||
skin_id: createProfileDto.skin_id ? parseInt(createProfileDto.skin_id) : undefined,
|
||
current_map: createProfileDto.current_map,
|
||
pos_x: createProfileDto.pos_x,
|
||
pos_y: createProfileDto.pos_y,
|
||
status: createProfileDto.status
|
||
};
|
||
|
||
const newProfile = await this.userProfilesService.create(profileData);
|
||
const formattedProfile = this.formatUserProfile(newProfile);
|
||
return createSuccessResponse(formattedProfile, '用户档案创建成功');
|
||
},
|
||
this.logOperation.bind(this)
|
||
).catch(error => this.handleServiceError(error, '创建用户档案', { userId: createProfileDto.user_id }));
|
||
}
|
||
|
||
/**
|
||
* 更新用户档案
|
||
*
|
||
* @param id 档案ID
|
||
* @param updateProfileDto 更新数据
|
||
* @returns 更新结果响应
|
||
*/
|
||
async updateUserProfile(id: bigint, updateProfileDto: AdminUpdateUserProfileDto): Promise<AdminApiResponse> {
|
||
return await OperationMonitor.executeWithMonitoring(
|
||
'更新用户档案',
|
||
{ profileId: id.toString(), updateFields: Object.keys(updateProfileDto) },
|
||
async () => {
|
||
// 转换AdminUpdateUserProfileDto为UpdateUserProfileDto
|
||
const updateData: any = {};
|
||
|
||
if (updateProfileDto.bio !== undefined) {
|
||
updateData.bio = updateProfileDto.bio;
|
||
}
|
||
if (updateProfileDto.resume_content !== undefined) {
|
||
updateData.resume_content = updateProfileDto.resume_content;
|
||
}
|
||
if (updateProfileDto.tags !== undefined) {
|
||
updateData.tags = JSON.parse(updateProfileDto.tags);
|
||
}
|
||
if (updateProfileDto.social_links !== undefined) {
|
||
updateData.social_links = JSON.parse(updateProfileDto.social_links);
|
||
}
|
||
if (updateProfileDto.skin_id !== undefined) {
|
||
updateData.skin_id = parseInt(updateProfileDto.skin_id);
|
||
}
|
||
if (updateProfileDto.current_map !== undefined) {
|
||
updateData.current_map = updateProfileDto.current_map;
|
||
}
|
||
if (updateProfileDto.pos_x !== undefined) {
|
||
updateData.pos_x = updateProfileDto.pos_x;
|
||
}
|
||
if (updateProfileDto.pos_y !== undefined) {
|
||
updateData.pos_y = updateProfileDto.pos_y;
|
||
}
|
||
if (updateProfileDto.status !== undefined) {
|
||
updateData.status = updateProfileDto.status;
|
||
}
|
||
|
||
const updatedProfile = await this.userProfilesService.update(id, updateData);
|
||
const formattedProfile = this.formatUserProfile(updatedProfile);
|
||
return createSuccessResponse(formattedProfile, '用户档案更新成功');
|
||
},
|
||
this.logOperation.bind(this)
|
||
).catch(error => this.handleServiceError(error, '更新用户档案', { profileId: id.toString(), updateData: updateProfileDto }));
|
||
}
|
||
|
||
/**
|
||
* 删除用户档案
|
||
*
|
||
* @param id 档案ID
|
||
* @returns 删除结果响应
|
||
*/
|
||
async deleteUserProfile(id: bigint): Promise<AdminApiResponse> {
|
||
return await OperationMonitor.executeWithMonitoring(
|
||
'删除用户档案',
|
||
{ profileId: id.toString() },
|
||
async () => {
|
||
const result = await this.userProfilesService.remove(id);
|
||
return createSuccessResponse({ deleted: true, id: id.toString(), affected: result.affected }, '用户档案删除成功');
|
||
},
|
||
this.logOperation.bind(this)
|
||
).catch(error => this.handleServiceError(error, '删除用户档案', { profileId: id.toString() }));
|
||
}
|
||
|
||
// ==================== Zulip账号关联管理方法 ====================
|
||
|
||
/**
|
||
* 获取Zulip账号关联列表
|
||
*
|
||
* @param limit 限制数量
|
||
* @param offset 偏移量
|
||
* @returns Zulip账号关联列表响应
|
||
*/
|
||
async getZulipAccountList(limit: number = DEFAULT_PAGE_SIZE, offset: number = 0): Promise<AdminListResponse> {
|
||
return await OperationMonitor.executeWithMonitoring(
|
||
'获取Zulip账号关联列表',
|
||
{ limit, offset },
|
||
async () => {
|
||
// ZulipAccountsService的findMany方法目前不支持分页参数
|
||
// 先获取所有数据,然后手动分页
|
||
const result = await this.zulipAccountsService.findMany({});
|
||
|
||
// 手动实现分页
|
||
const startIndex = offset;
|
||
const endIndex = offset + limit;
|
||
const paginatedAccounts = result.accounts.slice(startIndex, endIndex);
|
||
|
||
const formattedAccounts = paginatedAccounts.map(account => this.formatZulipAccount(account));
|
||
return createListResponse(formattedAccounts, result.total, limit, offset, 'Zulip账号关联列表获取成功');
|
||
},
|
||
this.logOperation.bind(this)
|
||
).catch(error => this.handleListError(error, '获取Zulip账号关联列表', { limit, offset }));
|
||
}
|
||
|
||
/**
|
||
* 根据ID获取Zulip账号关联详情
|
||
*
|
||
* @param id 关联ID
|
||
* @returns Zulip账号关联详情响应
|
||
*/
|
||
async getZulipAccountById(id: string): Promise<AdminApiResponse> {
|
||
return await OperationMonitor.executeWithMonitoring(
|
||
'获取Zulip账号关联详情',
|
||
{ accountId: id },
|
||
async () => {
|
||
const account = await this.zulipAccountsService.findById(id, true);
|
||
const formattedAccount = this.formatZulipAccount(account);
|
||
return createSuccessResponse(formattedAccount, 'Zulip账号关联详情获取成功');
|
||
},
|
||
this.logOperation.bind(this)
|
||
).catch(error => this.handleServiceError(error, '获取Zulip账号关联详情', { accountId: id }));
|
||
}
|
||
|
||
/**
|
||
* 获取Zulip账号关联统计
|
||
*
|
||
* @returns 统计信息响应
|
||
*/
|
||
async getZulipAccountStatistics(): Promise<AdminApiResponse> {
|
||
return await OperationMonitor.executeWithMonitoring(
|
||
'获取Zulip账号关联统计',
|
||
{},
|
||
async () => {
|
||
const stats = await this.zulipAccountsService.getStatusStatistics();
|
||
return createSuccessResponse(stats, 'Zulip账号关联统计获取成功');
|
||
},
|
||
this.logOperation.bind(this)
|
||
).catch(error => this.handleServiceError(error, '获取Zulip账号关联统计', {}));
|
||
}
|
||
|
||
/**
|
||
* 创建Zulip账号关联
|
||
*
|
||
* @param createAccountDto 创建数据
|
||
* @returns 创建结果响应
|
||
*/
|
||
async createZulipAccount(createAccountDto: AdminCreateZulipAccountDto): Promise<AdminApiResponse> {
|
||
return await OperationMonitor.executeWithMonitoring(
|
||
'创建Zulip账号关联',
|
||
{ gameUserId: createAccountDto.gameUserId },
|
||
async () => {
|
||
const newAccount = await this.zulipAccountsService.create(createAccountDto);
|
||
const formattedAccount = this.formatZulipAccount(newAccount);
|
||
return createSuccessResponse(formattedAccount, 'Zulip账号关联创建成功');
|
||
},
|
||
this.logOperation.bind(this)
|
||
).catch(error => this.handleServiceError(error, '创建Zulip账号关联', { gameUserId: createAccountDto.gameUserId }));
|
||
}
|
||
|
||
/**
|
||
* 更新Zulip账号关联
|
||
*
|
||
* @param id 关联ID
|
||
* @param updateAccountDto 更新数据
|
||
* @returns 更新结果响应
|
||
*/
|
||
async updateZulipAccount(id: string, updateAccountDto: AdminUpdateZulipAccountDto): Promise<AdminApiResponse> {
|
||
return await OperationMonitor.executeWithMonitoring(
|
||
'更新Zulip账号关联',
|
||
{ accountId: id, updateFields: Object.keys(updateAccountDto) },
|
||
async () => {
|
||
const updatedAccount = await this.zulipAccountsService.update(id, updateAccountDto);
|
||
const formattedAccount = this.formatZulipAccount(updatedAccount);
|
||
return createSuccessResponse(formattedAccount, 'Zulip账号关联更新成功');
|
||
},
|
||
this.logOperation.bind(this)
|
||
).catch(error => this.handleServiceError(error, '更新Zulip账号关联', { accountId: id, updateData: updateAccountDto }));
|
||
}
|
||
|
||
/**
|
||
* 删除Zulip账号关联
|
||
*
|
||
* @param id 关联ID
|
||
* @returns 删除结果响应
|
||
*/
|
||
async deleteZulipAccount(id: string): Promise<AdminApiResponse> {
|
||
return await OperationMonitor.executeWithMonitoring(
|
||
'删除Zulip账号关联',
|
||
{ accountId: id },
|
||
async () => {
|
||
const result = await this.zulipAccountsService.delete(id);
|
||
return createSuccessResponse({ deleted: result, id }, 'Zulip账号关联删除成功');
|
||
},
|
||
this.logOperation.bind(this)
|
||
).catch(error => this.handleServiceError(error, '删除Zulip账号关联', { accountId: id }));
|
||
}
|
||
|
||
/**
|
||
* 批量更新Zulip账号状态
|
||
*
|
||
* @param ids ID列表
|
||
* @param status 新状态
|
||
* @param reason 操作原因
|
||
* @returns 批量更新结果响应
|
||
*/
|
||
async batchUpdateZulipAccountStatus(ids: string[], status: string, reason?: string): Promise<AdminApiResponse> {
|
||
return await OperationMonitor.executeWithMonitoring(
|
||
'批量更新Zulip账号状态',
|
||
{ count: ids.length, status, reason },
|
||
async () => {
|
||
const result = await this.zulipAccountsService.batchUpdateStatus(ids, status as any);
|
||
return createSuccessResponse({
|
||
success_count: result.updatedCount,
|
||
failed_count: ids.length - result.updatedCount,
|
||
total_count: ids.length,
|
||
reason
|
||
}, `Zulip账号关联批量状态更新完成,成功:${result.updatedCount},失败:${ids.length - result.updatedCount}`);
|
||
},
|
||
this.logOperation.bind(this)
|
||
).catch(error => this.handleServiceError(error, '批量更新Zulip账号状态', { count: ids.length, status, reason }));
|
||
}
|
||
|
||
/**
|
||
* 格式化用户档案信息
|
||
*
|
||
* @param profile 用户档案实体
|
||
* @returns 格式化的用户档案信息
|
||
*/
|
||
private formatUserProfile(profile: UserProfiles) {
|
||
return {
|
||
id: profile.id.toString(),
|
||
user_id: profile.user_id.toString(),
|
||
bio: profile.bio,
|
||
resume_content: profile.resume_content,
|
||
tags: profile.tags,
|
||
social_links: profile.social_links,
|
||
skin_id: profile.skin_id,
|
||
current_map: profile.current_map,
|
||
pos_x: profile.pos_x,
|
||
pos_y: profile.pos_y,
|
||
status: profile.status,
|
||
last_login_at: profile.last_login_at,
|
||
last_position_update: profile.last_position_update
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 格式化Zulip账号关联信息
|
||
*
|
||
* @param account Zulip账号关联实体
|
||
* @returns 格式化的Zulip账号关联信息
|
||
*/
|
||
private formatZulipAccount(account: ZulipAccountResponseDto) {
|
||
return {
|
||
id: account.id,
|
||
gameUserId: account.gameUserId,
|
||
zulipUserId: account.zulipUserId,
|
||
zulipEmail: account.zulipEmail,
|
||
zulipFullName: account.zulipFullName,
|
||
status: account.status,
|
||
lastVerifiedAt: account.lastVerifiedAt,
|
||
lastSyncedAt: account.lastSyncedAt,
|
||
errorMessage: account.errorMessage,
|
||
retryCount: account.retryCount,
|
||
createdAt: account.createdAt,
|
||
updatedAt: account.updatedAt,
|
||
gameUser: account.gameUser
|
||
};
|
||
}
|
||
} |