All files / libs/tenants/companies/admin-scopes/shared/src/lib AdminScopesContainer.ts

56.12% Statements 55/98
90.9% Branches 10/11
37.5% Functions 3/8
56.12% Lines 55/98

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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 991x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 12x 12x 12x 12x 48x     12x 12x 1x 1x           1x 1x     1x 1x 12x 12x 12x 12x 12x 48x 40x 12x 12x 12x 1x 1x 12x 12x 12x 12x 12x 12x 1x 1x                                                             1x 1x     1x 1x     1x  
import { VariableType, type Quota } from '@amalia/amalia-lang/tokens/types';
import { toTimestamp, type UnixTimestampInSeconds } from '@amalia/ext/dates';
import { assert } from '@amalia/ext/typescript';
import {
  type AdminScopesContainerDehydrated,
  type AdminScopesContainerInterface,
  type AdminScopesContainerParams,
} from '@amalia/kernel/auth/types';
import { type Plan } from '@amalia/payout-definition/plans/types';
import { type UserContract } from '@amalia/tenants/users/types';
 
export class AdminScopesContainer implements AdminScopesContainerInterface {
  private readonly scope: AdminScopesContainerParams['scope'];
 
  private readonly planAssignments: AdminScopesContainerParams['planAssignments'];
 
  public constructor({ scope, planAssignments }: AdminScopesContainerParams) {
    this.scope = scope;
    this.planAssignments = planAssignments;
 
    planAssignments.forEach((pa) => {
      if (!scope.planIds.includes(pa.planId)) {
        throw new Error(`Invalid plan assignment ${pa.id}, not part of plans of scope ${scope.id}`);
      }
    });
  }
 
  public dehydrate(): AdminScopesContainerDehydrated {
    return {
      scope: this.scope,
      planAssignments: this.planAssignments,
    };
  }
 
  public static hydrate(dehydrated: AdminScopesContainerDehydrated) {
    return new AdminScopesContainer(dehydrated);
  }
 
  public allUsersInMyScope(date: Date | UnixTimestampInSeconds): UserContract[] {
    const observationDateTimestamp = toTimestamp(date);
 
    return this.planAssignments
      .filter(
        (pa) =>
          (!pa.effectiveAsOf || pa.effectiveAsOf <= observationDateTimestamp) &&
          (!pa.effectiveUntil || observationDateTimestamp <= pa.effectiveUntil),
      )
      .map((pa) => pa.user!);
  }
 
  public userIsInScope(userId: UserContract['id'], date: Date | UnixTimestampInSeconds): boolean {
    const observationDateTimestamp = toTimestamp(date);
 
    const allUsersInMyScope = this.allUsersInMyScope(observationDateTimestamp);
 
    return allUsersInMyScope.some((user) => user.id === userId);
  }
 
  public canAccessQuotaValue(quotaValue: {
    quotaType: VariableType;
    quotaId?: Quota['id'];
    userId?: string | null;
    planId?: string | null;
    date?: Date | UnixTimestampInSeconds | null;
  }): boolean {
    assert(quotaValue.quotaId, 'quotaValue.quotaId is required');
    assert(quotaValue.quotaType, 'quotaValue.quotaType is required');

    // In any case, check first that the quota is in the scope.
    if (!this.scope.quotaIds.includes(quotaValue.quotaId)) {
      return false;
    }

    if (quotaValue.quotaType === VariableType.plan) {
      assert(quotaValue.planId, 'quotaValue.planId is required');
      assert(quotaValue.quotaType, 'quotaValue.quotaType is required');

      return this.scope.planIds.includes(quotaValue.planId);
    }

    if (quotaValue.quotaType === VariableType.user) {
      assert(quotaValue.userId, 'quotaValue.userId is required');

      // If no date is provided (quota without frequency), use today.
      return this.userIsInScope(quotaValue.userId, quotaValue.date ?? new Date());
    }

    return false;
  }
 
  public listPlansInMyScope(): Plan['id'][] {
    return this.scope.planIds;
  }
 
  public listQuotasInMyScope(): Quota['id'][] {
    return this.scope.quotaIds;
  }
}