feat: chuẩn bị backend cho tính năng anonymous user upload ảnh không cần đăng nhập
This commit is contained in:
+3
-2
@@ -5,8 +5,8 @@ export declare class JwtStrategy extends JwtStrategy_base {
|
|||||||
constructor(prisma: PrismaService);
|
constructor(prisma: PrismaService);
|
||||||
validate(payload: any): Promise<{
|
validate(payload: any): Promise<{
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string | null;
|
||||||
passwordHash: string;
|
passwordHash: string | null;
|
||||||
name: string | null;
|
name: string | null;
|
||||||
phone: string | null;
|
phone: string | null;
|
||||||
address: string | null;
|
address: string | null;
|
||||||
@@ -14,6 +14,7 @@ export declare class JwtStrategy extends JwtStrategy_base {
|
|||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
isAdmin: boolean;
|
isAdmin: boolean;
|
||||||
isBlocked: boolean;
|
isBlocked: boolean;
|
||||||
|
isAnonymous: boolean;
|
||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
export {};
|
export {};
|
||||||
|
|||||||
Vendored
+48
@@ -279,6 +279,47 @@ let AuthController = class AuthController {
|
|||||||
this.emailService = emailService;
|
this.emailService = emailService;
|
||||||
this.cacheManager = cacheManager;
|
this.cacheManager = cacheManager;
|
||||||
}
|
}
|
||||||
|
async convertGuestToOfficial(body) {
|
||||||
|
const { guestId, email, password, name } = body;
|
||||||
|
if (!guestId || !email || !password) {
|
||||||
|
throw new common_1.BadRequestException('Vui lòng cung cấp đủ guestId, email và mật khẩu.');
|
||||||
|
}
|
||||||
|
const existingOfficialUser = await this.prisma.user.findFirst({
|
||||||
|
where: {
|
||||||
|
email: email,
|
||||||
|
isAnonymous: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (existingOfficialUser) {
|
||||||
|
throw new common_1.BadRequestException('Email này đã được một tài khoản khác sử dụng.');
|
||||||
|
}
|
||||||
|
const guestUser = await this.prisma.user.findUnique({
|
||||||
|
where: { id: guestId },
|
||||||
|
});
|
||||||
|
if (!guestUser || !guestUser.isAnonymous) {
|
||||||
|
throw new common_1.NotFoundException('Không tìm thấy tài khoản khách hoặc tài khoản này đã được chuyển đổi.');
|
||||||
|
}
|
||||||
|
const passwordHash = await bcrypt.hash(password, 10);
|
||||||
|
const updatedUser = await this.prisma.user.update({
|
||||||
|
where: { id: guestId },
|
||||||
|
data: {
|
||||||
|
email: email,
|
||||||
|
passwordHash: passwordHash,
|
||||||
|
name: name || guestUser.name,
|
||||||
|
isAnonymous: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const payload = { email: updatedUser.email, sub: updatedUser.id };
|
||||||
|
return {
|
||||||
|
access_token: this.jwtService.sign(payload),
|
||||||
|
user: {
|
||||||
|
id: updatedUser.id,
|
||||||
|
email: updatedUser.email,
|
||||||
|
name: updatedUser.name,
|
||||||
|
isAdmin: updatedUser.isAdmin,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
async getStatus() {
|
async getStatus() {
|
||||||
const userCount = await this.prisma.user.count();
|
const userCount = await this.prisma.user.count();
|
||||||
console.log(`[Status Check] Users found: ${userCount}`);
|
console.log(`[Status Check] Users found: ${userCount}`);
|
||||||
@@ -346,6 +387,13 @@ let AuthController = class AuthController {
|
|||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
__decorate([
|
||||||
|
(0, common_1.Post)('convert-guest'),
|
||||||
|
__param(0, (0, common_1.Body)()),
|
||||||
|
__metadata("design:type", Function),
|
||||||
|
__metadata("design:paramtypes", [Object]),
|
||||||
|
__metadata("design:returntype", Promise)
|
||||||
|
], AuthController.prototype, "convertGuestToOfficial", null);
|
||||||
__decorate([
|
__decorate([
|
||||||
(0, common_1.Get)('status'),
|
(0, common_1.Get)('status'),
|
||||||
__metadata("design:type", Function),
|
__metadata("design:type", Function),
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,15 @@
|
|||||||
|
-- DropForeignKey
|
||||||
|
ALTER TABLE "Photo" DROP CONSTRAINT "Photo_tourId_fkey";
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Photo" ADD COLUMN "originalUrl" TEXT,
|
||||||
|
ALTER COLUMN "tourId" DROP NOT NULL,
|
||||||
|
ALTER COLUMN "imageUrl" DROP NOT NULL;
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "User" ADD COLUMN "isAnonymous" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
ALTER COLUMN "email" DROP NOT NULL,
|
||||||
|
ALTER COLUMN "passwordHash" DROP NOT NULL;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Photo" ADD CONSTRAINT "Photo_tourId_fkey" FOREIGN KEY ("tourId") REFERENCES "Tour"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
@@ -57,8 +57,8 @@ enum PrivacyLevel {
|
|||||||
|
|
||||||
model User {
|
model User {
|
||||||
id String @id @default(uuid())
|
id String @id @default(uuid())
|
||||||
email String @unique
|
email String? @unique
|
||||||
passwordHash String
|
passwordHash String?
|
||||||
name String?
|
name String?
|
||||||
phone String?
|
phone String?
|
||||||
address String?
|
address String?
|
||||||
@@ -66,6 +66,7 @@ model User {
|
|||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
isAdmin Boolean @default(false)
|
isAdmin Boolean @default(false)
|
||||||
isBlocked Boolean @default(false)
|
isBlocked Boolean @default(false)
|
||||||
|
isAnonymous Boolean @default(false)
|
||||||
|
|
||||||
createdTours Tour[] @relation("TourCreator")
|
createdTours Tour[] @relation("TourCreator")
|
||||||
tourParticipations TourParticipant[]
|
tourParticipations TourParticipant[]
|
||||||
|
|||||||
@@ -262,6 +262,61 @@ class AuthController {
|
|||||||
@Inject(CACHE_MANAGER) private cacheManager: Cache
|
@Inject(CACHE_MANAGER) private cacheManager: Cache
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
@Post('convert-guest')
|
||||||
|
async convertGuestToOfficial(@Body() body: any) {
|
||||||
|
const { guestId, email, password, name } = body;
|
||||||
|
|
||||||
|
if (!guestId || !email || !password) {
|
||||||
|
throw new BadRequestException('Vui lòng cung cấp đủ guestId, email và mật khẩu.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Kiểm tra xem email đã tồn tại với một tài khoản chính thức khác chưa
|
||||||
|
const existingOfficialUser = await this.prisma.user.findFirst({
|
||||||
|
where: {
|
||||||
|
email: email,
|
||||||
|
isAnonymous: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (existingOfficialUser) {
|
||||||
|
throw new BadRequestException('Email này đã được một tài khoản khác sử dụng.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Tìm tài khoản khách
|
||||||
|
const guestUser = await this.prisma.user.findUnique({
|
||||||
|
where: { id: guestId },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!guestUser || !guestUser.isAnonymous) {
|
||||||
|
throw new NotFoundException('Không tìm thấy tài khoản khách hoặc tài khoản này đã được chuyển đổi.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Mã hóa mật khẩu và cập nhật người dùng
|
||||||
|
const passwordHash = await bcrypt.hash(password, 10);
|
||||||
|
|
||||||
|
const updatedUser = await this.prisma.user.update({
|
||||||
|
where: { id: guestId },
|
||||||
|
data: {
|
||||||
|
email: email,
|
||||||
|
passwordHash: passwordHash,
|
||||||
|
name: name || guestUser.name, // Cập nhật tên mới nếu có, nếu không giữ lại tên ẩn danh cũ
|
||||||
|
isAnonymous: false, // Đánh dấu đây là tài khoản chính thức
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 4. Tạo và trả về token để người dùng đăng nhập ngay lập tức
|
||||||
|
const payload = { email: updatedUser.email, sub: updatedUser.id };
|
||||||
|
return {
|
||||||
|
access_token: this.jwtService.sign(payload),
|
||||||
|
user: {
|
||||||
|
id: updatedUser.id,
|
||||||
|
email: updatedUser.email,
|
||||||
|
name: updatedUser.name,
|
||||||
|
isAdmin: updatedUser.isAdmin,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Get('status')
|
@Get('status')
|
||||||
async getStatus() {
|
async getStatus() {
|
||||||
const userCount = await this.prisma.user.count();
|
const userCount = await this.prisma.user.count();
|
||||||
|
|||||||
Reference in New Issue
Block a user