52 lines
1.6 KiB
TypeScript
52 lines
1.6 KiB
TypeScript
import { Injectable, CanActivate, ExecutionContext, ForbiddenException } from '@nestjs/common';
|
|
import { PrismaService } from './prisma.service.js';
|
|
|
|
@Injectable()
|
|
export class TourRoleGuard implements CanActivate {
|
|
constructor(private prisma: PrismaService) {}
|
|
|
|
async canActivate(context: ExecutionContext): Promise<boolean> {
|
|
const request = context.switchToHttp().getRequest();
|
|
const user = request.user;
|
|
|
|
const tourId = request.params.id || request.params.tourId;
|
|
const path = request.url;
|
|
|
|
if (!user || !tourId) {
|
|
throw new ForbiddenException("Thông tin xác thực hoặc mã Tour không hợp lệ.");
|
|
}
|
|
|
|
if (path.includes('/join-requests') && request.method === 'POST' && (!request.params.requestId || /\/join-requests\/[^/]+\/(accept|reject)$/.test(path))) {
|
|
request.tourParticipation = null;
|
|
return true;
|
|
}
|
|
|
|
const participation = await this.prisma.tourParticipant.findUnique({
|
|
where: {
|
|
tourId_userId: {
|
|
tourId: tourId,
|
|
userId: user.id,
|
|
},
|
|
},
|
|
});
|
|
|
|
if (!participation) {
|
|
throw new ForbiddenException("Bạn không phải là thành viên của tour này.");
|
|
}
|
|
|
|
request.tourParticipation = participation;
|
|
|
|
const role = participation.role;
|
|
const isPlanPath = path.includes('/plans');
|
|
const isExpensePath = path.includes('/expenses');
|
|
|
|
if (
|
|
(role === 'MEMBER_NO_FINANCE' || role === 'VIEWER_ONLY') &&
|
|
(isPlanPath || isExpensePath)
|
|
) {
|
|
throw new ForbiddenException("Bạn không có quyền xem kế hoạch và chi phí của tour này.");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
} |