penisularhr / src / modules / rainfall / rainfall.controller.ts
rainfall.controller.ts
Raw
import {
  Body,
  Controller,
  Delete,
  Get,
  HttpCode,
  HttpStatus,
  Param,
  Patch,
  Post,
  Query,
} from '@nestjs/common';
import { ApiCreatedResponse, ApiOkResponse, ApiTags } from '@nestjs/swagger';
import moment from 'moment';

import { type PageDto } from '../../common/dto/page.dto';
import { RoleType } from '../../constants';
import { ApiPageOkResponse, Auth, AuthUser, Whitelist } from '../../decorators';
import {
  AccountHasClosedException,
  RainfallNotFoundException,
  RainfallRecordDateExceedTodayException,
  RecordMoreThan3DaysException,
} from '../../exceptions';
import { ApiConfigService } from '../../shared/services/api-config.service';
import { UserEntity } from '../user/user.entity';
import { CreateRainfallRecordDto } from './dtos/create-rainfall.dto';
import { RainfallRecordPageOptionsDto } from './dtos/get-rainfall-page.dto';
import { RainfallRecordDto } from './dtos/rainfall.dto';
import { UpdateRainfallRecordDto } from './dtos/update-rainfall.dto';
import { RainfallRecordService } from './rainfall.service';

@Controller('rainfall')
@ApiTags('rainfall')
export class RainfallController {
  constructor(
    private rainfallRecordService: RainfallRecordService,
    private configService: ApiConfigService,
  ) {}

  @Get()
  @Whitelist()
  @Auth([RoleType.ADMIN, RoleType.USER])
  @HttpCode(HttpStatus.OK)
  @ApiPageOkResponse({
    type: RainfallRecordDto,
    description: 'Get rainfall Records',
  })
  async getRainfallRecords(
    @Query() dto: RainfallRecordPageOptionsDto,
  ): Promise<PageDto<RainfallRecordDto>> {
    return this.rainfallRecordService.findMany(dto);
  }

  @Post()
  @Whitelist()
  @Auth([RoleType.ADMIN, RoleType.USER])
  @HttpCode(HttpStatus.CREATED)
  @ApiCreatedResponse()
  async createRainfall(
    @AuthUser() user: UserEntity,
    @Body() body: CreateRainfallRecordDto,
  ): Promise<RainfallRecordDto> {
    const { fromTime, toTime } = body;

    const recordDate = moment.utc(fromTime);
    const recordToTime = moment.utc(toTime);
    const currentDate = moment.utc();

    const recordDateMonth = moment.utc(fromTime).month();
    const currentMonth = moment.utc().month();

    const daysDifference = currentDate.diff(recordDate, 'days');

    if (this.configService.isProduction) {
      if (user.role === RoleType.USER && daysDifference > 3) {
        throw new RecordMoreThan3DaysException();
      }

      if (currentMonth - recordDateMonth >= 1 && currentDate.date() > 7) {
        throw new AccountHasClosedException();
      }

      if (recordToTime >= currentDate || recordDate >= currentDate) {
        throw new RainfallRecordDateExceedTodayException();
      }
    }

    const rainfallEntity =
      await this.rainfallRecordService.createRainfall(body);

    return rainfallEntity.toDto();
  }

  @Patch(':id')
  @Whitelist()
  @Auth([RoleType.ADMIN, RoleType.USER])
  @HttpCode(HttpStatus.OK)
  @ApiOkResponse()
  async updateRainfall(
    @AuthUser() user: UserEntity,
    @Param('id') id: Uuid,
    @Body() body: UpdateRainfallRecordDto,
  ): Promise<RainfallRecordDto> {
    const { fromTime, toTime } = body;

    const recordDate = moment.utc(fromTime);
    const recordToTime = moment.utc(toTime);
    const currentDate = moment.utc();

    const recordDateMonth = moment.utc(fromTime).month();
    const currentMonth = moment.utc().month();

    const daysDifference = currentDate.diff(recordDate, 'days');

    if (this.configService.isProduction) {
      if (user.role === RoleType.USER && daysDifference > 3) {
        throw new RecordMoreThan3DaysException();
      }

      if (currentMonth - recordDateMonth >= 1 && currentDate.date() > 7) {
        throw new AccountHasClosedException();
      }

      if (recordToTime >= currentDate || recordDate >= currentDate) {
        throw new RainfallRecordDateExceedTodayException();
      }
    }

    const toPatchEntity = await this.rainfallRecordService.findOne({
      id,
    });

    if (!toPatchEntity) {
      throw new RainfallNotFoundException();
    }

    const rainfallEntity = await this.rainfallRecordService.updateRainfall(
      toPatchEntity,
      body,
    );

    return rainfallEntity.toDto();
  }

  @Delete(':id')
  @Whitelist()
  @Auth([RoleType.ADMIN, RoleType.USER])
  @HttpCode(HttpStatus.OK)
  @ApiOkResponse()
  async deleteRainfall(
    @AuthUser() user: UserEntity,
    @Param('id') id: Uuid,
  ): Promise<Record<string, string>> {
    const toDeleteEntity = await this.rainfallRecordService.findOne({
      id,
    });

    if (!toDeleteEntity) {
      throw new RainfallNotFoundException();
    }

    const recordDate = moment.utc(toDeleteEntity.fromTime);
    const currentDate = moment.utc();

    const recordDateMonth = moment.utc(toDeleteEntity.fromTime).month();
    const currentMonth = moment.utc().month();

    const daysDifference = currentDate.diff(recordDate, 'days');

    if (this.configService.isProduction) {
      if (user.role === RoleType.USER && daysDifference > 3) {
        throw new RecordMoreThan3DaysException();
      }

      if (currentMonth - recordDateMonth >= 1 && currentDate.date() > 7) {
        throw new AccountHasClosedException();
      }
    }

    await this.rainfallRecordService.deleteRainfall(toDeleteEntity);

    return { status: 'success' };
  }
}