diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3343c96 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +node_modules +.env +package-lock.json +build \ No newline at end of file diff --git a/README.md b/README.md index 978a24d..1138f89 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,65 @@ -## LabenuSystem: - -Você estuda na Labenu_ há tanto tempo que já parecem anos, não é? Então, hoje, vamos pedir para criar um sistema que represente o básico da nossa organização. - -Ele deve possuir, ao menos, as 3 entidades importantes: - -1. Estudantes - - Representa estudantes da nossa instituição. Eles devem possuir: id, nome, email, data de nascimento e os principais hobbies dele. - -2. Docente - - Representa docentes da nossa instituição. Eles devem possuir: id, nome, email, data de nascimento e todas as especialidades dele. Há 7 especialidades: React, Redux, CSS, Testes, Typescript, Programação Orientada a Objetos e Backend - -3. Turma - - Toda turma é composta das seguintes características: id, nome, data de início, data de término, lista de professores responsáveis, uma lista de alunos e módulo atual em que a turma está. - - O módulo pode assumir os valores de 1 a 7 ou `undefined`, indicando que as aulas dessa turma ainda não começaram. Para esse exercício, vamos considerar que existam dois tipos de turma: integral ou noturna. Há uma restrição para o nome das turmas noturnas: tem que terminar com `-na-night`. - -As funcionalidades básicas são: - -→ Criar estudante; - -→ Criar docente; - -→ Criar turma; - -→ Adicionar estudante na turma; - -→ Adicionar docente na turma; - -→ Pegar a idade de algum estudante a partir do id +# LabenuSystem + +## :memo: Funcionalidades +* Criar estudante +* Criar docente +* Criar turma +* Adicionar estudante a turma +* Adicionar docente a turma +* Pegar a idade de algum estudante a partir do ID +* Exibir estudantes de uma turma +* Exibir docentes de uma turma +* Exibir estudantes que possuam o mesmo hobby +* Remover estudante de uma turma +* Remover estudante do curso +* Remover docente de uma turma +* Mudar turma de módulo + +## 💻 Documentação +Teste as rotas com a documentação, basta importar ela para seu postman. + +[Postman - LabenuSystem](https://documenter.getpostman.com/view/14146800/TzCQb737) + +## ✨ Tecnologias +Esse projeto foi desenvolvido com as seguintes tecnologias: + +* Node +* Express +* Typescript +* Cors +* Knex +* MySQL +* Dotenv + +## 🚀 Como executar +* Clone o repositório: + +https://github.com/future4code/epps-labenu-system8 + +* Instale as dependências com +``` +npm install + ``` +* Crie um arquivo .env +``` +touch .env + ``` +* Preencha o arquivo .env +``` +DB_HOST = Coloque aqui seu endereço do banco de dados +DB_USER = Coloque aqui seu usuário +DB_PASSWORD = Coloque aqui sua senha +DB_NAME = Coloque aqui o nome do banco de dados + ``` +* Crie as tabelas com + ``` +npm run tables + ``` +* Inicie o servidor com + ``` +npm run dev + ``` + + ## Desenvolvido por: + - Bruno Vallim + - [Daniel Ribeiro](https://www.linkedin.com/in/daniel-ribeiro-59b739140/) diff --git a/package.json b/package.json new file mode 100644 index 0000000..5fd5617 --- /dev/null +++ b/package.json @@ -0,0 +1,36 @@ +{ + "name": "epps-labenu-system8", + "version": "1.0.0", + "description": "Você estuda na Labenu_ há tanto tempo que já parecem anos, não é? Então, hoje, vamos pedir para criar um sistema que represente o básico da nossa organização.", + "main": "index.js", + "scripts": { + "tables": "clear && tsc && node ./build/createTables/createTables.js", + "dev": "clear && ts-node-dev ./src/index.ts", + "start": "clear && tsc && node ./build/index.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/future4code/epps-labenu-system8.git" + }, + "keywords": [], + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/future4code/epps-labenu-system8/issues" + }, + "homepage": "https://github.com/future4code/epps-labenu-system8#readme", + "devDependencies": { + "@types/cors": "^2.8.10", + "@types/express": "^4.17.11", + "cors": "^2.8.5", + "express": "^4.17.1", + "ts-node-dev": "^1.1.6", + "typescript": "^4.2.3" + }, + "dependencies": { + "@types/knex": "^0.16.1", + "dotenv": "^8.2.0", + "knex": "^0.95.4", + "mysql": "^2.18.1" + } +} diff --git a/request.rest b/request.rest new file mode 100644 index 0000000..8291cc8 --- /dev/null +++ b/request.rest @@ -0,0 +1,66 @@ +### +POST http://localhost:3003/student/create +Content-Type: application/json + +{ + "name":"Daniel", + "email":"daniel@gmail.com", + "birthdate":"1993-05-19", + "hobbies": "Patinar." +} + +#### +POST http://localhost:3003/class/create +Content-Type: application/json + +{ + "name":"Turma Neil-na-night.", + "start_date":"2022-03-01", + "end_date":"2022-09-01", + "type_class": "Noturna" +} + +### +POST http://localhost:3003/teacher/create +Content-Type: application/json + +{ + "name":"Neil", + "email":"Neil@gmail.com", + "birthdate":"1970-04-15", + "speciality": "Redux" +} + +### +PUT http://localhost:3003/update/class +Content-Type: application/json + +{ + "tableName": "Students", + "peapleClassId": "1617566013084", + "peapleNewClassId": "1617619560126" +} + +### +GET http://localhost:3003/students/1617547014022 + +### +GET http://localhost:3003/teachers/1617547014022 + +### +GET http://localhost:3003/search/age?id=1617546212494&&tableName=teachers + +### +GET http://localhost:3003/students/hobbies + +### +PUT http://localhost:3003/class/change-module?id=1617547014022&&module=1 + +### +DELETE http://localhost:3003/student/remove-class/1617566013084 + +### +DELETE http://localhost:3003/teacher/remove-class/:id + +### +DELETE http://localhost:3003/student/remove/1617312546437 \ No newline at end of file diff --git a/src/GlobalFunctions/aboutDate/addZero.ts b/src/GlobalFunctions/aboutDate/addZero.ts new file mode 100644 index 0000000..73c13ca --- /dev/null +++ b/src/GlobalFunctions/aboutDate/addZero.ts @@ -0,0 +1,8 @@ +// adiciona 0 nos dates e nos months quando eles estão na casa de unidade. + +export const addZero = (numero: number) => { + if (numero <= 9) + return "0" + numero; + else + return numero; +} diff --git a/src/GlobalFunctions/aboutDate/convertDate.ts b/src/GlobalFunctions/aboutDate/convertDate.ts new file mode 100644 index 0000000..e170edd --- /dev/null +++ b/src/GlobalFunctions/aboutDate/convertDate.ts @@ -0,0 +1,11 @@ +import { addZero } from './addZero' + +// formata data para dd/mm/yyyy + +export const convertDate = (valueDate: string) => { + let data = new Date(valueDate.toString()); + let dataFormatada = (addZero((data.getDate()))) + "/" + + (addZero((data.getMonth() + 1))) + "/" + + data.getFullYear(); + return dataFormatada +} \ No newline at end of file diff --git a/src/GlobalFunctions/aboutDate/convertDateToTimestamp.ts b/src/GlobalFunctions/aboutDate/convertDateToTimestamp.ts new file mode 100644 index 0000000..c301831 --- /dev/null +++ b/src/GlobalFunctions/aboutDate/convertDateToTimestamp.ts @@ -0,0 +1,9 @@ +// converte datas para timestamp + +export const convertDateToTimestamp = (date: string) => { + const myDate = date + const newMyDate = myDate.split("/") + const newDate = new Date(Number(newMyDate[2]), (Number(newMyDate[1]) -1), Number(newMyDate[0])) + + return newDate.getTime() +} \ No newline at end of file diff --git a/src/GlobalFunctions/aboutDate/currentDate.ts b/src/GlobalFunctions/aboutDate/currentDate.ts new file mode 100644 index 0000000..3d07bae --- /dev/null +++ b/src/GlobalFunctions/aboutDate/currentDate.ts @@ -0,0 +1,9 @@ +import {convertDate} from './convertDate' + +// pegando a data atual + +export const currentDate = () =>{ + const date = new Date + const newDate = convertDate(String(date)) + return newDate +} \ No newline at end of file diff --git a/src/GlobalFunctions/aboutDate/getAge.ts b/src/GlobalFunctions/aboutDate/getAge.ts new file mode 100644 index 0000000..89c8a36 --- /dev/null +++ b/src/GlobalFunctions/aboutDate/getAge.ts @@ -0,0 +1,28 @@ +import { connection } from '../../connection' +import { convertDate } from './convertDate' +import { convertDateToTimestamp } from './convertDateToTimestamp' +import { currentDate } from './currentDate' +import { timestampToYear } from './timestampToYear' + +// pegando idade da pessoa + +export const getAge = async (idUser: string, tableName: string) => { + const birthdate = await connection.raw(` + SELECT birthdate + FROM ${tableName} + WHERE id = "${idUser}" + `) + + const dateNow = currentDate() + const dataFormatada = convertDate(birthdate[0][0].birthdate) + + const timestampNow = convertDateToTimestamp(dateNow) + const timestampAgePeople = convertDateToTimestamp(dataFormatada) + + const dateMilisecunds = timestampNow - timestampAgePeople + const ageInYears = timestampToYear(dateMilisecunds) + + + return Math.floor(ageInYears) +} +export default getAge; \ No newline at end of file diff --git a/src/GlobalFunctions/aboutDate/timestampToYear.ts b/src/GlobalFunctions/aboutDate/timestampToYear.ts new file mode 100644 index 0000000..fad93cf --- /dev/null +++ b/src/GlobalFunctions/aboutDate/timestampToYear.ts @@ -0,0 +1,7 @@ +// convertendo timestamp para ano + +export const timestampToYear = (timestamp: number) =>{ + const ageinYears = timestamp / 1000 / 60 / 60 / 24 / 365 + + return ageinYears +} \ No newline at end of file diff --git a/src/GlobalFunctions/capitalize/capitalize.ts b/src/GlobalFunctions/capitalize/capitalize.ts new file mode 100644 index 0000000..e67e5d1 --- /dev/null +++ b/src/GlobalFunctions/capitalize/capitalize.ts @@ -0,0 +1,4 @@ +export const capitalize = (string: string) => { + if (typeof string !== 'string') return '' + return string.charAt(0).toUpperCase() + string.slice(1) + } \ No newline at end of file diff --git a/src/GlobalFunctions/error/notFound.ts b/src/GlobalFunctions/error/notFound.ts new file mode 100644 index 0000000..9eda0a0 --- /dev/null +++ b/src/GlobalFunctions/error/notFound.ts @@ -0,0 +1,3 @@ +export const notFound = (value: string[]) =>{ + if(value.length === 0) throw new Error('No teacher found') +} \ No newline at end of file diff --git a/src/GlobalFunctions/updateClass.ts b/src/GlobalFunctions/updateClass.ts new file mode 100644 index 0000000..5735e25 --- /dev/null +++ b/src/GlobalFunctions/updateClass.ts @@ -0,0 +1,10 @@ +import {connection} from '../connection' + +const updateClassStudant = async (classId: string, newClassId: string, tableName: string) =>{ + await connection.raw(` + UPDATE ${tableName} + SET class_id = "${newClassId}" + WHERE id = "${classId}"; + `) +} +export default updateClassStudant; \ No newline at end of file diff --git a/src/TypesAndEnums/Enums.ts b/src/TypesAndEnums/Enums.ts new file mode 100644 index 0000000..e71f58c --- /dev/null +++ b/src/TypesAndEnums/Enums.ts @@ -0,0 +1,16 @@ +export enum Especialidades{ + + REACT="react", + REDUX="redux", + CSS="css", + TESTES="testes", + TYPESCRIPT="typescript", + PROGRAMACAO_ORIENTADA_OBJETOS="programacao orientada objetos", + BACKEND="backend" + +} + +export enum Type{ + TEACHER = "Teachers", + STUDENT = "Students" +} \ No newline at end of file diff --git a/src/TypesAndEnums/Types.ts b/src/TypesAndEnums/Types.ts new file mode 100644 index 0000000..6901cef --- /dev/null +++ b/src/TypesAndEnums/Types.ts @@ -0,0 +1,36 @@ +import { Especialidades, Type } from './Enums' + +export type Docentes = { + nome:string, + email:string, + data_nasc:string, + turma_id:number, + especialidade:Especialidades +} + +export type updateClass = { + tableName: Type, + peapleClassId: string, + peapleNewClassId: string +} + +export type data = { + id: string, + tableName: string +} + +export type student = { + id: string, + student_name: string, + email: string, + hobbies: string, + birthdate: string +} + +export type teacher = { + id: string, + teachers_name: string, + email: string, + speciality: string, + birthdate: string +} \ No newline at end of file diff --git a/src/app.ts b/src/app.ts new file mode 100644 index 0000000..fd02ebd --- /dev/null +++ b/src/app.ts @@ -0,0 +1,18 @@ +import express, {Express} from 'express' +import cors from 'cors' +import { AddressInfo } from "net"; + +const app: Express = express(); + +app.use(express.json()); +app.use(cors()); + +const server = app.listen(process.env.PORT || 3003, () => { + if (server) { + const address = server.address() as AddressInfo; + console.log(`Server is running in http://localhost: ${address.port}`); + } else { + console.error(`Failure upon starting server.`); + } +}); +export default app; \ No newline at end of file diff --git a/src/connection.ts b/src/connection.ts new file mode 100644 index 0000000..fc7a82e --- /dev/null +++ b/src/connection.ts @@ -0,0 +1,15 @@ +import knex from "knex"; +import dotenv from "dotenv"; + +dotenv.config(); + +export const connection = knex({ + client: "mysql", + connection: { + host: process.env.DB_HOST, + port: Number(process.env.DB_PORT) || 3306, + user: process.env.DB_USER, + password: process.env.DB_PASS, + database: process.env.DB_NAME + } +}); \ No newline at end of file diff --git a/src/createTables/createTables.ts b/src/createTables/createTables.ts new file mode 100644 index 0000000..13f1bfa --- /dev/null +++ b/src/createTables/createTables.ts @@ -0,0 +1,45 @@ +import { connection } from '../connection' + +const createTables = async (): Promise => { + try { + await connection.raw(` + CREATE TABLE Class ( + id VARCHAR(255) PRIMARY KEY, + name VARCHAR(50) NOT NULL, + start_date DATE NOT NULL, + end_date DATE NOT NULL, + module ENUM ('1', '2', '3', '4', '5', '6', '7', '0') DEFAULT '0', + type_class ENUM ("Integral", "Noturna") + ); + `) + + await connection.raw(` + CREATE TABLE IF NOT EXISTS Teachers ( + id VARCHAR(255) PRIMARY KEY, + name VARCHAR(50) NOT NULL, + email VARCHAR(50) NOT NULL UNIQUE, + birthdate DATE NOT NULL, + speciality ENUM ("React", "Redux", "CSS", "Testes", "Typescript", "Programação Orientada a Objetos", "Backend"), + class_id VARCHAR(255) NULL, + FOREIGN KEY (class_id) REFERENCES Class(id) + ); + `) + + await connection.raw(` + CREATE TABLE Students ( + id VARCHAR(255) PRIMARY KEY, + name VARCHAR(50) NOT NULL, + email VARCHAR(50) NOT NULL UNIQUE, + birthdate DATE NOT NULL, + hobbies VARCHAR(225), + class_id VARCHAR(255) NULL, + FOREIGN KEY (class_id) REFERENCES Class(id) + ); + `) + console.log('Funfou') + connection.destroy(); + } catch (error) { + throw new Error(error.message || error.sqlMessage); + } +} +createTables() \ No newline at end of file diff --git a/src/endpoints/both/getAge.ts b/src/endpoints/both/getAge.ts new file mode 100644 index 0000000..bd8da01 --- /dev/null +++ b/src/endpoints/both/getAge.ts @@ -0,0 +1,24 @@ +import { Request, Response } from 'express' +import getAge from "../../GlobalFunctions/aboutDate/getAge"; +import { capitalize } from '../../GlobalFunctions/capitalize/capitalize'; +import { data } from '../../TypesAndEnums/Types'; + +const getStudentAge = async (req: Request, res: Response): Promise => { + + try { + const data: data = { + id: req.query.id as string, + tableName: capitalize(req.query.tableName as string) + } + + const age: number = await getAge(data.id, data.tableName) + + res.status(200).send({ Age: age }) + + } + catch (error) { + res.status(500).send(error.message); + } +}; + +export default getStudentAge; \ No newline at end of file diff --git a/src/endpoints/class/post/createClass.ts b/src/endpoints/class/post/createClass.ts new file mode 100644 index 0000000..16a3d61 --- /dev/null +++ b/src/endpoints/class/post/createClass.ts @@ -0,0 +1,42 @@ +import { connection } from '../../../connection' +import { Request, Response } from 'express' + + +const createClass = async ( + req: Request, + res: Response +): Promise => { + try { + + let nameClass = req.body.name + if (req.body.type_class === 'Noturna') { + if (!req.body.name.includes('-na-night')) { + throw new Error('Nomes de turmas noturnas precisam terminar com -na-night.') + } else { + nameClass = req.body.name + } + } + + await connection.raw( + `INSERT INTO Class (id, class_name, start_date, end_date, type_class) + VALUES( + "${Date.now()}", + "${nameClass}", + "${req.body.start_date}", + "${req.body.end_date}", + "${req.body.type_class}" + )` + ) + + res.status(201).send({message: 'Turma criada com sucesso!'}) + + + } catch (error) { + if (error.message.includes('type_class')) { + res.status(422).send('Este tipo de turma não existe.') + } + res.status(500).send(error.message) + } +} + +export default createClass; \ No newline at end of file diff --git a/src/endpoints/class/put/changeClass.ts b/src/endpoints/class/put/changeClass.ts new file mode 100644 index 0000000..13b3de8 --- /dev/null +++ b/src/endpoints/class/put/changeClass.ts @@ -0,0 +1,46 @@ +import { Request, Response } from 'express'; +import updateClassStudant from '../../../GlobalFunctions/updateClass'; +import { updateClass } from '../../../TypesAndEnums/Types' + +const changeClass = async (req: Request, + res: Response) => { + try { + let errorCode: number = 400 + const body: updateClass = { + tableName: req.body.tableName, + peapleClassId: req.body.peapleClassId, + peapleNewClassId: req.body.peapleNewClassId + } + + let valueRes: string = "" + if(body.tableName.toLowerCase() === 'teachers'){ + valueRes = "The Teacher was insert in class successfully." + } + + if(body.tableName.toLowerCase() === 'students'){ + valueRes = "The Student was insert in class successfully." + } + + if(body.tableName !== 'Teachers' && body.tableName !== 'Students'){ + errorCode = 422 + throw new Error('tableName dont exist.') + } else if (!body.peapleClassId) { + errorCode = 422 + throw new Error('Invalid peapleClassId parameter.') + } else if (!body.peapleNewClassId) { + errorCode = 422 + throw new Error('Invalid peapleNewClassId parameter.') + } else if (!body.tableName) { + errorCode = 422 + throw new Error('Invalid talbleName parameter.') + } else { + await updateClassStudant(body.peapleClassId, body.peapleNewClassId, body.tableName) + res.status(200).send({message: String(valueRes)}) + } + + } catch (error) { + console.log(error) + res.status(400).send({ message: error.message }) + } +} +export default changeClass; \ No newline at end of file diff --git a/src/endpoints/class/put/changeModule.ts b/src/endpoints/class/put/changeModule.ts new file mode 100644 index 0000000..d933e13 --- /dev/null +++ b/src/endpoints/class/put/changeModule.ts @@ -0,0 +1,30 @@ +import { connection } from "../../../connection"; +import { Request, Response } from 'express' + +const changeModule = async (req: Request, res: Response): Promise => { + try { + const query = { + module: Number(req.query.module), + id: Number(req.query.id) + } + + if(isNaN(query.id) === true){ + throw new Error('Invalid id.') + } else if(isNaN(query.module) === true){ + throw new Error('Invalid module.') + } + + await connection.raw(` + UPDATE Class + SET module = ${query.module} + WHERE id = "${query.id}" + `) + + res.status(200).send({message: 'Module updated successfully.'}) + + } catch (error) { + console.log(error.message) + res.status(400).send(error.message) + } +} +export default changeModule \ No newline at end of file diff --git a/src/endpoints/studant/delete/removeStudent.ts b/src/endpoints/studant/delete/removeStudent.ts new file mode 100644 index 0000000..71d142a --- /dev/null +++ b/src/endpoints/studant/delete/removeStudent.ts @@ -0,0 +1,23 @@ +import { connection } from "../../../connection"; +import { Request, Response } from 'express' + +const removeStudent = async (req: Request, res: Response): Promise => { + try { + const id = Number(req.params.id) + + if(isNaN(id) === true) throw new Error("Invalid Id.") + + await connection.raw(` + DELETE + FROM Students + WHERE id = "${id}" + `) + + res.status(200).send({message: 'Student removed successfully.'}) + + } catch (error) { + console.log(error.message) + res.status(400).send(error.message) + } +} +export default removeStudent \ No newline at end of file diff --git a/src/endpoints/studant/delete/removeStudentsFromClass.ts b/src/endpoints/studant/delete/removeStudentsFromClass.ts new file mode 100644 index 0000000..4380a70 --- /dev/null +++ b/src/endpoints/studant/delete/removeStudentsFromClass.ts @@ -0,0 +1,23 @@ +import { connection } from "../../../connection"; +import { Request, Response } from 'express' + +const removeStudentFromClass = async (req: Request, res: Response): Promise => { + try { + const id = Number(req.params.id) + + if(isNaN(id) === true) throw new Error("Invalid Id.") + + await connection.raw(` + UPDATE Students + SET class_id = null + WHERE id = "${id}" + `) + + res.status(200).send({message: 'Student removed successfully.'}) + + } catch (error) { + console.log(error.message) + res.status(400).send(error.message) + } +} +export default removeStudentFromClass \ No newline at end of file diff --git a/src/endpoints/studant/get/getStudantsByClass.ts b/src/endpoints/studant/get/getStudantsByClass.ts new file mode 100644 index 0000000..02e7110 --- /dev/null +++ b/src/endpoints/studant/get/getStudantsByClass.ts @@ -0,0 +1,43 @@ +import { connection } from "../../../connection"; +import { Request, Response } from 'express' +import { convertDate } from "../../../GlobalFunctions/aboutDate/convertDate"; +import { student } from "../../../TypesAndEnums/Types"; + +const getStudantsByClass = async (req: Request, res: Response): Promise => { + + try { + const QueryResult = await connection.raw(` + SELECT + C.class_name, + S.id, + S.student_name, + S.email, + S.birthdate, + S.hobbies + FROM Students S + JOIN Class C + ON S.class_id = "${req.params.id}" + `) + + const students = QueryResult[0].map((student: student) => { + return ({ + id: student.id, + student_name: student.student_name, + email: student.email, + hobbies: student.hobbies, + birthdate: convertDate(student.birthdate) + }) + }) + + res.status(200).send({ + className: QueryResult[0][0].class_name, + student: students + }) + + } + catch (error) { + res.status(500).send(error.message) + } +} + +export default getStudantsByClass \ No newline at end of file diff --git a/src/endpoints/studant/get/getStudentsByHobbies.ts b/src/endpoints/studant/get/getStudentsByHobbies.ts new file mode 100644 index 0000000..f1b68f1 --- /dev/null +++ b/src/endpoints/studant/get/getStudentsByHobbies.ts @@ -0,0 +1,39 @@ +import { connection } from "../../../connection"; +import { Request, Response } from 'express' +import { convertDate } from "../../../GlobalFunctions/aboutDate/convertDate"; +import { student } from "../../../TypesAndEnums/Types"; +import { notFound } from "../../../GlobalFunctions/error/notFound"; + +const getStudentsByHobbies = async (req: Request, res: Response): Promise => { + + try { + const QueryResult = await connection.raw(` + SELECT * FROM Students WHERE hobbies IN ( + SELECT hobbies FROM Students + GROUP BY hobbies HAVING COUNT(*) > 1 + ); + `) + + const students = QueryResult[0].map((student: student) => { + return ({ + id: student.id, + student_name: student.student_name, + email: student.email, + hobbies: student.hobbies, + birthdate: convertDate(student.birthdate) + }) + }) + + notFound(students) + + res.status(200).send({ + students: students + }) + + } + catch (error) { + res.status(500).send(error.message) + } +} + +export default getStudentsByHobbies \ No newline at end of file diff --git a/src/endpoints/studant/post/createStudant.ts b/src/endpoints/studant/post/createStudant.ts new file mode 100644 index 0000000..1fa1c4a --- /dev/null +++ b/src/endpoints/studant/post/createStudant.ts @@ -0,0 +1,35 @@ +import { connection } from '../../../connection' +import { Request, Response } from 'express' + +const createStudant = async ( + req: Request, + res: Response +): Promise => { + try { + + let classId = 0 + if(!req.body.class_id){ + classId = 1 + } else { + classId = Number(req.body.class_id) + } + + await connection.raw( + ` + INSERT INTO Students (id, student_name, email, birthdate, hobbies) + VALUES( + "${Date.now()}", + "${req.body.name}", + "${req.body.email}", + "${req.body.birthdate}", + "${req.body.hobbies}" + )`) + + res.status(201).send({message: 'Estudante criado com sucesso!'}) + + } catch (error) { + res.status(500).send(error.message) + } +} + +export default createStudant; \ No newline at end of file diff --git a/src/endpoints/studant/put/put.ts b/src/endpoints/studant/put/put.ts new file mode 100644 index 0000000..1a80f44 --- /dev/null +++ b/src/endpoints/studant/put/put.ts @@ -0,0 +1 @@ +//criar endpoint put \ No newline at end of file diff --git a/src/endpoints/teacher/delete/removeTeacherFromClass.ts b/src/endpoints/teacher/delete/removeTeacherFromClass.ts new file mode 100644 index 0000000..a0fbbe2 --- /dev/null +++ b/src/endpoints/teacher/delete/removeTeacherFromClass.ts @@ -0,0 +1,23 @@ +import { connection } from "../../../connection"; +import { Request, Response } from 'express' + +const removeTeacherFromClass = async (req: Request, res: Response): Promise => { + try { + const id = Number(req.params.id) + + if(isNaN(id) === true) throw new Error("Invalid Id.") + + await connection.raw(` + UPDATE Teachers + SET class_id = null + WHERE id = "${id}" + `) + + res.status(200).send({message: 'Teacher removed successfully.'}) + + } catch (error) { + console.log(error.message) + res.status(400).send(error.message) + } +} +export default removeTeacherFromClass \ No newline at end of file diff --git a/src/endpoints/teacher/get/getTeacherByClass.ts b/src/endpoints/teacher/get/getTeacherByClass.ts new file mode 100644 index 0000000..c69e77f --- /dev/null +++ b/src/endpoints/teacher/get/getTeacherByClass.ts @@ -0,0 +1,46 @@ +import { connection } from "../../../connection"; +import { Request, Response } from 'express' +import { convertDate } from "../../../GlobalFunctions/aboutDate/convertDate"; +import { teacher } from "../../../TypesAndEnums/Types"; +import { notFound } from "../../../GlobalFunctions/error/notFound"; + +const getTeacherByClass = async (req: Request, res: Response): Promise => { + + try { + const QueryResult = await connection.raw(` + SELECT + C.class_name, + T.id, + T.teacher_name, + T.email, + T.birthdate, + T.speciality + FROM Teachers T + JOIN Class C + ON T.class_id = "${req.params.id}" + `) + + const teachers = QueryResult[0].map((teacher: teacher) => { + return ({ + id: teacher.id, + teachers_name: teacher.teachers_name, + email: teacher.email, + speciality: teacher.speciality, + birthdate: convertDate(teacher.birthdate) + }) + }) + + notFound(teachers) + + res.status(200).send({ + className: QueryResult[0][0].class_name, + teachers: teachers + }) + + } + catch (error) { + res.status(500).send(error.message) + } +} + +export default getTeacherByClass \ No newline at end of file diff --git a/src/endpoints/teacher/post/createTeacher.ts b/src/endpoints/teacher/post/createTeacher.ts new file mode 100644 index 0000000..a0fa0b4 --- /dev/null +++ b/src/endpoints/teacher/post/createTeacher.ts @@ -0,0 +1,33 @@ +import { connection } from '../../../connection' +import { Request, Response } from 'express' +import { Especialidades } from '../../../TypesAndEnums/Enums' +import { Docentes } from '../../../TypesAndEnums/Types' + +const createTeacher = async ( + req: Request, + res: Response +): Promise => { + try { + + await connection.raw( + ` + INSERT INTO Teachers (id, teacher_name, email, birthdate, speciality) + VALUES( + "${Date.now()}", + "${req.body.name}", + "${req.body.email}", + "${req.body.birthdate}", + "${req.body.speciality}" + )`) + + res.status(201).send({message: 'Professor criado com sucesso!'}) + + } catch (error) { + if(error.message.includes('speciality')){ + res.status(500).send('Esta especialidade não existe, tente novamente.') + } + res.status(500).send(error.message) + } +} + +export default createTeacher; \ No newline at end of file diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..25a0bee --- /dev/null +++ b/src/index.ts @@ -0,0 +1,26 @@ +import app from './app' +import createClass from './endpoints/class/post/createClass' +import createStudant from './endpoints/studant/post/createStudant' +import createTeacher from './endpoints/teacher/post/createTeacher' +import changeClass from './endpoints/class/put/changeClass' +import getStudantsByClass from './endpoints/studant/get/getStudantsByClass' +import getStudentAge from './endpoints/both/getAge' +import getTeacherByClass from './endpoints/teacher/get/getTeacherByClass' +import getStudentsByHobbies from './endpoints/studant/get/getStudentsByHobbies' +import removeStudentFromClass from './endpoints/studant/delete/removeStudentsFromClass' +import removeStudent from './endpoints/studant/delete/removeStudent' +import removeTeacherFromClass from './endpoints/teacher/delete/removeTeacherFromClass' +import changeModule from './endpoints/class/put/changeModule' + +app.get('/students/hobbies', getStudentsByHobbies) +app.get('/search/age', getStudentAge) +app.get('/students/:id', getStudantsByClass) +app.get('/teachers/:id', getTeacherByClass) +app.post ('/class/create', createClass) +app.post('/student/create', createStudant) +app.post ('/teacher/create', createTeacher) +app.put('/update/class', changeClass) +app.put('/class/change-module', changeModule) +app.delete('/student/remove-class/:id', removeStudentFromClass) +app.delete('/teacher/remove-class/:id', removeTeacherFromClass) +app.delete('/student/remove/:id', removeStudent) diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..3911e42 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,71 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "./build", /* Redirect output structure to the directory. */ + "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + + /* Advanced Options */ + "skipLibCheck": true, /* Skip type checking of declaration files. */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + } +}