fix: sửa lỗi các nút bị che dưới thanh địa chỉ của chrome, hỗ trợ iphone upload ảnh heic

This commit is contained in:
2026-06-20 07:05:25 +07:00
parent 36e8658dad
commit def0e0d0f9
19 changed files with 116 additions and 37 deletions
+31 -7
View File
@@ -1695,7 +1695,7 @@ let UserController = class UserController {
this.prisma = prisma;
}
async getAllUsers(req, q) {
const currentUserId = req.user?.sub;
const currentUserId = req.user?.id;
const users = await this.prisma.user.findMany({
where: q
? {
@@ -1718,18 +1718,32 @@ let UserController = class UserController {
orderBy: { capturedAt: 'desc' }
});
}
async updateUser(id, data) {
async updateUser(id, data, req) {
const requestingUser = req.user;
const targetUser = await this.prisma.user.findUnique({ where: { id } });
if (!targetUser) {
throw new common_1.NotFoundException('Không tìm thấy người dùng');
}
if (targetUser.isAdmin && !requestingUser.isAdmin) {
throw new common_1.ForbiddenException('Không có quyền thay đổi thông tin hoặc reset password của Quản trị viên');
}
if (!requestingUser.isAdmin && requestingUser.id !== id) {
throw new common_1.ForbiddenException('Bạn không có quyền thực hiện hành động này');
}
if (data.password) {
data.passwordHash = await bcrypt.hash(data.password, 10);
delete data.password;
}
if (!requestingUser.isAdmin && data.isAdmin !== undefined) {
delete data.isAdmin;
}
return this.prisma.user.update({
where: { id },
data,
select: { id: true, email: true, name: true, isAdmin: true, isBlocked: true }
});
}
async deleteUser(id) {
async deleteUser(id, req) {
const user = await this.prisma.user.findUnique({ where: { id } });
if (!user)
throw new common_1.NotFoundException('Không tìm thấy người dùng');
@@ -1757,10 +1771,13 @@ let UserController = class UserController {
}
return { message: 'Đã xóa người dùng' };
}
async toggleBlock(id) {
async toggleBlock(id, req) {
const user = await this.prisma.user.findUnique({ where: { id } });
if (!user)
throw new common_1.NotFoundException('Người dùng không tồn tại');
if (user.isAdmin) {
throw new common_1.BadRequestException('Không thể khóa tài khoản Quản trị viên');
}
const updated = await this.prisma.user.update({
where: { id },
data: { isBlocked: !user.isBlocked },
@@ -1771,6 +1788,7 @@ let UserController = class UserController {
};
__decorate([
(0, common_1.Get)(),
(0, common_1.UseGuards)(admin_guard_1.AdminGuard),
__param(0, (0, common_1.Req)()),
__param(1, (0, common_1.Query)('q')),
__metadata("design:type", Function),
@@ -1790,27 +1808,33 @@ __decorate([
(0, common_1.Patch)(':id'),
__param(0, (0, common_1.Param)('id', common_1.ParseUUIDPipe)),
__param(1, (0, common_1.Body)()),
__param(2, (0, common_1.Req)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, Object]),
__metadata("design:paramtypes", [String, Object, Object]),
__metadata("design:returntype", Promise)
], UserController.prototype, "updateUser", null);
__decorate([
(0, exports.Roles)(client_1.ParticipantRole.OWNER),
(0, common_1.Delete)(':id'),
(0, common_1.UseGuards)(admin_guard_1.AdminGuard),
__param(0, (0, common_1.Param)('id', common_1.ParseUUIDPipe)),
__param(1, (0, common_1.Req)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:paramtypes", [String, Object]),
__metadata("design:returntype", Promise)
], UserController.prototype, "deleteUser", null);
__decorate([
(0, exports.Roles)(client_1.ParticipantRole.OWNER, client_1.ParticipantRole.MANAGER),
(0, common_1.Post)('block/:id'),
(0, common_1.UseGuards)(admin_guard_1.AdminGuard),
__param(0, (0, common_1.Param)('id', common_1.ParseUUIDPipe)),
__param(1, (0, common_1.Req)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:paramtypes", [String, Object]),
__metadata("design:returntype", Promise)
], UserController.prototype, "toggleBlock", null);
UserController = __decorate([
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard),
(0, common_1.Controller)('users'),
(0, exports.Roles)(client_1.ParticipantRole.OWNER, client_1.ParticipantRole.MANAGER),
__metadata("design:paramtypes", [prisma_service_1.PrismaService])
+1 -1
View File
File diff suppressed because one or more lines are too long
+19
View File
@@ -0,0 +1,19 @@
import { PrismaClient } from '@prisma/client';
import { PrismaPg } from '@prisma/adapter-pg';
import { Pool } from 'pg';
import * as dotenv from 'dotenv';
import * as path from 'path';
const envPath = path.resolve(process.cwd(), '..', '.env');
dotenv.config({ path: envPath });
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const adapter = new PrismaPg(pool);
const prisma = new PrismaClient({ adapter });
async function main() {
const users = await prisma.user.findMany();
console.log('USERS:', users);
}
main().finally(() => pool.end());
+39 -4
View File
@@ -1640,14 +1640,16 @@ class PhotoController {
}
}
@UseGuards(JwtAuthGuard)
@Controller('users')
@Roles(ParticipantRole.OWNER, ParticipantRole.MANAGER) // Default roles for User management (Admin/Manager)
class UserController {
constructor(private prisma: PrismaService) {}
@Get()
@UseGuards(AdminGuard)
async getAllUsers(@Req() req: any, @Query('q') q?: string) {
const currentUserId = req.user?.sub;
const currentUserId = req.user?.id;
const users = await this.prisma.user.findMany({
where: q
? {
@@ -1677,11 +1679,36 @@ class UserController {
@Roles(ParticipantRole.OWNER, ParticipantRole.MANAGER) // Default roles for updating user (Admin/Manager)
@Patch(':id')
async updateUser(@Param('id', ParseUUIDPipe) id: string, @Body() data: any) {
async updateUser(@Param('id', ParseUUIDPipe) id: string, @Body() data: any, @Req() req: any) {
const requestingUser = req.user;
// Fetch target user from DB
const targetUser = await this.prisma.user.findUnique({ where: { id } });
if (!targetUser) {
throw new NotFoundException('Không tìm thấy người dùng');
}
// 1. If target user is an Admin, only an Admin can update them.
// (A manager/normal user cannot reset/change password of an Admin)
if (targetUser.isAdmin && !requestingUser.isAdmin) {
throw new ForbiddenException('Không có quyền thay đổi thông tin hoặc reset password của Quản trị viên');
}
// 2. A non-admin can only update their own profile.
if (!requestingUser.isAdmin && requestingUser.id !== id) {
throw new ForbiddenException('Bạn không có quyền thực hiện hành động này');
}
if (data.password) {
data.passwordHash = await bcrypt.hash(data.password, 10);
delete data.password;
}
// Safety: prevent non-admins from promoting anyone to admin
if (!requestingUser.isAdmin && data.isAdmin !== undefined) {
delete data.isAdmin;
}
return this.prisma.user.update({
where: { id },
data,
@@ -1691,7 +1718,8 @@ class UserController {
@Roles(ParticipantRole.OWNER) // Only owner can delete user
@Delete(':id')
async deleteUser(@Param('id', ParseUUIDPipe) id: string) {
@UseGuards(AdminGuard)
async deleteUser(@Param('id', ParseUUIDPipe) id: string, @Req() req: any) {
const user = await this.prisma.user.findUnique({ where: { id } });
if (!user) throw new NotFoundException('Không tìm thấy người dùng');
if (user.isAdmin) {
@@ -1729,9 +1757,16 @@ class UserController {
@Roles(ParticipantRole.OWNER, ParticipantRole.MANAGER) // Default roles for blocking user (Admin/Manager)
@Post('block/:id')
async toggleBlock(@Param('id', ParseUUIDPipe) id: string) {
@UseGuards(AdminGuard)
async toggleBlock(@Param('id', ParseUUIDPipe) id: string, @Req() req: any) {
const user = await this.prisma.user.findUnique({ where: { id } });
if (!user) throw new NotFoundException('Người dùng không tồn tại');
// Safety check: Cannot block an Admin
if (user.isAdmin) {
throw new BadRequestException('Không thể khóa tài khoản Quản trị viên');
}
const updated = await this.prisma.user.update({
where: { id },
data: { isBlocked: !user.isBlocked },
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB