├── .gitignore ├── .env ├── src ├── routes │ ├── houseRoutes.js │ ├── wizardRoutes.js │ └── reportRoutes.js ├── config │ └── database.js ├── models │ ├── houseModel.js │ └── wizardModel.js └── controllers │ ├── houseController.js │ ├── wizardController.js │ └── reportController.js ├── package.json ├── server.js └── database └── schema.sql /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | #O env está disponivel para que seja consultado pelos alunos. 2 | PORT=3000 3 | DB_USER=postgres 4 | DB_HOST=localhost 5 | DB_NAME=hp 6 | DB_PASSWORD=ds564 7 | DB_PORT=7777 8 | -------------------------------------------------------------------------------- /src/routes/houseRoutes.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const houseController = require("../controllers/houseController"); 4 | 5 | router.get("/houses", houseController.getAllHouses); 6 | router.get("/houses/:id", houseController.getHouse); 7 | 8 | module.exports = router; 9 | -------------------------------------------------------------------------------- /src/config/database.js: -------------------------------------------------------------------------------- 1 | const { Pool } = require("pg"); 2 | 3 | const pool = new Pool({ 4 | user: process.env.DB_USER, 5 | host: process.env.DB_HOST, 6 | database: process.env.DB_NAME, 7 | password: process.env.DB_PASSWORD, 8 | port: process.env.DB_PORT 9 | }); 10 | 11 | module.exports = pool; 12 | -------------------------------------------------------------------------------- /src/routes/wizardRoutes.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const wizardController = require("../controllers/wizardController"); 4 | 5 | router.get("/wizards", wizardController.getAllWizards); 6 | router.get("/wizards/:id", wizardController.getWizard); 7 | router.post("/wizards", wizardController.createWizard); 8 | 9 | 10 | module.exports = router; 11 | -------------------------------------------------------------------------------- /src/routes/reportRoutes.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const reportController = require("../controllers/reportController"); 4 | 5 | // Rota para gerar CSV 6 | router.get("/wizards/csv", reportController.exportWizardsCSV); 7 | 8 | // Rota para gerar PDF 9 | router.get("/wizards/pdf", reportController.exportWizardsPDF); 10 | 11 | module.exports = router; 12 | -------------------------------------------------------------------------------- /src/models/houseModel.js: -------------------------------------------------------------------------------- 1 | const pool = require("../config/database"); 2 | 3 | const getHouses = async () => { 4 | const result = await pool.query("SELECT * FROM houses"); 5 | return result.rows; 6 | }; 7 | 8 | const getHouseById = async (id) => { 9 | const result = await pool.query("SELECT * FROM houses WHERE id = $1", [id]); 10 | return result.rows[0]; 11 | }; 12 | 13 | module.exports = { getHouses, getHouseById }; 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "cors": "^2.8.5", 4 | "dotenv": "^16.4.7", 5 | "express": "^5.1.0", 6 | "fast-csv": "^5.0.2", 7 | "pdfkit": "^0.16.0", 8 | "pg": "^8.14.1" 9 | }, 10 | "name": "harrypotter", 11 | "version": "1.0.0", 12 | "main": "index.js", 13 | "scripts": { 14 | "test": "echo \"Error: no test specified\" && exit 1", 15 | "dev": "nodemon server.js" 16 | }, 17 | "keywords": [], 18 | "author": "", 19 | "license": "ISC", 20 | "description": "", 21 | "devDependencies": { 22 | "nodemon": "^3.1.9" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | const express = require("express"); 3 | const cors = require("cors"); 4 | const wizardRoutes = require("./src/routes/wizardRoutes"); 5 | const houseRoutes = require("./src/routes/houseRoutes"); 6 | const reportRoutes = require("./src/routes/reportRoutes"); 7 | 8 | const app = express(); 9 | app.use(cors()); 10 | app.use(express.json()); 11 | 12 | app.use("/api", wizardRoutes); 13 | app.use("/api", houseRoutes); 14 | app.use("/api/reports", reportRoutes); 15 | 16 | const PORT = process.env.PORT || 3000; 17 | app.listen(PORT, () => { 18 | console.log(`🚀 Servidor rodando em http://localhost:${PORT}`); 19 | }); 20 | -------------------------------------------------------------------------------- /database/schema.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE hp; 2 | 3 | CREATE TABLE houses ( 4 | id SERIAL PRIMARY KEY, 5 | name VARCHAR(100) UNIQUE NOT NULL, 6 | founder VARCHAR(100) NOT NULL 7 | ); 8 | 9 | CREATE TABLE wizards ( 10 | id SERIAL PRIMARY KEY, 11 | name VARCHAR(100) NOT NULL, 12 | house_id INTEGER REFERENCES houses(id) ON DELETE SET NULL 13 | ); 14 | 15 | INSERT INTO houses (name, founder) VALUES 16 | ('Grifinória', 'Godric Gryffindor'), 17 | ('Sonserina', 'Salazar Slytherin'), 18 | ('Corvinal', 'Rowena Ravenclaw'), 19 | ('Lufa-Lufa', 'Helga Hufflepuff'); 20 | 21 | INSERT INTO wizards (name, house_id) VALUES 22 | ('Harry Potter', 1), 23 | ('Draco Malfoy', 2), 24 | ('Luna Lovegood', 3), 25 | ('Cedrico Diggory', 4); 26 | -------------------------------------------------------------------------------- /src/controllers/houseController.js: -------------------------------------------------------------------------------- 1 | const houseModel = require("../models/houseModel"); 2 | 3 | const getAllHouses = async (req, res) => { 4 | try { 5 | const houses = await houseModel.getHouses(); 6 | res.json(houses); 7 | } catch (error) { 8 | res.status(500).json({ message: "Erro ao buscar casas." }); 9 | } 10 | }; 11 | 12 | const getHouse = async (req, res) => { 13 | try { 14 | const house = await houseModel.getHouseById(req.params.id); 15 | if (!house) { 16 | return res.status(404).json({ message: "Casa não encontrada." }); 17 | } 18 | res.json(house); 19 | } catch (error) { 20 | res.status(500).json({ message: "Erro ao buscar casa." }); 21 | } 22 | }; 23 | 24 | module.exports = { getAllHouses, getHouse }; 25 | -------------------------------------------------------------------------------- /src/controllers/wizardController.js: -------------------------------------------------------------------------------- 1 | const wizardModel = require("../models/wizardModel"); 2 | 3 | const getAllWizards = async (req, res) => { 4 | try { 5 | const wizards = await wizardModel.getWizards(); 6 | res.json(wizards); 7 | } catch (error) { 8 | res.status(500).json({ message: "Erro ao buscar bruxos." }); 9 | } 10 | }; 11 | 12 | const getWizard = async (req, res) => { 13 | try { 14 | const wizard = await wizardModel.getWizardById(req.params.id); 15 | if (!wizard) { 16 | return res.status(404).json({ message: "Bruxo não encontrado." }); 17 | } 18 | res.json(wizard); 19 | } catch (error) { 20 | res.status(500).json({ message: "Erro ao buscar bruxo." }); 21 | } 22 | }; 23 | 24 | const createWizard = async (req, res) => { 25 | try { 26 | const { name, house_id } = req.body; 27 | const newWizard = await wizardModel.createWizard(name, house_id); 28 | res.status(201).json(newWizard); 29 | } catch (error) { 30 | res.status(500).json({ message: "Erro ao criar bruxo." }); 31 | } 32 | }; 33 | 34 | 35 | module.exports = { getAllWizards, getWizard, createWizard }; 36 | -------------------------------------------------------------------------------- /src/models/wizardModel.js: -------------------------------------------------------------------------------- 1 | const pool = require("../config/database"); 2 | 3 | const getWizards = async () => { 4 | /* 5 | wizards.* → Pega todas as colunas da tabela wizards. 6 | 7 | houses.name AS house_name → Seleciona o nome da casa e dá a ela um alias house_name. 8 | 9 | FROM wizards → Define a tabela principal (wizards), onde buscamos os dados dos bruxos. 10 | 11 | LEFT JOIN houses ON wizards.house_id = houses.id → Junta a tabela houses com wizards, 12 | ligando house_id da tabela wizards ao id da tabela houses. 13 | O LEFT JOIN garante que mesmo bruxos sem casa cadastrada ainda apareçam na consulta. 14 | 15 | */ 16 | const result = await pool.query( 17 | `SELECT wizards.*, houses.name AS house_name 18 | FROM wizards 19 | LEFT JOIN houses ON wizards.house_id = houses.id` 20 | ); 21 | return result.rows; 22 | }; 23 | 24 | const getWizardById = async (id) => { 25 | const result = await pool.query( 26 | `SELECT wizards.*, houses.name AS house_name 27 | FROM wizards 28 | LEFT JOIN houses ON wizards.house_id = houses.id 29 | WHERE wizards.id = $1`, [id] 30 | ); 31 | return result.rows[0]; 32 | }; 33 | 34 | const createWizard = async (name, house_id) => { 35 | const result = await pool.query( 36 | "INSERT INTO wizards (name, house_id) VALUES ($1, $2) RETURNING *", 37 | [name, house_id] 38 | ); 39 | return result.rows[0]; 40 | }; 41 | 42 | module.exports = { getWizards, getWizardById, createWizard }; 43 | -------------------------------------------------------------------------------- /src/controllers/reportController.js: -------------------------------------------------------------------------------- 1 | const { format } = require("@fast-csv/format"); 2 | const PDFDocument = require("pdfkit"); 3 | 4 | const wizardModel = require("../models/wizardModel"); 5 | 6 | const exportWizardsCSV = async (req, res) => { 7 | try { 8 | const wizards = await wizardModel.getWizards(); 9 | 10 | res.setHeader("Content-Disposition", "attachment; filename=wizards.csv"); 11 | res.setHeader("Content-Type", "text/csv"); 12 | 13 | const csvStream = format({ headers: true }); 14 | csvStream.pipe(res); 15 | 16 | // Adicionando os dados ao CSV 17 | wizards.forEach((wizard) => { 18 | csvStream.write({ 19 | ID: wizard.id, 20 | Nome: wizard.name, 21 | Casa: wizard.house_name || "Sem casa" 22 | }); 23 | }); 24 | 25 | csvStream.end(); // Finaliza o stream do CSV 26 | } catch (error) { 27 | console.error("Erro ao gerar relatório:", error); 28 | res.status(500).json({ message: "Erro ao gerar relatório." }); 29 | } 30 | }; 31 | 32 | 33 | const exportWizardsPDF = async (req, res) => { 34 | try { 35 | const wizards = await wizardModel.getWizards(); 36 | 37 | // Configurar a resposta HTTP para PDF 38 | res.setHeader("Content-Type", "application/pdf"); 39 | res.setHeader("Content-Disposition", "inline; filename=wizards.pdf"); 40 | 41 | // Criar o documento PDF 42 | const doc = new PDFDocument(); 43 | doc.pipe(res); 44 | 45 | // Título 46 | doc.fontSize(20).text("Relatório de Bruxos", { align: "center" }); 47 | doc.moveDown(); 48 | 49 | // Cabeçalho da tabela 50 | doc.fontSize(12).text("ID | Nome | Casa", { underline: true }); 51 | doc.moveDown(0.5); 52 | 53 | // Adicionar os dados dos bruxos 54 | wizards.forEach((wizard) => { 55 | doc.text( 56 | `${wizard.id} | ${wizard.name} | ${wizard.house_name || "Sem casa"}` 57 | ); 58 | }); 59 | 60 | doc.end(); // Finalizar e enviar o PDF 61 | 62 | } catch (error) { 63 | console.error("Erro ao gerar relatório em PDF:", error); 64 | res.status(500).json({ message: "Erro ao gerar relatório em PDF." }); 65 | } 66 | }; 67 | 68 | module.exports = { exportWizardsCSV, exportWizardsPDF }; 69 | 70 | --------------------------------------------------------------------------------