Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(candidacy): candidacy entity, service & controller #185

Merged
merged 13 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { PassportModule } from '@nestjs/passport';
import { UserRepository } from './modules/user/repository/user.repository';
import { UsersEntity } from './database/entities/users.entity';
import { AlertsModule } from './modules/alert/alerts.module';

import { CandidacyModule } from './modules/candidacy/candidacy.module';

@Module({
imports: [
Expand All @@ -44,11 +44,9 @@ import { AlertsModule } from './modules/alert/alerts.module';
ApplicationsModule,
TypeOrmModule.forFeature([UsersEntity]),
AlertsModule,
CandidacyModule,
],
controllers: [AppController],
providers: [
AppService,
UserRepository
],
providers: [AppService, UserRepository],
})
export class AppModule {}
8 changes: 4 additions & 4 deletions src/database/data-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ export const typeormConfig: DataSourceOptions = {
'dist/database/migrations/*.js',
'dist/database/migrations/seeds/*.js',
],
ssl: {
ca: CA_CERT,
rejectUnauthorized: false,
},
// ssl: {
// ca: CA_CERT,
// rejectUnauthorized: false,
// }
};

export const AppDataSource = new DataSource({
Expand Down
43 changes: 43 additions & 0 deletions src/database/entities/candidacy.entity.ts
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Se não precisar registar hora pode deixar apenas o date, mas se precisar, mantem como está. na coluna do timestamp.

Vamos manter com camelCase para ficar show.

Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import {
Column,
Entity,
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 {
@PrimaryGeneratedColumn('uuid')
id: string;

@Column('uuid', { name: 'job_id' })
jobId: string;

@Column('uuid', { name: 'user_id' })
userId: string;

@Column({ type: 'enum', enum: CandidacyStatus })
status: CandidacyStatus;

@Column({
type: 'timestamp',
name: 'date_candidacy',
default: () => 'CURRENT_TIMESTAMP',
})
dateCandidacy: Date;

@Column({ type: 'timestamp', nullable: true })
dateclosing: Date;

@ManyToOne(() => UsersEntity)
@JoinColumn({ name: 'user_id' })
user: UsersEntity;

@ManyToOne(() => JobsEntity)
@JoinColumn({ name: 'job_id' })
job: JobsEntity;
}
5 changes: 5 additions & 0 deletions src/database/entities/candidancy-status.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export enum CandidacyStatus {
InProgress = 'em andamento',
Closed = 'encerrada',
NoInterest = 'sem interesse',
}
4 changes: 4 additions & 0 deletions src/database/entities/users.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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;

Expand Down
71 changes: 71 additions & 0 deletions src/database/migrations/1731094752487-Candidacy.ts
GuiTDS marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import {
MigrationInterface,
QueryRunner,
Table,
TableForeignKey,
} from 'typeorm';

export class Candidacy1731094752487 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
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<void> {
await queryRunner.dropTable('tb_candidacies');
}
}
14 changes: 14 additions & 0 deletions src/modules/candidacy/candidacy.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { TypeOrmModule } from '@nestjs/typeorm';
import { Module } from '@nestjs/common';
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: [CandidacyController],
providers: [CandidacyService, CandidacyRepository],
exports: [CandidacyService],
})
export class CandidacyModule {}
45 changes: 45 additions & 0 deletions src/modules/candidacy/controller/candidacy.controller.ts
GuiTDS marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
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';
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) {
throw new BadRequestException(
'Não é possível atualizar para o status "em andamento"',
);
}
return await this.candidacyService.closeCandidacy(
updateCandidacyDto.id,
updateCandidacyDto.status,
);
}
}
11 changes: 11 additions & 0 deletions src/modules/candidacy/dto/create-candidacy.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { IsUUID, IsNotEmpty } from 'class-validator';

export class CreateCandidacyDto {
@IsUUID()
@IsNotEmpty()
userId: string;

@IsUUID()
@IsNotEmpty()
jobId: string;
}
15 changes: 15 additions & 0 deletions src/modules/candidacy/dto/update-candidacy.dto.ts
Original file line number Diff line number Diff line change
@@ -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;
}
69 changes: 69 additions & 0 deletions src/modules/candidacy/repository/candidacy.repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
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 {
constructor(
@InjectRepository(CandidacyEntity)
private candidacyRepository: Repository<CandidacyEntity>,
) {}

async createCandidacy(candidacy: CandidacyEntity): Promise<CandidacyEntity> {
return this.candidacyRepository.save(candidacy);
}

async findAllByUserId(userId: string): Promise<CandidacyEntity[]> {
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: CandidacyStatus,
): Promise<CandidacyEntity | null> {
try {
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,
);
}
}
}
}
18 changes: 18 additions & 0 deletions src/modules/candidacy/service/candidacy.service.spec.ts
Original file line number Diff line number Diff line change
@@ -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>(CandidacyService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});
});
Loading
Loading