diff --git a/server/prisma/migrations/20240731003618_add_aluno_atividade_relation_table/migration.sql b/server/prisma/migrations/20240731003618_add_aluno_atividade_relation_table/migration.sql new file mode 100644 index 0000000..57b8fc0 --- /dev/null +++ b/server/prisma/migrations/20240731003618_add_aluno_atividade_relation_table/migration.sql @@ -0,0 +1,14 @@ +-- CreateTable +CREATE TABLE `alunos_atividades` ( + `alunoId` VARCHAR(191) NOT NULL, + `atividadeId` VARCHAR(191) NOT NULL, + `mencao` ENUM('I', 'R', 'B', 'MB') NOT NULL, + + PRIMARY KEY (`alunoId`, `atividadeId`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- AddForeignKey +ALTER TABLE `alunos_atividades` ADD CONSTRAINT `alunos_atividades_alunoId_fkey` FOREIGN KEY (`alunoId`) REFERENCES `alunos`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `alunos_atividades` ADD CONSTRAINT `alunos_atividades_atividadeId_fkey` FOREIGN KEY (`atividadeId`) REFERENCES `atividades`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/server/prisma/schema.prisma b/server/prisma/schema.prisma index 1e7492f..fbbc92a 100644 --- a/server/prisma/schema.prisma +++ b/server/prisma/schema.prisma @@ -24,6 +24,7 @@ model Aluno { tentativasRestantes Int @default(5) validated Boolean @default(false) turmas AlunoTurma[] + atividades AlunoAtividade[] cursosExtracurriculares Extracurricular[] vinculosAluno Vinculo[] @relation("AlunoVinculo") vinculoComoAluno Vinculo[] @relation("VinculoComAluno") @@ -133,6 +134,24 @@ model AlunoTurma { @@map("alunos_turmas") } +model AlunoAtividade { + alunoId String @default(uuid()) + atividadeId String @default(uuid()) + mencao Mencao + aluno Aluno @relation(fields: [alunoId], references: [id]) + atividade Atividade @relation(fields: [atividadeId], references: [id]) + + @@id([alunoId, atividadeId]) + @@map("alunos_atividades") +} + +enum Mencao { + I + R + B + MB +} + model Extracurricular { extracurricularId String @id @default(uuid()) alunoId String @@ -234,9 +253,10 @@ model Atividade { id String @id @default(uuid()) title String descricao String @db.VarChar(1000) - professor Professor @relation(fields: [professorId], references: [id]) professorId String imagem String? + alunos AlunoAtividade[] + professor Professor @relation(fields: [professorId], references: [id]) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt diff --git a/server/src/modules/controllers/professorControllers.ts b/server/src/modules/controllers/professorControllers.ts index 73c2ef8..b37f99b 100644 --- a/server/src/modules/controllers/professorControllers.ts +++ b/server/src/modules/controllers/professorControllers.ts @@ -5,6 +5,8 @@ import { ValidateProfessorUseCase } from "../services/professor/ValidateProfesso import { ValidateRecoveryUseCase } from "../services/professor/ValidateRecoveryUseCase"; import { RecoveryProfessorUseCase } from "../services/professor/RecoveryProfessorUseCase"; import { RefreshTokenUseCase } from "../services/professor/RefreshTokenUseCase"; +import { CreateActivityUseCase } from "../services/professor/CreateActivityUseCase"; +import { RelateAlunoAtividadeUseCase } from "../services/professor/LinkAlunoActivityUseCase"; export class InitProfessorController { async handle(req: Request, res: Response) { @@ -76,4 +78,31 @@ export class RefreshTokenController { return res.status(201).json(result); } -} \ No newline at end of file +} + +export class CreateActivityController { + async handle(req: Request, res: Response) { + const professorId = req.body.entidade.id; + const {title, descricao} = req.body; + const imagem = req.file as Express.Multer.File; + + const createActivityUseCase = new CreateActivityUseCase(); + + const result = await createActivityUseCase.execute({title, descricao, professorId, imagem}); + + return res.status(201).json(result); + } +} + +export class RelateAlunoAtividadeController { + async handle(req: Request, res: Response) { + const professorId = req.body.entidade.id; + const {alunoId, atividadeId, mencao} = req.body; + + const relateAlunoAtividadeUseCase = new RelateAlunoAtividadeUseCase(); + + const result = await relateAlunoAtividadeUseCase.execute({alunoId, atividadeId, professorId, mencao}); + + return res.status(201).json(result); + } +} diff --git a/server/src/modules/interfaces/professorDTOs.ts b/server/src/modules/interfaces/professorDTOs.ts index 9680d8b..8147743 100644 --- a/server/src/modules/interfaces/professorDTOs.ts +++ b/server/src/modules/interfaces/professorDTOs.ts @@ -22,4 +22,25 @@ export interface ValidateRecoveryDTO { email: string, recoveryPass: string, newPass: string +} + +export interface CreateActivityDTO { + title: string; + descricao: string; + professorId: string; + imagem: Express.Multer.File; +} + +export interface RelateAlunoAtividadeDTO { + alunoId: string; + atividadeId: string; + professorId: string; + mencao: Mencao; +} + +export enum Mencao{ + I = "I", + R = "R", + B = "B", + MB = "MB" } \ No newline at end of file diff --git a/server/src/modules/services/professor/CreateActivityUseCase.ts b/server/src/modules/services/professor/CreateActivityUseCase.ts new file mode 100644 index 0000000..f32c007 --- /dev/null +++ b/server/src/modules/services/professor/CreateActivityUseCase.ts @@ -0,0 +1,45 @@ +import { Professor } from "@prisma/client"; +import { prisma } from "../../../prisma/client"; +import { AppError } from "../../../errors/error"; +import { CreateActivityDTO } from "../../interfaces/professorDTOs"; +import { clearUploads } from "../shared/helpers/helpers"; +import { uploadToMinio } from "../../../minioService"; + + +export class CreateActivityUseCase { + async execute({ title, descricao, professorId, imagem }: CreateActivityDTO) { + if (!title || !descricao || !professorId || !imagem) { + throw new AppError("Parâmetros insuficientes ou inválidos."); + } + + const professor = await prisma.professor.findUnique({ + where: { id: professorId } + }); + + if (!professor) { + throw new Error('Professor não encontrado'); + } + + const bucketName = 'boot'; + const objectName = `atividades/${professor.email}/title`; + + try { + const filePath = imagem.path; + await uploadToMinio(bucketName, objectName, filePath); + + clearUploads(); + await prisma.atividade.create({ + data: { + title, + descricao, + professorId, + imagem: objectName + } + }); + + return "Atividade criada com sucesso1"; + } catch (error) { + throw new AppError(`Error uploading image: ${error}`); + } + } +} \ No newline at end of file diff --git a/server/src/modules/services/professor/LinkAlunoActivityUseCase.ts b/server/src/modules/services/professor/LinkAlunoActivityUseCase.ts new file mode 100644 index 0000000..b794fdf --- /dev/null +++ b/server/src/modules/services/professor/LinkAlunoActivityUseCase.ts @@ -0,0 +1,53 @@ +import { prisma } from "../../../prisma/client"; +import { AppError } from "../../../errors/error"; +import { RelateAlunoAtividadeDTO } from "../../interfaces/professorDTOs"; + +export class RelateAlunoAtividadeUseCase { + async execute({ alunoId, atividadeId, professorId, mencao }: RelateAlunoAtividadeDTO) { + if (!alunoId || !atividadeId || !professorId || !mencao) { + throw new AppError("Parâmetros insuficientes ou inválidos."); + } + + const atividade = await prisma.atividade.findUnique({ + where: { id: atividadeId } + }); + + if (!atividade) { + throw new AppError("Atividade não encontrada."); + } + + const professor = await prisma.professor.findUnique({ + where: { id: professorId } + }); + + if (!professor) { + throw new AppError("Professor não encontrado."); + } + + if(atividade.professorId != professorId){ + throw new AppError("Professor inválido."); + } + + const aluno = await prisma.aluno.findUnique({ + where: { id: alunoId } + }); + + if (!aluno) { + throw new AppError("Aluno não encontrado."); + } + + try { + await prisma.alunoAtividade.create({ + data: { + alunoId, + atividadeId, + mencao + } + }); + + return "Aluno relacionado à atividade com sucesso."; + } catch (error) { + throw new AppError(`Erro ao relacionar aluno à atividade: ${error}`); + } + } +} diff --git a/server/src/router/routes/imports/professor.ts b/server/src/router/routes/imports/professor.ts index a217abd..0fce0c4 100644 --- a/server/src/router/routes/imports/professor.ts +++ b/server/src/router/routes/imports/professor.ts @@ -13,7 +13,9 @@ import { InitProfessorController, RecoveryProfessorController, ValidateRecoveryController, - RefreshTokenController + RefreshTokenController, + CreateActivityController, + RelateAlunoAtividadeController } from "../../../modules/controllers/professorControllers"; export const createControllers = () => ({ @@ -29,5 +31,7 @@ export const createControllers = () => ({ getVinculosController: new GetVinculosController(), getUnlinkedsController: new GetUnlinkedsController(), refreshTokenController: new RefreshTokenController(), - createMessageController: new CreateMessageController() + createMessageController: new CreateMessageController(), + createActivityController: new CreateActivityController(), + relateAlunoAtividadeController :new RelateAlunoAtividadeController(), }); \ No newline at end of file diff --git a/server/src/router/routes/professor.routes.ts b/server/src/router/routes/professor.routes.ts index 3e3250c..376eeae 100644 --- a/server/src/router/routes/professor.routes.ts +++ b/server/src/router/routes/professor.routes.ts @@ -19,6 +19,8 @@ professorRoutes.post("/link/accept", controllers.acceptVinculoController.handle) professorRoutes.post("/link/reject", controllers.ignoreVinculoController.handle); professorRoutes.post("/link/delete", controllers.deleteVinculoController.handle); professorRoutes.post("/message/send", controllers.createMessageController.handle); +professorRoutes.post("/activity/create", controllers.createActivityController.handle); +professorRoutes.post("/activity/relate", controllers.recoveryProfessorController.handle); professorRoutes.get("/auth", (req, res) => { res.status(200).send("Professor autenticado com sucesso.");