All files / libs/tenants/users/core/src/lib/usecases update-impersonate-target.use-case.ts

97.59% Statements 81/83
78.94% Branches 15/19
100% Functions 2/2
97.59% Lines 81/83

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 841x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 3x 3x 3x 3x 3x 1x 1x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 2x 2x 4x 3x 2x 4x 1x 1x 1x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 4x 4x 4x 4x 4x 4x 4x 1x 1x 1x 1x 1x 1x 1x 1x     1x 4x 1x  
import { Injectable, Logger, NotFoundException } from '@nestjs/common';
import { EventBus } from '@nestjs/cqrs';
import { InjectRepository } from '@nestjs/typeorm';
import { pick } from 'lodash-es';
import { Repository } from 'typeorm';
 
import { User, type Company } from '@amalia/core/models';
import { type AuthenticatedContext } from '@amalia/kernel/auth/types';
import { RecordObject, RecordType } from '@amalia/tenants/monitoring/audit/types';
import { formatUserFullName } from '@amalia/tenants/users/types';
 
import { AppUsersRepository } from '../appUsers.repository';
import { UserSignedInEvent } from '../events/UserSignedInEvent';
 
@Injectable()
export class UpdateImpersonateTargetUseCase {
  private readonly logger = new Logger(UpdateImpersonateTargetUseCase.name);
 
  public constructor(
    @InjectRepository(User)
    private readonly userRepository: Repository<User>,
    private readonly appUsersRepository: AppUsersRepository,
    private readonly eventBus: EventBus,
  ) {}
 
  public async execute({
    company,
    authenticatedContext,
    userIdToImpersonate,
  }: {
    company: Company;
    authenticatedContext: AuthenticatedContext;
    userIdToImpersonate: string | null;
  }) {
    // If user is currently impersonating, get the impersonator instead of the current user
    const userToUpdate = authenticatedContext.impersonation
      ? ((await this.appUsersRepository.findUserByEmail(authenticatedContext.impersonation.impersonator.email)) as User)
      : await this.appUsersRepository.findOne(company, authenticatedContext.user.id);
 
    try {
      if (userIdToImpersonate) {
        userToUpdate.impersonate = await this.appUsersRepository.findOne(company, userIdToImpersonate);
        userToUpdate.impersonateId = userIdToImpersonate;
      } else {
        userToUpdate.impersonate = null;
        userToUpdate.impersonateId = null;
      }
 
      const savedUser = await this.userRepository.save(userToUpdate);
      await this.eventBus.publish(
        new UserSignedInEvent(company, savedUser, {
          authenticatedContext: {
            ...authenticatedContext,
            user: savedUser,
          },
          object: RecordObject.AUTHENTICATION,
          type: RecordType.IMPERSONATE,
          values: {
            target: {
              id: savedUser.id,
              name: formatUserFullName(savedUser),
            },
            newValues: {
              action: userIdToImpersonate ? 'Start impersonation' : 'Reset impersonation',
              impersonatedPeople: userIdToImpersonate ? formatUserFullName(savedUser.impersonate) : undefined,
            },
          },
        }),
      );
    } catch (error) {
      if (error instanceof NotFoundException) {
        this.logger.error({
          message: `User with id ${userIdToImpersonate} not found in Company ${company.name}`,
          error,
          company: pick(company, ['id', 'name']),
        });
        throw new NotFoundException(`User with id ${userIdToImpersonate} not found in Company ${company.name}`);
      } else {
        throw error;
      }
    }
  }
}