2026-05-24 11:18:56 +08:00
|
|
|
import { Injectable, BadRequestException, NotFoundException } from '@nestjs/common';
|
2026-05-09 18:25:04 +08:00
|
|
|
import { UsersRepository } from './users.repository';
|
2026-05-24 11:18:56 +08:00
|
|
|
import { PrismaService } from '../../infrastructure/database/prisma.service';
|
|
|
|
|
|
|
|
|
|
const DELETION_COOLING_DAYS = 7;
|
2026-05-09 18:25:04 +08:00
|
|
|
|
|
|
|
|
@Injectable()
|
|
|
|
|
export class UsersService {
|
2026-05-24 11:18:56 +08:00
|
|
|
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); }
|
2026-05-09 18:25:04 +08:00
|
|
|
|
2026-05-24 11:18:56 +08:00
|
|
|
// ── Membership ──
|
|
|
|
|
|
|
|
|
|
async getMembership(userId: string) {
|
|
|
|
|
return this.prisma.userMembership.findFirst({
|
|
|
|
|
where: { userId, active: true },
|
|
|
|
|
include: { plan: true },
|
|
|
|
|
orderBy: { createdAt: 'desc' },
|
|
|
|
|
});
|
2026-05-09 18:25:04 +08:00
|
|
|
}
|
|
|
|
|
|
2026-05-24 11:18:56 +08:00
|
|
|
// ── 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 },
|
|
|
|
|
});
|
2026-05-09 18:25:04 +08:00
|
|
|
}
|
|
|
|
|
|
2026-05-24 11:18:56 +08:00
|
|
|
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() },
|
|
|
|
|
});
|
2026-05-17 19:08:07 +08:00
|
|
|
}
|
|
|
|
|
|
2026-05-24 11:18:56 +08:00
|
|
|
// ── Device Management ──
|
|
|
|
|
|
|
|
|
|
async getDevices(userId: string) {
|
|
|
|
|
return this.prisma.userDevice.findMany({
|
|
|
|
|
where: { userId },
|
|
|
|
|
orderBy: { lastSeenAt: 'desc' },
|
|
|
|
|
});
|
2026-05-17 19:08:07 +08:00
|
|
|
}
|
|
|
|
|
|
2026-05-24 11:18:56 +08:00
|
|
|
async removeDevice(userId: string, deviceId: string) {
|
|
|
|
|
await this.prisma.userDevice.deleteMany({
|
|
|
|
|
where: { userId, deviceId },
|
|
|
|
|
});
|
|
|
|
|
return { success: true };
|
2026-05-09 18:25:04 +08:00
|
|
|
}
|
|
|
|
|
}
|