From 0b0aac10e14fb9e36f2aeb53ac107748ab0ef87b Mon Sep 17 00:00:00 2001 From: Chiquita Ahsanunnisa <16521248@mahasiswa.itb.ac.id> Date: Thu, 2 May 2024 08:52:06 +0700 Subject: [PATCH] refactor: periode validations to active status validation --- src/app.module.ts | 2 + src/bimbingan/bimbingan.module.ts | 7 +- src/bimbingan/bimbingan.service.ts | 10 +- src/dashboard/dashboard.service.ts | 4 +- src/dosen-bimbingan/dosen-bimbingan.module.ts | 7 +- src/entities/pengguna.entity.ts | 4 + src/pengguna/pengguna.module.ts | 11 ++ src/pengguna/pengguna.service.ts | 24 ++++ .../registrasi-tesis.controller.ts | 4 +- .../registrasi-tesis.module.ts | 5 +- .../registrasi-tesis.service.ts | 110 +++++++----------- 11 files changed, 108 insertions(+), 80 deletions(-) create mode 100644 src/pengguna/pengguna.module.ts create mode 100644 src/pengguna/pengguna.service.ts diff --git a/src/app.module.ts b/src/app.module.ts index 9367c42..bd865e2 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -18,6 +18,7 @@ import { validate } from "./env.validation"; import { BerkasBimbingan } from "./entities/berkasBimbingan.entity"; import { PendaftaranSidsem } from "./entities/pendaftaranSidsem"; import { DosenBimbinganModule } from "./dosen-bimbingan/dosen-bimbingan.module"; +import { PenggunaModule } from "./pengguna/pengguna.module"; @Module({ imports: [ @@ -48,6 +49,7 @@ import { DosenBimbinganModule } from "./dosen-bimbingan/dosen-bimbingan.module"; DashboardModule, BimbinganModule, DosenBimbinganModule, + PenggunaModule, ], controllers: [AppController], providers: [AppService], diff --git a/src/bimbingan/bimbingan.module.ts b/src/bimbingan/bimbingan.module.ts index e38f360..b77070f 100644 --- a/src/bimbingan/bimbingan.module.ts +++ b/src/bimbingan/bimbingan.module.ts @@ -6,6 +6,9 @@ import { Bimbingan } from "src/entities/bimbingan.entity"; import { PendaftaranTesis } from "src/entities/pendaftaranTesis.entity"; import { DosenBimbingan } from "src/entities/dosenBimbingan.entity"; import { BerkasBimbingan } from "src/entities/berkasBimbingan.entity"; +import { PenggunaModule } from "src/pengguna/pengguna.module"; +import { PenggunaService } from "src/pengguna/pengguna.service"; +import { Pengguna } from "src/entities/pengguna.entity"; @Module({ imports: [ @@ -14,10 +17,12 @@ import { BerkasBimbingan } from "src/entities/berkasBimbingan.entity"; PendaftaranTesis, DosenBimbingan, BerkasBimbingan, + Pengguna, ]), + PenggunaModule, ], controllers: [BimbinganController], - providers: [BimbinganService], + providers: [BimbinganService, PenggunaService], exports: [BimbinganService], }) export class BimbinganModule {} diff --git a/src/bimbingan/bimbingan.service.ts b/src/bimbingan/bimbingan.service.ts index 44a2824..825ce91 100644 --- a/src/bimbingan/bimbingan.service.ts +++ b/src/bimbingan/bimbingan.service.ts @@ -24,6 +24,7 @@ import { UpdateStatusResDto, } from "./bimbingan.dto"; import { BerkasBimbingan } from "src/entities/berkasBimbingan.entity"; +import { PenggunaService } from "src/pengguna/pengguna.service"; @Injectable() export class BimbinganService { @@ -36,12 +37,15 @@ export class BimbinganService { private dosenBimbinganRepository: Repository<DosenBimbingan>, @InjectRepository(BerkasBimbingan) private berkasBimbinganRepository: Repository<BerkasBimbingan>, + private penggunaService: PenggunaService, ) {} async getByMahasiswaId( mahasiswaId: string, user: AuthDto, ): Promise<GetByMahasiswaIdResDto> { + await this.penggunaService.isMahasiswaAktifOrFail(mahasiswaId); + const pendaftaran = await this.pendaftaranTesisRepository.findOne({ where: { mahasiswa: { id: mahasiswaId }, @@ -159,7 +163,7 @@ export class BimbinganService { user: AuthDto, dto: UpdateStatusDto, ): Promise<UpdateStatusResDto> { - const bimbingan = await this.getByBimbinganId(user, dto.bimbinganId); + const bimbingan = await this.getByBimbinganId(user, dto.bimbinganId); // already check if mahasiswa is aktif await this.bimbinganRepository.update(bimbingan.id, { disahkan: dto.status, @@ -189,6 +193,10 @@ export class BimbinganService { throw new NotFoundException("Bimbingan tidak ditemukan"); } + if (!bimbingan.pendaftaran.mahasiswa.aktif) { + throw new BadRequestException("Bimbingan milik mahasiswa tidak aktif"); + } + if ( !user.roles.includes(RoleEnum.ADMIN) && !bimbingan.pendaftaran.dosenBimbingan diff --git a/src/dashboard/dashboard.service.ts b/src/dashboard/dashboard.service.ts index 7486c33..f168aa3 100644 --- a/src/dashboard/dashboard.service.ts +++ b/src/dashboard/dashboard.service.ts @@ -41,6 +41,7 @@ export class DashboardService { dosenId, }, ) + .where("mahasiswa.aktif = true") .andWhere("pendaftaranTesis.status = :status", { status: RegStatus.APPROVED, }); @@ -94,7 +95,7 @@ export class DashboardService { .createQueryBuilder("pendaftaranTesis") .select("pendaftaranTesis.jalurPilihan", "jalurPilihan") .addSelect("COUNT(*)", "count") - .leftJoin("pendaftaranTesis.topik", "topik") + .leftJoin("pendaftaranTesis.mahasiswa", "mahasiswa") .innerJoin( "pendaftaranTesis.dosenBimbingan", "dosenBimbingan", @@ -103,6 +104,7 @@ export class DashboardService { dosenId, }, ) + .where("mahasiswa.aktif = true") .andWhere("pendaftaranTesis.status = :status", { status: RegStatus.APPROVED, }) diff --git a/src/dosen-bimbingan/dosen-bimbingan.module.ts b/src/dosen-bimbingan/dosen-bimbingan.module.ts index 5fef686..1721d9d 100644 --- a/src/dosen-bimbingan/dosen-bimbingan.module.ts +++ b/src/dosen-bimbingan/dosen-bimbingan.module.ts @@ -3,16 +3,11 @@ import { DosenBimbinganController } from "./dosen-bimbingan.controller"; import { DosenBimbinganService } from "./dosen-bimbingan.service"; import { AuthModule } from "src/auth/auth.module"; import { TypeOrmModule } from "@nestjs/typeorm"; -import { PendaftaranTesis } from "src/entities/pendaftaranTesis.entity"; -import { DosenBimbingan } from "src/entities/dosenBimbingan.entity"; import { Pengguna } from "src/entities/pengguna.entity"; import { CustomStrategy } from "src/middlewares/custom.strategy"; @Module({ - imports: [ - TypeOrmModule.forFeature([PendaftaranTesis, DosenBimbingan, Pengguna]), - AuthModule, - ], + imports: [TypeOrmModule.forFeature([Pengguna]), AuthModule], controllers: [DosenBimbinganController], providers: [DosenBimbinganService, CustomStrategy], }) diff --git a/src/entities/pengguna.entity.ts b/src/entities/pengguna.entity.ts index e1d014a..1b4971a 100644 --- a/src/entities/pengguna.entity.ts +++ b/src/entities/pengguna.entity.ts @@ -55,6 +55,10 @@ export class Pengguna { @Column({ type: "text", nullable: true }) kontak: string; + @ApiHideProperty() + @Column({ type: "boolean", default: true }) + aktif: boolean; + @OneToMany(() => PendaftaranTesis, (pendaftaran) => pendaftaran.mahasiswa) pendaftaranTesis: PendaftaranTesis[]; } diff --git a/src/pengguna/pengguna.module.ts b/src/pengguna/pengguna.module.ts new file mode 100644 index 0000000..3e5276c --- /dev/null +++ b/src/pengguna/pengguna.module.ts @@ -0,0 +1,11 @@ +import { Module } from "@nestjs/common"; +import { PenggunaService } from "./pengguna.service"; +import { TypeOrmModule } from "@nestjs/typeorm"; +import { Pengguna } from "src/entities/pengguna.entity"; + +@Module({ + imports: [TypeOrmModule.forFeature([Pengguna])], + providers: [PenggunaService], + exports: [PenggunaService], +}) +export class PenggunaModule {} diff --git a/src/pengguna/pengguna.service.ts b/src/pengguna/pengguna.service.ts new file mode 100644 index 0000000..2828171 --- /dev/null +++ b/src/pengguna/pengguna.service.ts @@ -0,0 +1,24 @@ +import { Injectable, NotFoundException } from "@nestjs/common"; +import { InjectRepository } from "@nestjs/typeorm"; +import { Pengguna, RoleEnum } from "src/entities/pengguna.entity"; +import { ArrayContains, Repository } from "typeorm"; + +@Injectable() +export class PenggunaService { + constructor( + @InjectRepository(Pengguna) + private penggunaRepo: Repository<Pengguna>, + ) {} + + async isMahasiswaAktifOrFail(id: string) { + const mhs = await this.penggunaRepo.findOneBy({ + id, + aktif: true, + roles: ArrayContains([RoleEnum.S2_MAHASISWA]), + }); + + if (!mhs) { + throw new NotFoundException("Mahasiswa aktif tidak ditemukan"); + } + } +} diff --git a/src/registrasi-tesis/registrasi-tesis.controller.ts b/src/registrasi-tesis/registrasi-tesis.controller.ts index e740095..0ac28ae 100644 --- a/src/registrasi-tesis/registrasi-tesis.controller.ts +++ b/src/registrasi-tesis/registrasi-tesis.controller.ts @@ -52,7 +52,7 @@ export class RegistrasiTesisController { ) {} @ApiOperation({ - summary: "Create new registration. Roles: S2_MAHASISWA, ADMIN", + summary: "Create new registration. Roles: S2_MAHASISWA", }) @ApiCreatedResponse({ type: IdDto }) @ApiNotFoundResponse({ description: "Penerima atau topik tidak ditemukan" }) @@ -61,7 +61,7 @@ export class RegistrasiTesisController { "Mahasiswa sedang memiliki pendaftaran aktif atau judul dan deskripsi topik baru tidak ada", }) @UseGuards(CustomAuthGuard, RolesGuard) - @Roles(RoleEnum.S2_MAHASISWA, RoleEnum.ADMIN) + @Roles(RoleEnum.S2_MAHASISWA) @Post() async createTopicRegistration( @Body() topicRegistrationDto: RegDto, diff --git a/src/registrasi-tesis/registrasi-tesis.module.ts b/src/registrasi-tesis/registrasi-tesis.module.ts index 8e177eb..0b64d44 100644 --- a/src/registrasi-tesis/registrasi-tesis.module.ts +++ b/src/registrasi-tesis/registrasi-tesis.module.ts @@ -8,6 +8,8 @@ import { RegistrasiTesisService } from "./registrasi-tesis.service"; import { Topik } from "src/entities/topik.entity"; import { CustomStrategy } from "src/middlewares/custom.strategy"; import { AuthModule } from "src/auth/auth.module"; +import { PenggunaModule } from "src/pengguna/pengguna.module"; +import { PenggunaService } from "src/pengguna/pengguna.service"; @Module({ imports: [ @@ -18,8 +20,9 @@ import { AuthModule } from "src/auth/auth.module"; Topik, ]), AuthModule, + PenggunaModule, ], controllers: [RegistrasiTesisController], - providers: [RegistrasiTesisService, CustomStrategy], + providers: [RegistrasiTesisService, CustomStrategy, PenggunaService], }) export class RegistrasiTesisModule {} diff --git a/src/registrasi-tesis/registrasi-tesis.service.ts b/src/registrasi-tesis/registrasi-tesis.service.ts index f3c861c..c2f221a 100644 --- a/src/registrasi-tesis/registrasi-tesis.service.ts +++ b/src/registrasi-tesis/registrasi-tesis.service.ts @@ -25,6 +25,7 @@ import { UpdatePembimbingBodyDto, UpdateStatusBodyDto, } from "./registrasi-tesis.dto"; +import { PenggunaService } from "src/pengguna/pengguna.service"; @Injectable() export class RegistrasiTesisService { @@ -38,6 +39,7 @@ export class RegistrasiTesisService { @InjectRepository(DosenBimbingan) private dosenBimbinganRepository: Repository<DosenBimbingan>, private dataSource: DataSource, + private penggunaService: PenggunaService, ) {} async createTopicRegistration( @@ -124,6 +126,8 @@ export class RegistrasiTesisService { isNewestOnly: boolean, idPenerima?: string, ) { + await this.penggunaService.isMahasiswaAktifOrFail(mahasiswaId); + const baseQuery = this.pendaftaranTesisRepository .createQueryBuilder("pt") .select("pt.id") @@ -208,56 +212,33 @@ export class RegistrasiTesisService { "latest", "latest.latest_mahasiswaId = pt.mahasiswaId AND pt.waktuPengiriman = latest.latestPengiriman", ) - .innerJoinAndSelect("pt.topik", "topik"); + .innerJoin("pt.mahasiswa", "mahasiswa") + .where("mahasiswa.aktif = true"); if (options.idPenerima) { - baseQuery.where("pt.penerimaId = :idPenerima", { + baseQuery.andWhere("pt.penerimaId = :idPenerima", { idPenerima: options.idPenerima, }); totalMahasiswa = baseQuery.getCount(); } - let totalDiterima: Promise<number>; - let totalProses: Promise<number>; - let totalDitolak: Promise<number>; + const totalDiterima = baseQuery + .clone() + .andWhere("pt.status = :status", { status: RegStatus.APPROVED }) + .getCount(); - if (options.idPenerima) { - // where used - totalDiterima = baseQuery - .clone() - .andWhere("pt.status = :status", { status: RegStatus.APPROVED }) - .getCount(); - - totalProses = baseQuery - .clone() - .andWhere("pt.status IN (:...status)", { - status: [RegStatus.NOT_ASSIGNED, RegStatus.INTERVIEW], - }) - .getCount(); - - totalDitolak = baseQuery - .clone() - .andWhere("pt.status = :status", { status: RegStatus.REJECTED }) - .getCount(); - } else { - totalDiterima = baseQuery - .clone() - .where("pt.status = :status", { status: RegStatus.APPROVED }) - .getCount(); - - totalProses = baseQuery - .clone() - .where("pt.status IN (:...status)", { - status: [RegStatus.NOT_ASSIGNED, RegStatus.INTERVIEW], - }) - .getCount(); - - totalDitolak = baseQuery - .clone() - .where("pt.status = :status", { status: RegStatus.REJECTED }) - .getCount(); - } + const totalProses = baseQuery + .clone() + .andWhere("pt.status IN (:...status)", { + status: [RegStatus.NOT_ASSIGNED, RegStatus.INTERVIEW], + }) + .getCount(); + + const totalDitolak = baseQuery + .clone() + .andWhere("pt.status = :status", { status: RegStatus.REJECTED }) + .getCount(); const [total, diterima, proses, ditolak] = await Promise.all([ totalMahasiswa, @@ -311,45 +292,32 @@ export class RegistrasiTesisService { ); baseQuery - .innerJoinAndSelect("pt.topik", "topik") .innerJoinAndSelect("pt.penerima", "penerima") - .innerJoinAndSelect("pt.mahasiswa", "mahasiswa"); + .innerJoinAndSelect("pt.mahasiswa", "mahasiswa") + .where("mahasiswa.aktif = true"); - let whereUsed = false; if (options.idPenerima) { - baseQuery.where("pt.penerimaId = :idPenerima", { + baseQuery.andWhere("pt.penerimaId = :idPenerima", { idPenerima: options.idPenerima, }); - - whereUsed = true; } if (options.search) { - const bracket = new Brackets((qb) => - qb - .where("mahasiswa.nama ILIKE :search", { - search: `%${options.search}%`, - }) - .orWhere("mahasiswa.nim ILIKE :search", { - search: `%${options.search}%`, - }), + baseQuery.andWhere( + new Brackets((qb) => + qb + .where("mahasiswa.nama ILIKE :search", { + search: `%${options.search}%`, + }) + .orWhere("mahasiswa.nim ILIKE :search", { + search: `%${options.search}%`, + }), + ), ); - - if (whereUsed) { - baseQuery.andWhere(bracket); - } else { - baseQuery.where(bracket); - whereUsed = true; - } } if (options.status) { - if (whereUsed) { - baseQuery.andWhere("pt.status = :status", { status: options.status }); - } else { - baseQuery.where("pt.status = :status", { status: options.status }); - whereUsed = true; - } + baseQuery.andWhere("pt.status = :status", { status: options.status }); } if (options.order_by) { @@ -444,6 +412,8 @@ export class RegistrasiTesisService { dto: UpdateInterviewBodyDto, idPenerima?: string, ) { + await this.penggunaService.isMahasiswaAktifOrFail(mahasiswaId); + const minDate = new Date(); minDate.setDate(minDate.getDate() + 2); @@ -486,6 +456,8 @@ export class RegistrasiTesisService { dto: UpdateStatusBodyDto, idPenerima?: string, ) { + await this.penggunaService.isMahasiswaAktifOrFail(mahasiswaId); + const newestReg = await this.getNewestRegByMhsOrFail(mahasiswaId); if (newestReg && idPenerima && newestReg.penerima.id !== idPenerima) { @@ -531,6 +503,8 @@ export class RegistrasiTesisService { mahasiswaId: string, { pembimbing_ids: dosen_ids }: UpdatePembimbingBodyDto, ) { + await this.penggunaService.isMahasiswaAktifOrFail(mahasiswaId); + const newestReg = await this.getNewestRegByMhsOrFail(mahasiswaId); if (newestReg.status !== RegStatus.APPROVED) -- GitLab