[TIL] 사용 로그 출력 23.09.04

이상훈·2023년 9월 5일
0

[내일배움캠프]

목록 보기
64/68

워크스페이스 디테일에 activity 내용을 출력해주기 위해
사용 로그를 만들기로 결정하였음

// audit-log.entity.ts
import { Column, CreateDateColumn, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
import { User } from './user.entitiy';
import { Workspace } from './workspace.entity';
import ActionType from '../utils/action-type';

@Entity('audit_logs')
export class Audit_log {
  @PrimaryGeneratedColumn({ type: 'bigint' })
  id: number;

  @Column({ type: 'enum', enum: ActionType, nullable: false })
  actions: ActionType;

  @Column({ nullable: false })
  details: string;

  @CreateDateColumn()
  created_at: Date;

  @ManyToOne(() => User, (user) => user.audit_logs)
  user: User;

  @ManyToOne(() => Workspace, (workspace) => workspace.audit_logs, {
    onDelete: 'CASCADE',
    nullable: false,
  })
  workspace: Workspace;
}

초반에는 board, boardColumn, card도 관계설정을 해뒀다. 어떤 부분에서 이벤트가 발생하는지 출력을 해주기 위함이였는데 다시 생각해보니 워크스페이스 디테일에 들어가는 로그기 때문에, 어떤 유저와 어떤 워크스페이스에서 이벤트가 발생했는지만 출력해주면 될 것 같다고 판단되어 변경하였음

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Audit_log } from 'src/_common/entities/audit-log.entity';
import ActionType from 'src/_common/utils/action-type';
import { Repository } from 'typeorm';

@Injectable()
export class AuditLogsService {
  constructor(
    @InjectRepository(Audit_log)
    private auditLogRepository: Repository<Audit_log>
  ) {}

  async inviteMemberLog(
    workspaceId: number,
    inviterUserId: number,
    inviterUserName: string,
    invitedUserName: string
  ): Promise<Audit_log> {
    const newLog = this.auditLogRepository.create({
      workspace: { id: workspaceId },
      user: { id: inviterUserId },
      actions: ActionType.INVITE,
      details: `멤버 초대 - ${inviterUserName}님이 ${invitedUserName}님을 워크스페이스에 초대하였습니다. `,
    });

    return await this.auditLogRepository.save(newLog);
  }

  async deleteMemberLog(
    workspaceId: number,
    userId: number,
    userName: string,
    deletedUser: string
  ): Promise<Audit_log> {
    const newLog = this.auditLogRepository.create({
      workspace: { id: workspaceId },
      user: { id: userId },
      actions: ActionType.DELETE,
      details: `멤버 삭제 - ${userName}님이 ${deletedUser}님을 워크스페이스에서 내보냈습니다.`,
    });

    return await this.auditLogRepository.save(newLog);
  }

  async roleChangeLog(
    workspaceId: number,
    userId: number,
    userName: string,
    targetUser: string,
    role: string
  ): Promise<Audit_log> {
    const newLog = this.auditLogRepository.create({
      workspace: { id: workspaceId },
      user: { id: userId },
      actions: ActionType.ROLE_CHANGE,
      details: `역할 변경 - ${userName}님이 ${targetUser}님의 역할을 ${role}로 변경했습니다.`,
    });

    return await this.auditLogRepository.save(newLog);
  }

  async createBoardLog(workspaceId: number, boardName: string, userId: number, userName: string): Promise<Audit_log> {
    const newLog = this.auditLogRepository.create({
      workspace: { id: workspaceId },
      user: { id: userId },
      actions: ActionType.CREATE,
      details: `보드 생성 - ${userName}님이 ${boardName} 보드를 생성하였습니다.`,
    });

    return await this.auditLogRepository.save(newLog);
  }

  async updateBoardLog(
    workspaceId: number,
    beforeBoardName: string,
    afterBoardName: string,
    userId: number,
    userName: string
  ): Promise<Audit_log> {
    if (beforeBoardName === afterBoardName) {
      const newLog = this.auditLogRepository.create({
        workspace: { id: workspaceId },
        user: { id: userId },
        actions: ActionType.UPDATE,
        details: `보드 수정 - ${userName}님이 ${beforeBoardName} 보드를 수정하였습니다.`,
      });

      return await this.auditLogRepository.save(newLog);
    } else {
      const newLog = this.auditLogRepository.create({
        workspace: { id: workspaceId },
        user: { id: userId },
        actions: ActionType.UPDATE,
        details: `보드 수정 - ${userName}님이 ${beforeBoardName} 보드를 ${afterBoardName} 보드로 수정하였습니다.`,
      });

      return await this.auditLogRepository.save(newLog);
    }
  }

  async deleteBoardLog(workspaceId: number, boardName: string, userId: number, userName: string): Promise<Audit_log> {
    const newLog = this.auditLogRepository.create({
      workspace: { id: workspaceId },
      user: { id: userId },
      actions: ActionType.DELETE,
      details: `보드 삭제 - ${userName}님이 ${boardName} 보드를 삭제하였습니다.`,
    });

    return await this.auditLogRepository.save(newLog);
  }

