import { Injectable, BadRequestException, NotFoundException } from '@nestjs/common'; import { UsersRepository } from './users.repository'; import { PrismaService } from '../../infrastructure/database/prisma.service'; const DELETION_COOLING_DAYS = 7; @Injectable() export class UsersService { constructor( private readonly usersRepository: UsersRepository, private readonly prisma: PrismaService, ) {} async getProfile(userId: string) { return this.usersRepository.findProfileByUserId(userId); } async updateProfile(userId: string, dto: any) { return this.usersRepository.updateProfile(userId, dto); } async getProfileDetail(userId: string) { return this.usersRepository.findUserProfile(userId); } async updateProfileDetail(userId: string, dto: any) { return this.usersRepository.upsertUserProfile(userId, dto); } async updatePreferences(userId: string, dto: any) { return this.usersRepository.updatePreferences(userId, dto); } // ── Membership ── async getMembership(userId: string) { return this.prisma.userMembership.findFirst({ where: { userId, active: true }, include: { plan: true }, orderBy: { createdAt: 'desc' }, }); } // ── Account Deletion ── async requestDeletion(userId: string) { const existing = await this.prisma.accountDeletionRequest.findFirst({ where: { userId, status: 'pending' }, }); if (existing) throw new BadRequestException('已有进行中的注销申请'); const coolingEndsAt = new Date(Date.now() + DELETION_COOLING_DAYS * 86400000); return this.prisma.accountDeletionRequest.create({ data: { userId, coolingEndsAt }, }); } async cancelDeletion(userId: string) { const req = await this.prisma.accountDeletionRequest.findFirst({ where: { userId, status: 'pending' }, }); if (!req) throw new NotFoundException('未找到进行中的注销申请'); return this.prisma.accountDeletionRequest.update({ where: { id: req.id }, data: { status: 'cancelled', cancelledAt: new Date() }, }); } // ── Device Management ── async getDevices(userId: string) { return this.prisma.userDevice.findMany({ where: { userId }, orderBy: { lastSeenAt: 'desc' }, }); } async removeDevice(userId: string, deviceId: string) { await this.prisma.userDevice.deleteMany({ where: { userId, deviceId }, }); return { success: true }; } // ── Storage ── async getStorage(userId: string) { const files = await this.prisma.uploadedFile.findMany({ where: { userId }, select: { sizeBytes: true, mimeType: true }, }); const usedBytes = files.reduce((sum, f) => sum + Number(f.sizeBytes), 0); const totalBytes = 1024 * 1024 * 1024; // 1GB hardcoded for now return { totalBytes, usedBytes, fileCount: files.length }; } // ── Assets Summary ── async getAssetsSummary(userId: string) { const [kbCount, itemCount, cardCount] = await Promise.all([ this.prisma.knowledgeBase.count({ where: { userId, deletedAt: null } }), this.prisma.knowledgeItem.count({ where: { userId, deletedAt: null } }), this.prisma.reviewCard.count({ where: { userId } }), ]); return { knowledgeBaseCount: kbCount, knowledgeItemCount: itemCount, reviewCardCount: cardCount }; } }