All files / libs/kernel/api/src/lib/decorators featureFlag.guard.ts

100% Statements 33/33
66.66% Branches 4/6
100% Functions 2/2
100% Lines 33/33

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 341x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x 2x 2x 2x 2x 1x 1x 1x 1x 1x 1x 1x 1x  
import { Injectable, type CanActivate, type ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
 
import { type AuthenticatedContext } from '@amalia/kernel/auth/types';
import { type CompanyFeatureFlags } from '@amalia/tenants/companies/types';
 
import { METADATA_KEY_FLAG } from './featureFlag.decorator';
 
/**
 * Guard to check if the company has the feature flag activated.
 * If the flag is not set on the handler, the guard will return true.
 * If you pass multiple flags, the guard will return true if at least one of the flags is activated.
 * @example @FeatureFlag(CompanyFeatureFlags.DASHBOARDS)
 * @example @FeatureFlag([CompanyFeatureFlags.DASHBOARDS, CompanyFeatureFlags.CUSTOM_REPORTS])
 */
@Injectable()
export class FeatureFlagGuard implements CanActivate {
  public constructor(private readonly reflector: Reflector) {}
 
  public canActivate(context: ExecutionContext): boolean {
    // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
    const flags = (this.reflector.get<string[]>(METADATA_KEY_FLAG, context.getHandler()) ??
      []) as CompanyFeatureFlags[];
 
    if (flags.length === 0) {
      return true;
    }
    const request: { user: AuthenticatedContext } = context.switchToHttp().getRequest();
    const company = request.user.user.company;
 
    return flags.some((flag) => company.featureFlags[flag]);
  }
}