  async createColumnLog(workspaceId: number, columnName: string, userId: number, userName: string): Promise<Audit_log> {
    const newLog = this.auditLogRepository.create({
      workspace: { id: workspaceId },
      user: { id: userId },
      actions: ActionType.CREATE,
      details: `컬럼 생성 - ${userName}님이 ${columnName} 컬럼을 생성하였습니다.`,
    });

    return await this.auditLogRepository.save(newLog);
  }

  async updateColumnLog(
    workspaceId: number,
    beforeColumnName: string,
    afterColumnName: string,
    userId: number,
    userName: string
  ): Promise<Audit_log> {
    if (beforeColumnName === afterColumnName) {
      const newLog = this.auditLogRepository.create({
        workspace: { id: workspaceId },
        user: { id: userId },
        actions: ActionType.UPDATE,
        details: `컬럼 수정 - ${userName}님이 ${beforeColumnName} 컬럼을 수정하였습니다.`,
      });

      return await this.auditLogRepository.save(newLog);
    } else {
      const newLog = this.auditLogRepository.create({
        workspace: { id: workspaceId },
        user: { id: userId },
        actions: ActionType.UPDATE,
        details: `컬럼 수정 - ${userName}님이 ${beforeColumnName} 컬럼을 ${afterColumnName} 컬럼으로 수정하였습니다.`,
      });

      return await this.auditLogRepository.save(newLog);
    }
  }

  async deleteColumnLog(workspaceId: number, columnName: string, userId: number, userName: string): Promise<Audit_log> {
    const newLog = this.auditLogRepository.create({
      workspace: { id: workspaceId },
      user: { id: userId },
      actions: ActionType.DELETE,
      details: `컬럼 삭제 - ${userName}님이 ${columnName} 컬럼을 삭제하였습니다.`,
    });

    return await this.auditLogRepository.save(newLog);
  }

  async createCardLog(workspaceId: number, cardName: string, userId: number, userName: string): Promise<Audit_log> {
    const newLog = this.auditLogRepository.create({
      workspace: { id: workspaceId },
      user: { id: userId },
      actions: ActionType.CREATE,
      details: `카드 생성 - ${userName}님이 ${cardName} 카드를 생성하였습니다.`,
    });

    return await this.auditLogRepository.save(newLog);
  }

  async updateCardLog(
    workspaceId: number,
    beforeCardName: string,
    afterCardName: string,
    userId: number,
    userName: string
  ) {
    if (beforeCardName === afterCardName) {
      const newLog = this.auditLogRepository.create({
        workspace: { id: workspaceId },
        user: { id: userId },
        actions: ActionType.UPDATE,
        details: `카드 수정 - ${userName}님이 ${beforeCardName} 카드를 수정하였습니다.`,
      });

      return await this.auditLogRepository.save(newLog);
    } else {
      const newLog = this.auditLogRepository.create({
        workspace: { id: workspaceId },
        user: { id: userId },
        actions: ActionType.UPDATE,
        details: `카드 수정 - ${userName}님이 ${beforeCardName} 카드를 ${afterCardName} 카드로 수정하였습니다.`,
      });

      return await this.auditLogRepository.save(newLog);
    }
  }

  async deleteCardLog(workspaceId: number, cardName: string, userId: number, userName: string) {
    const newLog = this.auditLogRepository.create({
      workspace: { id: workspaceId },
      user: { id: userId },
      actions: ActionType.DELETE,
      details: `카드 수정 - ${userName}님이 ${cardName} 카드를 삭제하였습니다.`,
    });
    return await this.auditLogRepository.save(newLog);
  }
}

다소 반복되는감이 없지 않아 있긴 하지만 각 이벤트별로 출력될 로그들을 미리 작성해두고 테스트

//workspace.service.ts

  // 멤버 권한 변경
  async setMemberRole(
    body: SetRoleDto,
    workspaceId: number,
    userId: number,
    loginUserName: string,
    loginUserId: number
  ): Promise<IResult> {
    const existMember = await this.workspaceMemberRepository.findOne({
      where: { workspace: { id: workspaceId }, user: { id: userId } },
      relations: ['user'],
    });
    const loginUserRole = await this.loginUserRole(loginUserId, workspaceId);

    if (!existMember) throw new HttpException('해당 멤버가 존재하지 않습니다.', HttpStatus.NOT_FOUND);

    if (loginUserRole / 1 >= existMember.role)
      throw new HttpException('관리자 또는 어드민 계정은 역할 변경이 불가합니다.', HttpStatus.BAD_REQUEST);

    await this.workspaceMemberRepository.update(
      { user: { id: userId }, workspace: { id: workspaceId } },
      { role: body.role }
    );

    let role = '';
    if (body.role === 2) role = 'Manager';
    if (body.role === 3) role = 'Member';
    if (body.role === 4) role = 'OutSourcing';

    await this.auditLogService.roleChangeLog(workspaceId, userId, loginUserName, existMember.user.name, role);

    return { result: true };
  }

멤버권한 변경하는 코드의 하단부에 roleChangeLog 메서드를 추가해준 뒤 실행해보면


2번 유저가 15번 워크스페이스에서 만든 이벤트가 audit_log 테이블에 잘 쌓이고 있는 것을 확인.

이것을 이제 프론트에 연결해주는 작업 및 socket도 연결하여 실시간으로 이벤트가 발생할때마다 접속해있는 인원도 확인할 수 있게 만들면 마무리 될 것 같음!

profile
코린이

0개의 댓글