30 lines
1.4 KiB
TypeScript
30 lines
1.4 KiB
TypeScript
import { CanActivate, ExecutionContext, ForbiddenException, Injectable } from '@nestjs/common';
|
|||
|
|
import { PrismaService } from '../prisma/prisma.service';
|
||
|
|
import type { Actor } from '../common/record-scope';
|
||
|
|
|
||
|
|
@Injectable()
|
||
|
|
export class TreasuryAccessGuard implements CanActivate {
|
||
|
|
constructor(private readonly prisma: PrismaService) {}
|
||
|
|
|
||
|
|
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||
|
|
const req = context.switchToHttp().getRequest<{ user?: Actor; originalUrl?: string; url?: string }>();
|
||
|
|
const actor = req.user;
|
||
|
|
if (!actor) throw new ForbiddenException('دسترسی مالی مجاز نیست.');
|
||
|
|
const url = req.originalUrl || req.url || '';
|
||
|
|
const payroll = url.includes('/treasury/payroll');
|
||
|
|
if (actor.role === 'owner' || actor.role === 'admin') return true;
|
||
|
|
const membership = await this.prisma.membership.findFirst({
|
||
|
|
where: { userId: actor.userId, organizationId: actor.organizationId, isActive: true },
|
||
|
|
select: { orgRole: { select: { permissions: true } } },
|
||
|
|
});
|
||
|
|
const permissions = Array.isArray(membership?.orgRole?.permissions)
|
||
|
|
? membership.orgRole.permissions.map(String)
|
||
|
|
: [];
|
||
|
|
const allowed = payroll
|
||
|
|
? permissions.includes('treasury_payroll')
|
||
|
|
: permissions.includes('treasury') || permissions.includes('treasury_payroll');
|
||
|
|
if (!allowed) throw new ForbiddenException('دسترسی مالی برای نقش شما مجاز نیست.');
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
}
|