From f3b9881668742bf5387f96f575cda3f4a61e18e5 Mon Sep 17 00:00:00 2001 From: jlazaro Date: Fri, 11 Oct 2024 05:38:16 -0300 Subject: [PATCH 01/11] =?UTF-8?q?feat(Cria=C3=A7=C3=A3o=20do=20Servi=C3=A7?= =?UTF-8?q?o=20de=20Candidatura:create(createCandidacyDto;=20getCandidacyB?= =?UTF-8?q?yUserId(usuarioId:=20UUID);=20closeCandidacy(id:=20UUID):=20Atu?= =?UTF-8?q?alizar=20o=20status=20da=20candidatura)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.module.ts | 3 +- src/candidacy/candidacy.service.spec.ts | 18 +++++++++ src/candidacy/candidacy.service.ts | 29 ++++++++++++++ src/candidacy/dto/create-candidacy.dto.ts | 11 +++++ src/database/entities/candidacy.entity.ts | 39 ++++++++++++++++++ src/database/entities/users.entity.ts | 4 ++ .../repository/candidacy.repository.ts | 40 +++++++++++++++++++ 7 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 src/candidacy/candidacy.service.spec.ts create mode 100644 src/candidacy/candidacy.service.ts create mode 100644 src/candidacy/dto/create-candidacy.dto.ts create mode 100644 src/database/entities/candidacy.entity.ts create mode 100644 src/modules/candidacy/repository/candidacy.repository.ts diff --git a/src/app.module.ts b/src/app.module.ts index a72d171..f267846 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -16,6 +16,7 @@ import { UserModule } from './modules/user/user.module'; import { ApplicationsModule } from './modules/applications/applications.module'; import { typeormConfig } from './database/data-source';import { PassportModule } from '@nestjs/passport'; import { AlertsService } from './alerts/alerts.service'; +import { CandidacyService } from './candidacy/candidacy.service'; @Module({ imports: [ @@ -40,6 +41,6 @@ import { AlertsService } from './alerts/alerts.service'; ApplicationsModule, ], controllers: [AppController], - providers: [AppService, AlertsService], + providers: [AppService, AlertsService, CandidacyService], }) export class AppModule {} diff --git a/src/candidacy/candidacy.service.spec.ts b/src/candidacy/candidacy.service.spec.ts new file mode 100644 index 0000000..17fdb94 --- /dev/null +++ b/src/candidacy/candidacy.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { CandidacyService } from './candidacy.service'; + +describe('CandidacyService', () => { + let service: CandidacyService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [CandidacyService], + }).compile(); + + service = module.get(CandidacyService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/candidacy/candidacy.service.ts b/src/candidacy/candidacy.service.ts new file mode 100644 index 0000000..33ed2a0 --- /dev/null +++ b/src/candidacy/candidacy.service.ts @@ -0,0 +1,29 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { CandidacyRepository } from 'src/modules/candidacy/repository/candidacy.repository'; +import { CreateCandidacyDto } from 'src/candidacy/dto/create-candidacy.dto'; +import { CandidacyEntity } from '../database/entities/candidacy.entity'; + +@Injectable() +export class CandidacyService { + constructor( + @InjectRepository(CandidacyRepository) + private readonly candidacyRepository: CandidacyRepository + ) {} + + async create(createCandidacyDto: CreateCandidacyDto): Promise { + const candidacy = new CandidacyEntity(); + candidacy.userId = createCandidacyDto.userId; + candidacy.jobId = createCandidacyDto.jobId; + candidacy.status = 'Em andamento'; + return this.candidacyRepository.createCandidacy(candidacy); + } + + async getCandidacyByUserId(userId: string): Promise { + return this.candidacyRepository.findAllByUserId(userId); + } + + async closeCandidacy(id: string, status: 'Encerrada' | 'Sem interesse'): Promise { + return this.candidacyRepository.updateStatus(id, status); + } +} diff --git a/src/candidacy/dto/create-candidacy.dto.ts b/src/candidacy/dto/create-candidacy.dto.ts new file mode 100644 index 0000000..1a233b9 --- /dev/null +++ b/src/candidacy/dto/create-candidacy.dto.ts @@ -0,0 +1,11 @@ +import { IsUUID, IsNotEmpty } from 'class-validator'; + +export class CreateCandidacyDto { + @IsUUID() + @IsNotEmpty() + userId: string; + + @IsUUID() + @IsNotEmpty() + jobId: string; +} diff --git a/src/database/entities/candidacy.entity.ts b/src/database/entities/candidacy.entity.ts new file mode 100644 index 0000000..7731c38 --- /dev/null +++ b/src/database/entities/candidacy.entity.ts @@ -0,0 +1,39 @@ +import { + Column, + Entity, + PrimaryGeneratedColumn, + ManyToOne, + JoinColumn, +} from 'typeorm'; +import { UsersEntity } from './users.entity'; +import { JobsEntity } from './jobs.entity'; + +@Entity('tb_candidacies') +export class CandidacyEntity { + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column('uuid') + jobId: string; + + @Column('uuid') + userId: string; + + @Column({ type: 'enum', enum: ['em andamento', 'encerrada', 'sem interesse'] }) + status: string; + + @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }) + dataCandidatura: Date; + + @Column({ type: 'timestamp', nullable: true }) + dataEncerramento: Date; + + @ManyToOne(() => UsersEntity) + @JoinColumn({ name: 'userId' }) + user: UsersEntity; + + @ManyToOne(() => JobsEntity) + @JoinColumn({ name: 'jobId' }) + job: JobsEntity; +} + diff --git a/src/database/entities/users.entity.ts b/src/database/entities/users.entity.ts index 2f20bf3..62c6934 100644 --- a/src/database/entities/users.entity.ts +++ b/src/database/entities/users.entity.ts @@ -11,6 +11,7 @@ import { import { ApplicationEntity } from './applications.entity'; import { CurriculumEntity } from './curriculum.entity'; import { PersonalDataEntity } from './personal-data.entity'; +import { CandidacyEntity } from './candidacy.entity'; enum RolesEnum { ADMIN = 'ADMIN', @@ -72,6 +73,9 @@ export class UsersEntity { @OneToMany(() => ApplicationEntity, (application) => application.user) applications: ApplicationEntity[]; + @OneToMany(() => CandidacyEntity, (candidacy) => candidacy.user) + candidacies: CandidacyEntity[]; + @CreateDateColumn() created_at: Date; diff --git a/src/modules/candidacy/repository/candidacy.repository.ts b/src/modules/candidacy/repository/candidacy.repository.ts new file mode 100644 index 0000000..dcb73f5 --- /dev/null +++ b/src/modules/candidacy/repository/candidacy.repository.ts @@ -0,0 +1,40 @@ +import { Injectable } from '@nestjs/common'; +import { Repository } from 'typeorm'; +import { CandidacyEntity } from '../../../database/entities/candidacy.entity'; +import { InjectRepository } from '@nestjs/typeorm'; + +@Injectable() +export class CandidacyRepository { + constructor( + @InjectRepository(CandidacyEntity) + private candidacyRepository: Repository, + ) {} + + async createCandidacy(candidacy: CandidacyEntity): Promise { + return this.candidacyRepository.save(candidacy); + } + + async findAllByUserId(userId: string): Promise { + return this.candidacyRepository.find({ where: { user: { id: userId } } }); + } + + async updateStatus(id: string, status: string): Promise { + try { + const candidacies = await this.candidacyRepository.find({ where: { id } }); + + if (candidacies.length === 0) { + return undefined; + } + const candidacyToUpdate = candidacies[0]; + candidacyToUpdate.status = status; + + await this.candidacyRepository.save(candidacyToUpdate); + + return candidacyToUpdate; + } catch (error) { + + return undefined; + } + } + +} \ No newline at end of file From c247373e3de5e9facf1a0a98859a51972c982bd2 Mon Sep 17 00:00:00 2001 From: jlazaro Date: Tue, 22 Oct 2024 04:01:59 -0300 Subject: [PATCH 02/11] =?UTF-8?q?feat=20(Corre=C3=A7=C3=B5es=20e=20melhori?= =?UTF-8?q?as=20no=20servi=C3=A7o=20de=20candidaturas=20incluindo=20tratam?= =?UTF-8?q?ento=20de=20erros.)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/candidacy/candidacy.service.ts | 53 ++++++++++++++++--- src/database/entities/candidacy.entity.ts | 9 ++-- .../entities/candidancy-status.enum.ts | 5 ++ .../repository/candidacy.repository.ts | 43 +++++++++------ 4 files changed, 85 insertions(+), 25 deletions(-) create mode 100644 src/database/entities/candidancy-status.enum.ts diff --git a/src/candidacy/candidacy.service.ts b/src/candidacy/candidacy.service.ts index 33ed2a0..8a12b07 100644 --- a/src/candidacy/candidacy.service.ts +++ b/src/candidacy/candidacy.service.ts @@ -1,8 +1,9 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, BadRequestException, NotFoundException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { CandidacyRepository } from 'src/modules/candidacy/repository/candidacy.repository'; import { CreateCandidacyDto } from 'src/candidacy/dto/create-candidacy.dto'; import { CandidacyEntity } from '../database/entities/candidacy.entity'; +import { CandidacyStatus } from '../database/entities/candidancy-status.enum'; @Injectable() export class CandidacyService { @@ -12,18 +13,58 @@ export class CandidacyService { ) {} async create(createCandidacyDto: CreateCandidacyDto): Promise { + + if (!createCandidacyDto.userId || !createCandidacyDto.jobId) { + throw new BadRequestException('userId e jobId são obrigatórios'); + } + const candidacy = new CandidacyEntity(); candidacy.userId = createCandidacyDto.userId; candidacy.jobId = createCandidacyDto.jobId; - candidacy.status = 'Em andamento'; - return this.candidacyRepository.createCandidacy(candidacy); + candidacy.status = CandidacyStatus.InProgress; + + try { + return await this.candidacyRepository.createCandidacy(candidacy); + } catch (error) { + throw new BadRequestException('Erro ao criar a candidatura: ' + error.message); + } } async getCandidacyByUserId(userId: string): Promise { - return this.candidacyRepository.findAllByUserId(userId); + if (!userId) { + throw new BadRequestException('userId é obrigatório'); + } + + try { + const candidacy = await this.candidacyRepository.findAllByUserId(userId); + if (!candidacy.length) { + throw new NotFoundException('Nenhuma candidatura encontrada para este usuário'); + } + return candidacy; + } catch (error) { + throw new BadRequestException('Erro ao buscar candidaturas: ' + error.message); + } + } - async closeCandidacy(id: string, status: 'Encerrada' | 'Sem interesse'): Promise { - return this.candidacyRepository.updateStatus(id, status); + async closeCandidacy(id: string, status: CandidacyStatus.Closed | CandidacyStatus.NoInterest): Promise { + if (!id) { + throw new BadRequestException('ID é obrigatório'); + } + + if (!Object.values(CandidacyStatus).includes(status)) { + throw new BadRequestException('Status inválido'); + } + + try { + const candidacy = await this.candidacyRepository.updateStatus(id, status); + if (!candidacy) { + throw new NotFoundException('Candidatura não encontrada'); + } + return candidacy; + } catch (error) { + throw new BadRequestException('Erro ao encerrar a candidatura: ' + error.message); + } } + } diff --git a/src/database/entities/candidacy.entity.ts b/src/database/entities/candidacy.entity.ts index 7731c38..8bd4e06 100644 --- a/src/database/entities/candidacy.entity.ts +++ b/src/database/entities/candidacy.entity.ts @@ -7,6 +7,7 @@ import { } from 'typeorm'; import { UsersEntity } from './users.entity'; import { JobsEntity } from './jobs.entity'; +import { CandidacyStatus } from './candidancy-status.enum'; @Entity('tb_candidacies') export class CandidacyEntity { @@ -19,14 +20,14 @@ export class CandidacyEntity { @Column('uuid') userId: string; - @Column({ type: 'enum', enum: ['em andamento', 'encerrada', 'sem interesse'] }) - status: string; + @Column({ type: 'enum', enum: CandidacyStatus }) + status: CandidacyStatus; @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }) - dataCandidatura: Date; + dateCandidacy: Date; @Column({ type: 'timestamp', nullable: true }) - dataEncerramento: Date; + dateaClosing: Date; @ManyToOne(() => UsersEntity) @JoinColumn({ name: 'userId' }) diff --git a/src/database/entities/candidancy-status.enum.ts b/src/database/entities/candidancy-status.enum.ts new file mode 100644 index 0000000..f9a0897 --- /dev/null +++ b/src/database/entities/candidancy-status.enum.ts @@ -0,0 +1,5 @@ +export enum CandidacyStatus { + InProgress = 'em andamento', + Closed = 'encerrada', + NoInterest = 'sem interesse', +} \ No newline at end of file diff --git a/src/modules/candidacy/repository/candidacy.repository.ts b/src/modules/candidacy/repository/candidacy.repository.ts index dcb73f5..4589446 100644 --- a/src/modules/candidacy/repository/candidacy.repository.ts +++ b/src/modules/candidacy/repository/candidacy.repository.ts @@ -1,7 +1,8 @@ -import { Injectable } from '@nestjs/common'; +import { BadRequestException, Injectable, InternalServerErrorException, NotFoundException } from '@nestjs/common'; import { Repository } from 'typeorm'; import { CandidacyEntity } from '../../../database/entities/candidacy.entity'; import { InjectRepository } from '@nestjs/typeorm'; +import { CandidacyStatus } from 'src/database/entities/candidancy-status.enum'; @Injectable() export class CandidacyRepository { @@ -14,26 +15,38 @@ export class CandidacyRepository { return this.candidacyRepository.save(candidacy); } - async findAllByUserId(userId: string): Promise { - return this.candidacyRepository.find({ where: { user: { id: userId } } }); + async findAllByUserId(userId: string): Promise { + if (!userId) { + throw new BadRequestException('userId é obrigatório'); + } + try { + const candidacy = await this.candidacyRepository.find({ where: { userId: userId } }); + if (!candidacy.length) { + throw new NotFoundException('Nenhuma candidatura encontrada para este usuário'); + } + return candidacy; + } catch (error) { + throw new BadRequestException('Erro ao buscar candidaturas: ' + error.message); + } } - async updateStatus(id: string, status: string): Promise { + async updateStatus(id: string, status: CandidacyStatus): Promise { try { - const candidacies = await this.candidacyRepository.find({ where: { id } }); - - if (candidacies.length === 0) { - return undefined; + const candidacy = await this.candidacyRepository.findOne({ where: { id } }); + if (!candidacy) { + throw new NotFoundException('Candidatura não encontrada'); } - const candidacyToUpdate = candidacies[0]; - candidacyToUpdate.status = status; - - await this.candidacyRepository.save(candidacyToUpdate); - - return candidacyToUpdate; + candidacy.status = status; + await this.candidacyRepository.save(candidacy); + + return candidacy; } catch (error) { + if (error instanceof NotFoundException) { + throw error; - return undefined; + } else { + throw new InternalServerErrorException('Erro ao atualizar o status da candidatura: ' + error.message); + } } } From 118797b3592af1bd2190cee10a86841f6294d767 Mon Sep 17 00:00:00 2001 From: jlazaro Date: Wed, 23 Oct 2024 17:43:10 -0300 Subject: [PATCH 03/11] feat (Corrigido: dateaClosing --> dateClosing.) --- src/database/entities/candidacy.entity.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/database/entities/candidacy.entity.ts b/src/database/entities/candidacy.entity.ts index 8bd4e06..99ac16e 100644 --- a/src/database/entities/candidacy.entity.ts +++ b/src/database/entities/candidacy.entity.ts @@ -27,7 +27,7 @@ export class CandidacyEntity { dateCandidacy: Date; @Column({ type: 'timestamp', nullable: true }) - dateaClosing: Date; + dateClosing: Date; @ManyToOne(() => UsersEntity) @JoinColumn({ name: 'userId' }) From 82c657743dfab57fd53c3208b8e20fdb48c065c4 Mon Sep 17 00:00:00 2001 From: jlazaro Date: Fri, 25 Oct 2024 13:25:01 -0300 Subject: [PATCH 04/11] feat (Corrigido: Cadidacy.entity.ts.) --- src/database/entities/candidacy.entity.ts | 41 ++++++++++++----------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/database/entities/candidacy.entity.ts b/src/database/entities/candidacy.entity.ts index 99ac16e..a81c354 100644 --- a/src/database/entities/candidacy.entity.ts +++ b/src/database/entities/candidacy.entity.ts @@ -4,37 +4,40 @@ import { PrimaryGeneratedColumn, ManyToOne, JoinColumn, -} from 'typeorm'; -import { UsersEntity } from './users.entity'; -import { JobsEntity } from './jobs.entity'; -import { CandidacyStatus } from './candidancy-status.enum'; - -@Entity('tb_candidacies') -export class CandidacyEntity { + } from 'typeorm'; + import { UsersEntity } from './users.entity'; + import { JobsEntity } from './jobs.entity'; + import { CandidacyStatus } from './candidancy-status.enum'; + + @Entity('tb_candidacies', { indexes: [{ columns: ['userId'] }, { columns: ['jobId'] }] }) + export class CandidacyEntity { @PrimaryGeneratedColumn('uuid') id: string; - + @Column('uuid') jobId: string; - + @Column('uuid') - userId: string; - + userId: string; + @Column({ type: 'enum', enum: CandidacyStatus }) status: CandidacyStatus; - + @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }) dateCandidacy: Date; - - @Column({ type: 'timestamp', nullable: true }) + + @Column({ + type: 'timestamp', + nullable: true, + onUpdate: () => 'CURRENT_TIMESTAMP' + }) dateClosing: Date; - + @ManyToOne(() => UsersEntity) @JoinColumn({ name: 'userId' }) - user: UsersEntity; - + user: UsersEntity; + @ManyToOne(() => JobsEntity) @JoinColumn({ name: 'jobId' }) job: JobsEntity; -} - + } \ No newline at end of file From 6961a217110628caf656484ef1b8b61454393ea3 Mon Sep 17 00:00:00 2001 From: Guilherme Sanches Date: Wed, 30 Oct 2024 13:53:17 -0300 Subject: [PATCH 05/11] :wrench: fix(candidacy): files --- src/alerts/alerts.service.spec.ts | 18 ------- src/alerts/alerts.service.ts | 47 ----------------- src/alerts/dto/create-alert.dto.ts | 5 -- src/app.module.ts | 2 +- src/database/data-source.ts | 50 +++++++++---------- .../candidacy/candidacy.service.spec.ts | 2 +- .../candidacy/candidacy.service.ts | 42 ++++++++++------ .../candidacy/dto/create-candidacy.dto.ts | 0 .../repository/candidacy.repository.ts | 40 ++++++++++----- 9 files changed, 83 insertions(+), 123 deletions(-) delete mode 100644 src/alerts/alerts.service.spec.ts delete mode 100644 src/alerts/alerts.service.ts delete mode 100644 src/alerts/dto/create-alert.dto.ts rename src/{ => modules}/candidacy/candidacy.service.spec.ts (85%) rename src/{ => modules}/candidacy/candidacy.service.ts (61%) rename src/{ => modules}/candidacy/dto/create-candidacy.dto.ts (100%) diff --git a/src/alerts/alerts.service.spec.ts b/src/alerts/alerts.service.spec.ts deleted file mode 100644 index 0294813..0000000 --- a/src/alerts/alerts.service.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { AlertsService } from './alerts.service'; - -describe('AlertsService', () => { - let service: AlertsService; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [AlertsService], - }).compile(); - - service = module.get(AlertsService); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); -}); diff --git a/src/alerts/alerts.service.ts b/src/alerts/alerts.service.ts deleted file mode 100644 index aad7f56..0000000 --- a/src/alerts/alerts.service.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { AlertsRepository } from '../modules/alert/repository/alerts.repository' -import { JobsEntity } from '../database/entities/jobs.entity' -import { MailerService } from '@nestjs-modules/mailer'; -import axios from 'axios'; - -@Injectable() -export class AlertsService { - constructor( - private readonly mailerService: MailerService, - private readonly alertsRepository: AlertsRepository, - - ) {} - - - async sendEmailsDaily() { - const alerts = await this.alertsRepository.findAll(); - for (const alert of alerts) { - const jobs = await this.findJobs(alert.keyword, alert.location); - const userEmail = alert.user.email; - await this.sendEmail(userEmail, jobs); - } - } - - private findEmailUser(userId: number) { - // Simulação de busca de e-mail do usuário - return 'usuario@example.com'; - } - - private async findJobs(keyword: string, location: string): Promise { - // Exemplo de busca simples - const response = await axios.get(`/jobs?keyword=${keyword}&location=${location}`); - return response.data; - } - - private async sendEmail(email: string, jobs: JobsEntity[]): Promise { - await this.mailerService.sendMail({ - to: email, - subject: 'Vagas Relevantes para Você', - template: './vagas', - context: { - jobs, - }, - }); - } - -} \ No newline at end of file diff --git a/src/alerts/dto/create-alert.dto.ts b/src/alerts/dto/create-alert.dto.ts deleted file mode 100644 index 4005b55..0000000 --- a/src/alerts/dto/create-alert.dto.ts +++ /dev/null @@ -1,5 +0,0 @@ -export class CreateAlertDto { - keyword: string; - location: string; - userId: number; - } \ No newline at end of file diff --git a/src/app.module.ts b/src/app.module.ts index f267846..6210304 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -16,7 +16,7 @@ import { UserModule } from './modules/user/user.module'; import { ApplicationsModule } from './modules/applications/applications.module'; import { typeormConfig } from './database/data-source';import { PassportModule } from '@nestjs/passport'; import { AlertsService } from './alerts/alerts.service'; -import { CandidacyService } from './candidacy/candidacy.service'; +import { CandidacyService } from './modules/candidacy/candidacy.service'; @Module({ imports: [ diff --git a/src/database/data-source.ts b/src/database/data-source.ts index 6b5586a..c84b9f4 100644 --- a/src/database/data-source.ts +++ b/src/database/data-source.ts @@ -1,35 +1,35 @@ -import { config } from "dotenv"; -config() -import { DataSource, DataSourceOptions } from "typeorm"; -import "reflect-metadata" +import { config } from 'dotenv'; +config(); +import { DataSource, DataSourceOptions } from 'typeorm'; +import 'reflect-metadata'; const { - TYPEORM_HOST, - TYPEORM_PORT, - TYPEORM_PASSWORD, - TYPEORM_USERNAME, - TYPEORM_DATABASE, - CA_CERT, - } = process.env; + TYPEORM_HOST, + TYPEORM_PORT, + TYPEORM_PASSWORD, + TYPEORM_USERNAME, + TYPEORM_DATABASE, + CA_CERT, +} = process.env; export const typeormConfig: DataSourceOptions = { - type: 'postgres', - host: TYPEORM_HOST, - port: +TYPEORM_PORT, - username: TYPEORM_USERNAME, - password: TYPEORM_PASSWORD, - database: TYPEORM_DATABASE, - entities: ['dist/database/entities/*.entity.js'], - migrations: [ - 'dist/database/migrations/*.js', - 'dist/database/migrations/seeds/*.js', - ], + type: 'postgres', + host: TYPEORM_HOST, + port: +TYPEORM_PORT, + username: TYPEORM_USERNAME, + password: TYPEORM_PASSWORD, + database: TYPEORM_DATABASE, + entities: ['dist/database/entities/*.entity.js'], + migrations: [ + 'dist/database/migrations/*.js', + 'dist/database/migrations/seeds/*.js', + ], // ssl: { // ca: CA_CERT, // rejectUnauthorized: false, // } -} +}; export const AppDataSource = new DataSource({ - ...typeormConfig -}) \ No newline at end of file + ...typeormConfig, +}); diff --git a/src/candidacy/candidacy.service.spec.ts b/src/modules/candidacy/candidacy.service.spec.ts similarity index 85% rename from src/candidacy/candidacy.service.spec.ts rename to src/modules/candidacy/candidacy.service.spec.ts index 17fdb94..9e39e73 100644 --- a/src/candidacy/candidacy.service.spec.ts +++ b/src/modules/candidacy/candidacy.service.spec.ts @@ -1,5 +1,5 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { CandidacyService } from './candidacy.service'; +import { CandidacyService } from '../modules/candidacy/candidacy.service'; describe('CandidacyService', () => { let service: CandidacyService; diff --git a/src/candidacy/candidacy.service.ts b/src/modules/candidacy/candidacy.service.ts similarity index 61% rename from src/candidacy/candidacy.service.ts rename to src/modules/candidacy/candidacy.service.ts index 8a12b07..2277766 100644 --- a/src/candidacy/candidacy.service.ts +++ b/src/modules/candidacy/candidacy.service.ts @@ -1,19 +1,24 @@ -import { Injectable, BadRequestException, NotFoundException } from '@nestjs/common'; +import { + Injectable, + BadRequestException, + NotFoundException, +} from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { CandidacyRepository } from 'src/modules/candidacy/repository/candidacy.repository'; import { CreateCandidacyDto } from 'src/candidacy/dto/create-candidacy.dto'; -import { CandidacyEntity } from '../database/entities/candidacy.entity'; -import { CandidacyStatus } from '../database/entities/candidancy-status.enum'; +import { CandidacyEntity } from '../../database/entities/candidacy.entity'; +import { CandidacyStatus } from '../../database/entities/candidancy-status.enum'; @Injectable() export class CandidacyService { constructor( @InjectRepository(CandidacyRepository) - private readonly candidacyRepository: CandidacyRepository + private readonly candidacyRepository: CandidacyRepository, ) {} - async create(createCandidacyDto: CreateCandidacyDto): Promise { - + async create( + createCandidacyDto: CreateCandidacyDto, + ): Promise { if (!createCandidacyDto.userId || !createCandidacyDto.jobId) { throw new BadRequestException('userId e jobId são obrigatórios'); } @@ -25,8 +30,10 @@ export class CandidacyService { try { return await this.candidacyRepository.createCandidacy(candidacy); - } catch (error) { - throw new BadRequestException('Erro ao criar a candidatura: ' + error.message); + } catch (error) { + throw new BadRequestException( + 'Erro ao criar a candidatura: ' + error.message, + ); } } @@ -38,16 +45,22 @@ export class CandidacyService { try { const candidacy = await this.candidacyRepository.findAllByUserId(userId); if (!candidacy.length) { - throw new NotFoundException('Nenhuma candidatura encontrada para este usuário'); + throw new NotFoundException( + 'Nenhuma candidatura encontrada para este usuário', + ); } return candidacy; } catch (error) { - throw new BadRequestException('Erro ao buscar candidaturas: ' + error.message); + throw new BadRequestException( + 'Erro ao buscar candidaturas: ' + error.message, + ); } - } - async closeCandidacy(id: string, status: CandidacyStatus.Closed | CandidacyStatus.NoInterest): Promise { + async closeCandidacy( + id: string, + status: CandidacyStatus.Closed | CandidacyStatus.NoInterest, + ): Promise { if (!id) { throw new BadRequestException('ID é obrigatório'); } @@ -63,8 +76,9 @@ export class CandidacyService { } return candidacy; } catch (error) { - throw new BadRequestException('Erro ao encerrar a candidatura: ' + error.message); + throw new BadRequestException( + 'Erro ao encerrar a candidatura: ' + error.message, + ); } } - } diff --git a/src/candidacy/dto/create-candidacy.dto.ts b/src/modules/candidacy/dto/create-candidacy.dto.ts similarity index 100% rename from src/candidacy/dto/create-candidacy.dto.ts rename to src/modules/candidacy/dto/create-candidacy.dto.ts diff --git a/src/modules/candidacy/repository/candidacy.repository.ts b/src/modules/candidacy/repository/candidacy.repository.ts index 4589446..57ae3b6 100644 --- a/src/modules/candidacy/repository/candidacy.repository.ts +++ b/src/modules/candidacy/repository/candidacy.repository.ts @@ -1,4 +1,9 @@ -import { BadRequestException, Injectable, InternalServerErrorException, NotFoundException } from '@nestjs/common'; +import { + BadRequestException, + Injectable, + InternalServerErrorException, + NotFoundException, +} from '@nestjs/common'; import { Repository } from 'typeorm'; import { CandidacyEntity } from '../../../database/entities/candidacy.entity'; import { InjectRepository } from '@nestjs/typeorm'; @@ -15,39 +20,50 @@ export class CandidacyRepository { return this.candidacyRepository.save(candidacy); } - async findAllByUserId(userId: string): Promise { + async findAllByUserId(userId: string): Promise { if (!userId) { throw new BadRequestException('userId é obrigatório'); } try { - const candidacy = await this.candidacyRepository.find({ where: { userId: userId } }); + const candidacy = await this.candidacyRepository.find({ + where: { userId: userId }, + }); if (!candidacy.length) { - throw new NotFoundException('Nenhuma candidatura encontrada para este usuário'); + throw new NotFoundException( + 'Nenhuma candidatura encontrada para este usuário', + ); } return candidacy; } catch (error) { - throw new BadRequestException('Erro ao buscar candidaturas: ' + error.message); + throw new BadRequestException( + 'Erro ao buscar candidaturas: ' + error.message, + ); } } - async updateStatus(id: string, status: CandidacyStatus): Promise { + async updateStatus( + id: string, + status: CandidacyStatus, + ): Promise { try { - const candidacy = await this.candidacyRepository.findOne({ where: { id } }); + const candidacy = await this.candidacyRepository.findOne({ + where: { id }, + }); if (!candidacy) { throw new NotFoundException('Candidatura não encontrada'); } candidacy.status = status; await this.candidacyRepository.save(candidacy); - + return candidacy; } catch (error) { if (error instanceof NotFoundException) { throw error; - } else { - throw new InternalServerErrorException('Erro ao atualizar o status da candidatura: ' + error.message); + throw new InternalServerErrorException( + 'Erro ao atualizar o status da candidatura: ' + error.message, + ); } } } - -} \ No newline at end of file +} From 3c59c9483922e02146a6e3cd0238fb8f067138cd Mon Sep 17 00:00:00 2001 From: Guilherme Sanches Date: Wed, 30 Oct 2024 15:27:48 -0300 Subject: [PATCH 06/11] :sparkles: feat(473): create candidacy module & controller --- src/database/entities/candidacy.entity.ts | 14 ++++--- src/modules/candidacy/candidacy.module.ts | 5 ++- .../controller/candidacy.controller.ts | 37 +++++++++++++++++++ .../candidacy/dto/update-candidacy.dto.ts | 15 ++++++++ .../{ => service}/candidacy.service.spec.ts | 2 +- .../{ => service}/candidacy.service.ts | 10 ++--- 6 files changed, 68 insertions(+), 15 deletions(-) create mode 100644 src/modules/candidacy/controller/candidacy.controller.ts create mode 100644 src/modules/candidacy/dto/update-candidacy.dto.ts rename src/modules/candidacy/{ => service}/candidacy.service.spec.ts (88%) rename src/modules/candidacy/{ => service}/candidacy.service.ts (84%) diff --git a/src/database/entities/candidacy.entity.ts b/src/database/entities/candidacy.entity.ts index c872803..4d60b1c 100644 --- a/src/database/entities/candidacy.entity.ts +++ b/src/database/entities/candidacy.entity.ts @@ -14,26 +14,30 @@ export class CandidacyEntity { @PrimaryGeneratedColumn('uuid') id: string; - @Column('uuid') + @Column('uuid', { name: 'job_id' }) jobId: string; - @Column('uuid') + @Column('uuid', { name: 'user_id' }) userId: string; @Column({ type: 'enum', enum: CandidacyStatus }) status: CandidacyStatus; - @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }) + @Column({ + type: 'timestamp', + name: 'date_candidacy', + default: () => 'CURRENT_TIMESTAMP', + }) dateCandidacy: Date; @Column({ type: 'timestamp', nullable: true }) dateclosing: Date; @ManyToOne(() => UsersEntity) - @JoinColumn({ name: 'userId' }) + @JoinColumn({ name: 'user_id' }) user: UsersEntity; @ManyToOne(() => JobsEntity) - @JoinColumn({ name: 'jobId' }) + @JoinColumn({ name: 'job_id' }) job: JobsEntity; } diff --git a/src/modules/candidacy/candidacy.module.ts b/src/modules/candidacy/candidacy.module.ts index 72e8039..f28c96c 100644 --- a/src/modules/candidacy/candidacy.module.ts +++ b/src/modules/candidacy/candidacy.module.ts @@ -1,12 +1,13 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { Module } from '@nestjs/common'; -import { CandidacyService } from './candidacy.service'; import { CandidacyEntity } from 'src/database/entities/candidacy.entity'; import { CandidacyRepository } from './repository/candidacy.repository'; +import { CandidacyService } from './service/candidacy.service'; +import { CandidacyController } from './controller/candidacy.controller'; @Module({ imports: [TypeOrmModule.forFeature([CandidacyEntity])], - controllers: [], + controllers: [CandidacyController], providers: [CandidacyService, CandidacyRepository], exports: [CandidacyService], }) diff --git a/src/modules/candidacy/controller/candidacy.controller.ts b/src/modules/candidacy/controller/candidacy.controller.ts new file mode 100644 index 0000000..6ee68a8 --- /dev/null +++ b/src/modules/candidacy/controller/candidacy.controller.ts @@ -0,0 +1,37 @@ +import { Body, Controller, Get, Patch, Post, UseGuards } from '@nestjs/common'; +import { CandidacyService } from '../service/candidacy.service'; +import { CreateCandidacyDto } from '../dto/create-candidacy.dto'; +import { LoggedUser } from 'src/modules/auth/decorator/logged-user.decorator'; +import { UsersEntity } from 'src/database/entities/users.entity'; +import { AuthGuard } from '@nestjs/passport'; +import { UpdateCandidacyDto } from '../dto/update-candidacy.dto'; +import { CandidacyStatus } from 'src/database/entities/candidancy-status.enum'; + +@Controller('candidacy') +@UseGuards(AuthGuard('jwt')) +export class CandidacyController { + constructor(private readonly candidacyService: CandidacyService) {} + + @Post() + async createCandidacy(@Body() createCandidacyDTO: CreateCandidacyDto) { + return await this.candidacyService.create(createCandidacyDTO); + } + + @Get() + async getCandidacies(@LoggedUser() user: UsersEntity) { + return await this.candidacyService.getCandidacyByUserId(user.id); + } + + @Patch() + async updateCandidacy(@Body() updateCandidacyDto: UpdateCandidacyDto) { + if (updateCandidacyDto.status === CandidacyStatus.InProgress) { + return { + message: 'Não é possível atualizar para o status "em andamento"', + }; + } + return await this.candidacyService.closeCandidacy( + updateCandidacyDto.id, + updateCandidacyDto.status, + ); + } +} diff --git a/src/modules/candidacy/dto/update-candidacy.dto.ts b/src/modules/candidacy/dto/update-candidacy.dto.ts new file mode 100644 index 0000000..655df61 --- /dev/null +++ b/src/modules/candidacy/dto/update-candidacy.dto.ts @@ -0,0 +1,15 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsEnum, IsNotEmpty, IsUUID } from 'class-validator'; +import { CandidacyStatus } from 'src/database/entities/candidancy-status.enum'; + +export class UpdateCandidacyDto { + @ApiProperty() + @IsUUID() + @IsNotEmpty() + id: string; + + @ApiProperty() + @IsNotEmpty() + @IsEnum(CandidacyStatus) + status: CandidacyStatus; +} diff --git a/src/modules/candidacy/candidacy.service.spec.ts b/src/modules/candidacy/service/candidacy.service.spec.ts similarity index 88% rename from src/modules/candidacy/candidacy.service.spec.ts rename to src/modules/candidacy/service/candidacy.service.spec.ts index 17fdb94..9f9c1e0 100644 --- a/src/modules/candidacy/candidacy.service.spec.ts +++ b/src/modules/candidacy/service/candidacy.service.spec.ts @@ -1,5 +1,5 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { CandidacyService } from './candidacy.service'; +import { CandidacyService } from '../candidacy.service'; describe('CandidacyService', () => { let service: CandidacyService; diff --git a/src/modules/candidacy/candidacy.service.ts b/src/modules/candidacy/service/candidacy.service.ts similarity index 84% rename from src/modules/candidacy/candidacy.service.ts rename to src/modules/candidacy/service/candidacy.service.ts index f4c675d..99bd96b 100644 --- a/src/modules/candidacy/candidacy.service.ts +++ b/src/modules/candidacy/service/candidacy.service.ts @@ -3,10 +3,10 @@ import { BadRequestException, NotFoundException, } from '@nestjs/common'; +import { CandidacyEntity } from 'src/database/entities/candidacy.entity'; +import { CandidacyStatus } from 'src/database/entities/candidancy-status.enum'; import { CandidacyRepository } from 'src/modules/candidacy/repository/candidacy.repository'; -import { CandidacyEntity } from '../../database/entities/candidacy.entity'; -import { CandidacyStatus } from '../../database/entities/candidancy-status.enum'; -import { CreateCandidacyDto } from './dto/create-candidacy.dto'; +import { CreateCandidacyDto } from '../dto/create-candidacy.dto'; @Injectable() export class CandidacyService { @@ -15,10 +15,6 @@ export class CandidacyService { async create( createCandidacyDto: CreateCandidacyDto, ): Promise { - if (!createCandidacyDto.userId || !createCandidacyDto.jobId) { - throw new BadRequestException('userId e jobId são obrigatórios'); - } - const candidacy = new CandidacyEntity(); candidacy.userId = createCandidacyDto.userId; candidacy.jobId = createCandidacyDto.jobId; From 51b69966f7c73d569cbc5678b7a1483d992c34fd Mon Sep 17 00:00:00 2001 From: Guilherme Sanches Date: Mon, 4 Nov 2024 16:38:10 -0300 Subject: [PATCH 07/11] :wrench: fix(candidacy): update candidacy error handling --- .../candidacy/controller/candidacy.controller.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/modules/candidacy/controller/candidacy.controller.ts b/src/modules/candidacy/controller/candidacy.controller.ts index 6ee68a8..685cb93 100644 --- a/src/modules/candidacy/controller/candidacy.controller.ts +++ b/src/modules/candidacy/controller/candidacy.controller.ts @@ -1,4 +1,12 @@ -import { Body, Controller, Get, Patch, Post, UseGuards } from '@nestjs/common'; +import { + BadRequestException, + Body, + Controller, + Get, + Patch, + Post, + UseGuards, +} from '@nestjs/common'; import { CandidacyService } from '../service/candidacy.service'; import { CreateCandidacyDto } from '../dto/create-candidacy.dto'; import { LoggedUser } from 'src/modules/auth/decorator/logged-user.decorator'; @@ -25,9 +33,9 @@ export class CandidacyController { @Patch() async updateCandidacy(@Body() updateCandidacyDto: UpdateCandidacyDto) { if (updateCandidacyDto.status === CandidacyStatus.InProgress) { - return { - message: 'Não é possível atualizar para o status "em andamento"', - }; + throw new BadRequestException( + 'Não é possível atualizar para o status "em andamento"', + ); } return await this.candidacyService.closeCandidacy( updateCandidacyDto.id, From e6adf1151a80fb07e6b3ce1251d275f87f293ec5 Mon Sep 17 00:00:00 2001 From: Guilherme Sanches Date: Fri, 8 Nov 2024 17:00:58 -0300 Subject: [PATCH 08/11] :sparkles: feat(candidacy): migration --- .../migrations/1731094752487-Candidacy.ts | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/database/migrations/1731094752487-Candidacy.ts diff --git a/src/database/migrations/1731094752487-Candidacy.ts b/src/database/migrations/1731094752487-Candidacy.ts new file mode 100644 index 0000000..71a5839 --- /dev/null +++ b/src/database/migrations/1731094752487-Candidacy.ts @@ -0,0 +1,71 @@ +import { + MigrationInterface, + QueryRunner, + Table, + TableForeignKey, +} from 'typeorm'; + +export class Candidacy1731094752487 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.createTable( + new Table({ + name: 'tb_candidacies', + columns: [ + { + name: 'id', + type: 'uuid', + isPrimary: true, + generationStrategy: 'uuid', + default: 'uuid_generate_v4()', + }, + { + name: 'job_id', + type: 'uuid', + }, + { + name: 'user_id', + type: 'uuid', + }, + { + name: 'status', + type: 'enum', + enum: ['em andamento', 'encerrada', 'sem interesse'], + }, + { + name: 'date_candidacy', + type: 'timestamp', + default: 'CURRENT_TIMESTAMP', + }, + { + name: 'dateclosing', + type: 'timestamp', + isNullable: true, + }, + ], + }), + true, + ); + + await queryRunner.createForeignKey( + 'tb_candidacies', + new TableForeignKey({ + columnNames: ['user_id'], + referencedTableName: 'tb_users', + referencedColumnNames: ['id'], + }), + ); + + await queryRunner.createForeignKey( + 'tb_candidacies', + new TableForeignKey({ + columnNames: ['job_id'], + referencedTableName: 'tb_jobs', + referencedColumnNames: ['id'], + }), + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropTable('tb_candidacies'); + } +} From dfe71261354b48d5690556b9a9c81f8c43b9b815 Mon Sep 17 00:00:00 2001 From: Guilherme Sanches Date: Tue, 12 Nov 2024 09:34:46 -0300 Subject: [PATCH 09/11] fix(candidacy): add swagger decorators & change candidacy column name --- src/database/entities/candidacy.entity.ts | 6 ++--- .../migrations/1731094752487-Candidacy.ts | 7 ++++++ src/main.ts | 20 ++++++++++------- .../controller/candidacy.controller.ts | 8 +++++++ .../candidacy/dto/create-candidacy.dto.ts | 3 +++ .../candidacy/dto/update-candidacy.dto.ts | 4 ++-- .../candidacy/create-candidacy.swagger.ts | 22 +++++++++++++++++++ .../candidacy/get-candidacies.swagger.ts | 22 +++++++++++++++++++ .../candidacy/update-candidacy.swagger.ts | 22 +++++++++++++++++++ 9 files changed, 101 insertions(+), 13 deletions(-) create mode 100644 src/shared/Swagger/decorators/candidacy/create-candidacy.swagger.ts create mode 100644 src/shared/Swagger/decorators/candidacy/get-candidacies.swagger.ts create mode 100644 src/shared/Swagger/decorators/candidacy/update-candidacy.swagger.ts diff --git a/src/database/entities/candidacy.entity.ts b/src/database/entities/candidacy.entity.ts index 4d60b1c..4ebcaaf 100644 --- a/src/database/entities/candidacy.entity.ts +++ b/src/database/entities/candidacy.entity.ts @@ -24,14 +24,14 @@ export class CandidacyEntity { status: CandidacyStatus; @Column({ - type: 'timestamp', + type: 'date', name: 'date_candidacy', default: () => 'CURRENT_TIMESTAMP', }) dateCandidacy: Date; - @Column({ type: 'timestamp', nullable: true }) - dateclosing: Date; + @Column({ name: 'date_closing', type: 'timestamp', nullable: true }) + dateClosing: Date; @ManyToOne(() => UsersEntity) @JoinColumn({ name: 'user_id' }) diff --git a/src/database/migrations/1731094752487-Candidacy.ts b/src/database/migrations/1731094752487-Candidacy.ts index 71a5839..400f9b6 100644 --- a/src/database/migrations/1731094752487-Candidacy.ts +++ b/src/database/migrations/1731094752487-Candidacy.ts @@ -66,6 +66,13 @@ export class Candidacy1731094752487 implements MigrationInterface { } public async down(queryRunner: QueryRunner): Promise { + const table = await queryRunner.getTable('tb_candidacies'); + const foreignKeys = table.foreignKeys.filter( + (fk) => + fk.columnNames.indexOf('user_id') !== -1 || + fk.columnNames.indexOf('job_id') !== -1, + ); + await queryRunner.dropForeignKeys('tb_candidacies', foreignKeys); await queryRunner.dropTable('tb_candidacies'); } } diff --git a/src/main.ts b/src/main.ts index a9d739c..2bbe8a2 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,5 @@ -import { config } from "dotenv"; -config() +import { config } from 'dotenv'; +config(); import { ValidationPipe } from '@nestjs/common'; import { NestFactory } from '@nestjs/core'; import { NestExpressApplication } from '@nestjs/platform-express'; @@ -11,16 +11,20 @@ async function bootstrap() { cors: true, }); - app.useGlobalPipes(new ValidationPipe({ - whitelist: true, - transform: true - })); + app.useGlobalPipes( + new ValidationPipe({ + whitelist: true, + transform: true, + }), + ); const config = new DocumentBuilder() .setTitle('Vagas-Backend') .setDescription('App for Vagas-Backend.') .setVersion('1.1.1') .addBearerAuth() + .addTag('Alerts') + .addTag('Candidacy') .addTag('Upload') .addTag('Status') .addTag('Auth') @@ -29,10 +33,10 @@ async function bootstrap() { .build(); const document = SwaggerModule.createDocument(app, config); - + if (process.env.NODE_ENV == 'development') { SwaggerModule.setup('api', app, document); - } + } await app.listen(process.env.PORT || 3000); console.info(`🚀🚀 App listening on port ${process.env.PORT || 3000} 🚀🚀`); diff --git a/src/modules/candidacy/controller/candidacy.controller.ts b/src/modules/candidacy/controller/candidacy.controller.ts index 685cb93..79f5831 100644 --- a/src/modules/candidacy/controller/candidacy.controller.ts +++ b/src/modules/candidacy/controller/candidacy.controller.ts @@ -14,23 +14,31 @@ import { UsersEntity } from 'src/database/entities/users.entity'; import { AuthGuard } from '@nestjs/passport'; import { UpdateCandidacyDto } from '../dto/update-candidacy.dto'; import { CandidacyStatus } from 'src/database/entities/candidancy-status.enum'; +import { ApiTags } from '@nestjs/swagger'; +import { CreateCandidacySwagger } from 'src/shared/Swagger/decorators/candidacy/create-candidacy.swagger'; +import { GetCandidaciesSwagger } from 'src/shared/Swagger/decorators/candidacy/get-candidacies.swagger'; +import { UpdateCandidacySwagger } from 'src/shared/Swagger/decorators/candidacy/update-candidacy.swagger'; +@ApiTags('Candidacy') @Controller('candidacy') @UseGuards(AuthGuard('jwt')) export class CandidacyController { constructor(private readonly candidacyService: CandidacyService) {} @Post() + @CreateCandidacySwagger() async createCandidacy(@Body() createCandidacyDTO: CreateCandidacyDto) { return await this.candidacyService.create(createCandidacyDTO); } @Get() + @GetCandidaciesSwagger() async getCandidacies(@LoggedUser() user: UsersEntity) { return await this.candidacyService.getCandidacyByUserId(user.id); } @Patch() + @UpdateCandidacySwagger() async updateCandidacy(@Body() updateCandidacyDto: UpdateCandidacyDto) { if (updateCandidacyDto.status === CandidacyStatus.InProgress) { throw new BadRequestException( diff --git a/src/modules/candidacy/dto/create-candidacy.dto.ts b/src/modules/candidacy/dto/create-candidacy.dto.ts index 1a233b9..d467867 100644 --- a/src/modules/candidacy/dto/create-candidacy.dto.ts +++ b/src/modules/candidacy/dto/create-candidacy.dto.ts @@ -1,11 +1,14 @@ +import { ApiProperty } from '@nestjs/swagger'; import { IsUUID, IsNotEmpty } from 'class-validator'; export class CreateCandidacyDto { @IsUUID() @IsNotEmpty() + @ApiProperty({ type: 'string', format: 'uuid' }) userId: string; @IsUUID() @IsNotEmpty() + @ApiProperty({ type: 'string', format: 'uuid' }) jobId: string; } diff --git a/src/modules/candidacy/dto/update-candidacy.dto.ts b/src/modules/candidacy/dto/update-candidacy.dto.ts index 655df61..91ef0c9 100644 --- a/src/modules/candidacy/dto/update-candidacy.dto.ts +++ b/src/modules/candidacy/dto/update-candidacy.dto.ts @@ -3,12 +3,12 @@ import { IsEnum, IsNotEmpty, IsUUID } from 'class-validator'; import { CandidacyStatus } from 'src/database/entities/candidancy-status.enum'; export class UpdateCandidacyDto { - @ApiProperty() + @ApiProperty({ type: 'string', format: 'uuid' }) @IsUUID() @IsNotEmpty() id: string; - @ApiProperty() + @ApiProperty({ enum: CandidacyStatus }) @IsNotEmpty() @IsEnum(CandidacyStatus) status: CandidacyStatus; diff --git a/src/shared/Swagger/decorators/candidacy/create-candidacy.swagger.ts b/src/shared/Swagger/decorators/candidacy/create-candidacy.swagger.ts new file mode 100644 index 0000000..f12a887 --- /dev/null +++ b/src/shared/Swagger/decorators/candidacy/create-candidacy.swagger.ts @@ -0,0 +1,22 @@ +import { applyDecorators, HttpStatus } from '@nestjs/common'; +import { ApiOperation, ApiResponse } from '@nestjs/swagger'; +import { BadRequestSwagger } from '../../bad-request.swagger'; +import { CandidacyEntity } from 'src/database/entities/candidacy.entity'; + +export function CreateCandidacySwagger() { + return applyDecorators( + ApiResponse({ + status: HttpStatus.CREATED, + description: 'Exemplo do retorno de sucesso da rota', + type: CandidacyEntity, + }), + ApiResponse({ + status: HttpStatus.BAD_REQUEST, + description: 'Modelo de erro', + type: BadRequestSwagger, + }), + ApiOperation({ + summary: 'Rota para registrar uma candidatura', + }), + ); +} diff --git a/src/shared/Swagger/decorators/candidacy/get-candidacies.swagger.ts b/src/shared/Swagger/decorators/candidacy/get-candidacies.swagger.ts new file mode 100644 index 0000000..7c00d31 --- /dev/null +++ b/src/shared/Swagger/decorators/candidacy/get-candidacies.swagger.ts @@ -0,0 +1,22 @@ +import { applyDecorators, HttpStatus } from '@nestjs/common'; +import { ApiOperation, ApiResponse } from '@nestjs/swagger'; +import { BadRequestSwagger } from '../../bad-request.swagger'; +import { CandidacyEntity } from 'src/database/entities/candidacy.entity'; + +export function GetCandidaciesSwagger() { + return applyDecorators( + ApiResponse({ + status: HttpStatus.OK, + description: 'Exemplo do retorno de sucesso da rota', + type: [CandidacyEntity], + }), + ApiResponse({ + status: HttpStatus.BAD_REQUEST, + description: 'Modelo de erro', + type: BadRequestSwagger, + }), + ApiOperation({ + summary: 'Rota para obter todas as candidaturas de um usuário', + }), + ); +} diff --git a/src/shared/Swagger/decorators/candidacy/update-candidacy.swagger.ts b/src/shared/Swagger/decorators/candidacy/update-candidacy.swagger.ts new file mode 100644 index 0000000..09c56fd --- /dev/null +++ b/src/shared/Swagger/decorators/candidacy/update-candidacy.swagger.ts @@ -0,0 +1,22 @@ +import { applyDecorators, HttpStatus } from '@nestjs/common'; +import { ApiOperation, ApiResponse } from '@nestjs/swagger'; +import { BadRequestSwagger } from '../../bad-request.swagger'; +import { CandidacyEntity } from 'src/database/entities/candidacy.entity'; + +export function UpdateCandidacySwagger() { + return applyDecorators( + ApiResponse({ + status: HttpStatus.CREATED, + description: 'Exemplo do retorno de sucesso da rota', + type: CandidacyEntity, + }), + ApiResponse({ + status: HttpStatus.BAD_REQUEST, + description: 'Modelo de erro', + type: BadRequestSwagger, + }), + ApiOperation({ + summary: 'Rota para atualizar uma candidatura', + }), + ); +} From afd61f31a6390f111ea3a20d8fff2e3ce5a3d1e6 Mon Sep 17 00:00:00 2001 From: Guilherme Sanches Date: Thu, 14 Nov 2024 14:11:02 -0300 Subject: [PATCH 10/11] fix(candidacies): entity column name --- src/database/migrations/1731094752487-Candidacy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/database/migrations/1731094752487-Candidacy.ts b/src/database/migrations/1731094752487-Candidacy.ts index 400f9b6..9e0c8be 100644 --- a/src/database/migrations/1731094752487-Candidacy.ts +++ b/src/database/migrations/1731094752487-Candidacy.ts @@ -37,7 +37,7 @@ export class Candidacy1731094752487 implements MigrationInterface { default: 'CURRENT_TIMESTAMP', }, { - name: 'dateclosing', + name: 'date_closing', type: 'timestamp', isNullable: true, }, From ccd58c14a0e2280f1329a7b97feefe03df924674 Mon Sep 17 00:00:00 2001 From: Mikael Melo <85139137+MikaelMelo1@users.noreply.github.com> Date: Thu, 5 Dec 2024 15:23:55 -0300 Subject: [PATCH 11/11] Update data-source.ts --- src/database/data-source.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/database/data-source.ts b/src/database/data-source.ts index c84b9f4..642887c 100644 --- a/src/database/data-source.ts +++ b/src/database/data-source.ts @@ -1,9 +1,9 @@ -import { config } from 'dotenv'; -config(); +import 'dotenv/config' import { DataSource, DataSourceOptions } from 'typeorm'; import 'reflect-metadata'; const { + NODE_ENV, TYPEORM_HOST, TYPEORM_PORT, TYPEORM_PASSWORD, @@ -15,7 +15,7 @@ const { export const typeormConfig: DataSourceOptions = { type: 'postgres', host: TYPEORM_HOST, - port: +TYPEORM_PORT, + port: parseInt(TYPEORM_PORT), username: TYPEORM_USERNAME, password: TYPEORM_PASSWORD, database: TYPEORM_DATABASE, @@ -24,10 +24,13 @@ export const typeormConfig: DataSourceOptions = { 'dist/database/migrations/*.js', 'dist/database/migrations/seeds/*.js', ], - // ssl: { - // ca: CA_CERT, - // rejectUnauthorized: false, - // } + ssl: + NODE_ENV == 'production' + ? { + ca: CA_CERT, + rejectUnauthorized: false, + } + : undefined, }; export const AppDataSource = new DataSource({