├── .gitignore ├── .sequelizerc ├── .vscode └── launch.json ├── Dockerfile ├── Dockerfile_checkdisponibilidade ├── README.md ├── api ├── controllers │ ├── tarefas.js │ └── versao.js ├── data │ └── tarefas.json ├── models │ ├── index.js │ └── tarefas.js └── routes │ ├── ping.js │ ├── tarefas.js │ └── versao.js ├── buildspec.yml ├── client ├── db.json ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt ├── src │ ├── App.js │ ├── components │ │ ├── About.js │ │ ├── AddTask.js │ │ ├── Button.js │ │ ├── DadosHenrylle.js │ │ ├── Footer.js │ │ ├── Header.js │ │ ├── Task.js │ │ └── Tasks.js │ ├── index.css │ ├── index.js │ └── reportWebVitals.js └── yarn.lock ├── config ├── database.js ├── default.json └── express.js ├── database └── migrations │ └── 20210924000838-criar-tarefas.js ├── docker-compose.yml ├── index.html ├── index.js ├── lib └── boot.js ├── package-lock.json ├── package.json ├── rodar_app_local_unix.sh ├── rodar_app_local_windows.bat ├── scripts ├── criar_role_ssm.sh ├── ec2_principal.json ├── ecs │ ├── unix │ │ ├── build.sh │ │ ├── check-disponibilidade.sh │ │ ├── deploy.sh │ │ └── testar-latencia.sh │ └── windows │ │ ├── build.bat │ │ ├── build_rodando_powershell.PNG │ │ ├── check-disponibilidade.bat │ │ └── deploy.bat ├── lancar_ec2_zona_a.sh ├── ligar_bia_local.sh ├── parar_bia_local.sh ├── setup_bia_dev_ubuntu_ui.sh ├── setup_cloudshell_ssm.sh ├── setup_ui_ubuntu.sh ├── setup_vscode+chrome.sh ├── start-session-bash.sh ├── teste ├── user_data_ec2_zona_a.sh └── validar_recursos_zona_a.sh ├── scripts_evento └── README.md ├── server.js └── tests └── unit └── controllers └── versao.test.js /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | 7 | 8 | #React node_modules 9 | /client/node_modules 10 | 11 | #React production project 12 | /client/build 13 | /.pnp 14 | .pnp.js 15 | 16 | # testing 17 | /coverage 18 | 19 | # production 20 | /build 21 | 22 | # misc 23 | .DS_Store 24 | .env.local 25 | .env.development.local 26 | .env.test.local 27 | .env.production.local 28 | 29 | npm-debug.log* 30 | yarn-debug.log* 31 | yarn-error.log* 32 | -------------------------------------------------------------------------------- /.sequelizerc: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | 'config': path.resolve('config', 'database.js'), 5 | 'models-path': path.resolve('app', 'models'), 6 | 'seeders-path': path.resolve('database', 'seeders'), 7 | 'migrations-path': path.resolve('database', 'migrations'), 8 | }; -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Testar DB com secrets", 6 | "request": "launch", 7 | "skipFiles": [ 8 | "/**" 9 | ], 10 | "type": "node", 11 | "env": { 12 | "DB_SECRET_NAME": "", 13 | "DB_REGION": "us-east-1", 14 | "AWS_ACCESS_KEY_ID": "", 15 | "AWS_SECRET_ACCESS_KEY": "", 16 | "DEBUG_SECRET": "true" 17 | }, 18 | "program": "${workspaceFolder}/config/database.js" 19 | }, 20 | { 21 | "name": "Debug Server", 22 | "request": "launch", 23 | "skipFiles": [ 24 | "/**" 25 | ], 26 | "type": "node", 27 | "env": { 28 | "DB_SECRET_NAME": "", 29 | "DB_REGION": "us-east-1", 30 | "AWS_ACCESS_KEY_ID": "", 31 | "AWS_SECRET_ACCESS_KEY": "", 32 | "DEBUG_SECRET": "true" 33 | }, 34 | // "program": "${workspaceFolder}/server.js" 35 | "program": "${workspaceFolder}/server.js" 36 | } 37 | ] 38 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/docker/library/node:22-slim 2 | RUN npm install -g npm@11 --loglevel=error 3 | 4 | #Instalando o curl 5 | RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* 6 | 7 | WORKDIR /usr/src/app 8 | 9 | COPY package*.json ./ 10 | 11 | RUN npm install --loglevel=error 12 | 13 | COPY . . 14 | 15 | RUN NODE_OPTIONS=--openssl-legacy-provider REACT_APP_API_URL=http://34.239.240.133 SKIP_PREFLIGHT_CHECK=true npm run build --prefix client 16 | 17 | RUN mv client/build build 18 | 19 | RUN rm -rf client/* 20 | 21 | RUN mv build client/ 22 | 23 | EXPOSE 8080 24 | 25 | CMD [ "npm", "start" ] 26 | -------------------------------------------------------------------------------- /Dockerfile_checkdisponibilidade: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | # Define o fuso horário como São Paulo 4 | ENV TZ=America/Sao_Paulo 5 | 6 | # Endereço para teste 7 | ENV URL=https://www.google.com.br 8 | 9 | # Instala curl e configura timezone 10 | RUN apk add --no-cache curl tzdata \ 11 | && cp /usr/share/zoneinfo/$TZ /etc/localtime \ 12 | && echo "$TZ" > /etc/timezone 13 | 14 | # Script de monitoramento 15 | ENTRYPOINT echo "Checando Site: $URL"; \ 16 | while sleep 5; do \ 17 | curl -o /dev/null -s -w "Status: %{http_code} - Hora: $(date +%H:%M:%S)\n" $URL; \ 18 | done 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Projeto base para o evento Bootcamp Imersão AWS que irei realizar. 2 | 3 | ### Período do evento: 31/03 a 06/04/2025 (Online e ao Vivo às 20h) 4 | 5 | [>> Página de Inscrição do evento](https://org.imersaoaws.com.br/github/readme) 6 | 7 | #### Para rodar as migrations no container #### 8 | ``` 9 | docker compose exec server bash -c 'npx sequelize db:migrate' 10 | ``` 11 | -------------------------------------------------------------------------------- /api/controllers/tarefas.js: -------------------------------------------------------------------------------- 1 | const initializeModels = require("../models"); 2 | 3 | module.exports = () => { 4 | const controller = {}; 5 | 6 | controller.create = async (req, res) => { 7 | try { 8 | const { Tarefas } = await initializeModels(); 9 | let tarefa = { 10 | titulo: req.body.titulo, 11 | dia_atividade: req.body.dia, 12 | importante: req.body.importante, 13 | }; 14 | 15 | const data = await Tarefas.create(tarefa); 16 | res.send(data); 17 | } catch (err) { 18 | res.status(500).send({ 19 | message: err.message || "Deu ruim.", 20 | }); 21 | } 22 | }; 23 | 24 | controller.find = async (req, res) => { 25 | try { 26 | const { Tarefas } = await initializeModels(); 27 | let uuid = req.params.uuid; 28 | const data = await Tarefas.findByPk(uuid); 29 | if (data) { 30 | res.send(data); 31 | } else { 32 | res.status(404).send({ 33 | message: "Tarefa não encontrada.", 34 | }); 35 | } 36 | } catch (err) { 37 | res.status(500).send({ 38 | message: err.message || "Deu ruim.", 39 | }); 40 | } 41 | }; 42 | 43 | controller.delete = async (req, res) => { 44 | try { 45 | const { Tarefas } = await initializeModels(); 46 | let { uuid } = req.params; 47 | const result = await Tarefas.destroy({ 48 | where: { 49 | uuid: uuid, 50 | }, 51 | }); 52 | 53 | if (result) { 54 | res.send({ message: "Tarefa deletada com sucesso." }); 55 | } else { 56 | res.status(404).send({ 57 | message: "Tarefa não encontrada.", 58 | }); 59 | } 60 | } catch (err) { 61 | res.status(500).send({ 62 | message: err.message || "Deu ruim.", 63 | }); 64 | } 65 | }; 66 | 67 | controller.update_priority = async (req, res) => { 68 | try { 69 | const { Tarefas } = await initializeModels(); 70 | let { uuid } = req.params; 71 | await Tarefas.update(req.body, { 72 | where: { 73 | uuid: uuid, 74 | }, 75 | }); 76 | 77 | const data = await Tarefas.findByPk(uuid); 78 | if (data) { 79 | res.send(data); 80 | } else { 81 | res.status(404).send({ 82 | message: "Tarefa não encontrada.", 83 | }); 84 | } 85 | } catch (err) { 86 | res.status(500).send({ 87 | message: err.message || "Deu ruim.", 88 | }); 89 | } 90 | }; 91 | 92 | controller.findAll = async (req, res) => { 93 | try { 94 | const { Tarefas } = await initializeModels(); 95 | const data = await Tarefas.findAll(); 96 | res.send(data); 97 | } catch (err) { 98 | res.status(500).send({ 99 | message: err.message || "Deu ruim.", 100 | }); 101 | } 102 | }; 103 | 104 | return controller; 105 | }; 106 | -------------------------------------------------------------------------------- /api/controllers/versao.js: -------------------------------------------------------------------------------- 1 | module.exports = () => { 2 | const controller = {}; 3 | 4 | controller.get = async (req, res) => { 5 | const responseString = `Bia ${process.env.VERSAO_API || "3.2.0"}`; 6 | res.send(responseString); 7 | }; 8 | 9 | return controller; 10 | }; 11 | -------------------------------------------------------------------------------- /api/data/tarefas.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [{ 3 | "id": 1, 4 | "title": "Doctr Appoiment", 5 | "day": "Feb 5th at 2:30pm", 6 | "reminder": true 7 | }, 8 | { 9 | "title": "Party 2", 10 | "day": "16 de abril", 11 | "reminder": true, 12 | "id": 4 13 | }, 14 | { 15 | "title": "Party 3", 16 | "day": "18 de Abril", 17 | "reminder": true, 18 | "id": 5 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /api/models/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const fs = require("fs"); 4 | const path = require("path"); 5 | const Sequelize = require("sequelize"); 6 | const basename = path.basename(__filename); 7 | const getConfig = require("../../config/database.js"); 8 | 9 | const db = {}; 10 | 11 | const initializeModels = async () => { 12 | const resolvedConfig = await getConfig(); 13 | const sequelize = new Sequelize(resolvedConfig); 14 | try { 15 | const files = await fs.promises.readdir(__dirname); 16 | 17 | for (const file of files) { 18 | if (file !== basename && file.slice(-3) === ".js") { 19 | const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes); 20 | db[model.name] = model; 21 | } 22 | } 23 | 24 | Object.keys(db).forEach(modelName => { 25 | if (db[modelName].associate) { 26 | db[modelName].associate(db); 27 | } 28 | }); 29 | 30 | db.sequelize = sequelize; 31 | db.Sequelize = Sequelize; 32 | 33 | return db; 34 | } catch (error) { 35 | console.error("Erro ao inicializar os modelos:", error); 36 | throw error; 37 | } 38 | }; 39 | 40 | module.exports = initializeModels; 41 | -------------------------------------------------------------------------------- /api/models/tarefas.js: -------------------------------------------------------------------------------- 1 | module.exports = (sequelize, DataTypes) => { 2 | const Tarefas = sequelize.define("Tarefas", { 3 | uuid: { 4 | type: DataTypes.UUID, 5 | defaultValue: DataTypes.UUIDV1, 6 | primaryKey: true, 7 | }, 8 | titulo: DataTypes.STRING, 9 | dia_atividade: DataTypes.STRING, 10 | importante: DataTypes.BOOLEAN, 11 | }); 12 | 13 | return Tarefas; 14 | }; 15 | -------------------------------------------------------------------------------- /api/routes/ping.js: -------------------------------------------------------------------------------- 1 | module.exports = (app) => { 2 | app.route("/api/ping").get((req, res) => { 3 | res.json("Rota funcionando. Pong!"); 4 | }); 5 | }; 6 | -------------------------------------------------------------------------------- /api/routes/tarefas.js: -------------------------------------------------------------------------------- 1 | module.exports = (app) => { 2 | const controllerFactory = require("../controllers/tarefas"); 3 | const controller = controllerFactory(); 4 | 5 | app.route("/api/tarefas") 6 | .get(async (req, res, next) => { 7 | try { 8 | await controller.findAll(req, res); 9 | } catch (err) { 10 | next(err); 11 | } 12 | }) 13 | .post(async (req, res, next) => { 14 | try { 15 | await controller.create(req, res); 16 | } catch (err) { 17 | next(err); 18 | } 19 | }); 20 | 21 | app.route("/api/tarefas/:uuid") 22 | .get(async (req, res, next) => { 23 | try { 24 | await controller.find(req, res); 25 | } catch (err) { 26 | next(err); 27 | } 28 | }); 29 | 30 | app.route("/api/tarefas/update_priority/:uuid") 31 | .put(async (req, res, next) => { 32 | try { 33 | await controller.update_priority(req, res); 34 | } catch (err) { 35 | next(err); 36 | } 37 | }); 38 | 39 | app.route("/api/tarefas/:uuid") 40 | .delete(async (req, res, next) => { 41 | try { 42 | await controller.delete(req, res); 43 | } catch (err) { 44 | next(err); 45 | } 46 | }); 47 | }; 48 | -------------------------------------------------------------------------------- /api/routes/versao.js: -------------------------------------------------------------------------------- 1 | module.exports = (app) => { 2 | const controller = require("../controllers/versao")(); 3 | 4 | app.route("/api/versao").get(controller.get); 5 | }; 6 | -------------------------------------------------------------------------------- /buildspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | 3 | phases: 4 | pre_build: 5 | commands: 6 | - echo Fazendo login no ECR... 7 | - aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 905418381762.dkr.ecr.us-east-1.amazonaws.com 8 | - REPOSITORY_URI=905418381762.dkr.ecr.us-east-1.amazonaws.com/bia 9 | - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7) 10 | - IMAGE_TAG=${COMMIT_HASH:=latest} 11 | build: 12 | commands: 13 | - echo Build iniciado em `date` 14 | - echo Gerando imagem da BIA... 15 | - docker build -t $REPOSITORY_URI:latest . 16 | - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG 17 | post_build: 18 | commands: 19 | - echo Build finalizado com sucesso em `date` 20 | - echo Fazendo push da imagem para o ECR... 21 | - docker push $REPOSITORY_URI:latest 22 | - docker push $REPOSITORY_URI:$IMAGE_TAG 23 | - echo Gerando artefato da imagem para o ECS 24 | - printf '[{"name":"bia","imageUri":"%s"}]' $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json 25 | artifacts: 26 | files: imagedefinitions.json -------------------------------------------------------------------------------- /client/db.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | { 4 | "id": 1, 5 | "title": "Doctor Appoiment", 6 | "day": "Feb 5th at 2:30pm", 7 | "reminder": true 8 | }, 9 | { 10 | "title": "Party 2", 11 | "day": "16 de abril", 12 | "reminder": true, 13 | "id": 4 14 | }, 15 | { 16 | "title": "Party 3", 17 | "day": "18 de Abril", 18 | "reminder": true, 19 | "id": 5 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-task-tracker", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.11.4", 7 | "@testing-library/react": "^11.1.0", 8 | "@testing-library/user-event": "^12.1.10", 9 | "json-server": "^0.16.3", 10 | "react": "^17.0.2", 11 | "react-dom": "^17.0.2", 12 | "react-icons": "^4.2.0", 13 | "react-router-dom": "^5.3.0", 14 | "react-scripts": "4.0.3", 15 | "web-vitals": "^1.0.1" 16 | }, 17 | "scripts": { 18 | "start": "react-scripts start", 19 | "build": "react-scripts build", 20 | "test": "react-scripts test", 21 | "eject": "react-scripts eject", 22 | "server": "json-server --watch db.json --port 5000" 23 | }, 24 | "eslintConfig": { 25 | "extends": [ 26 | "react-app", 27 | "react-app/jest" 28 | ] 29 | }, 30 | "browserslist": { 31 | "production": [ 32 | ">0.2%", 33 | "not dead", 34 | "not op_mini all" 35 | ], 36 | "development": [ 37 | "last 1 chrome version", 38 | "last 1 firefox version", 39 | "last 1 safari version" 40 | ] 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/henrylle/bia/ee589a0a89aae86802df7797d2c2eaa9def066dd/client/public/favicon.ico -------------------------------------------------------------------------------- /client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | BIA - 2025 15 | 16 | 17 | 18 |
19 | 20 | 21 | -------------------------------------------------------------------------------- /client/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/henrylle/bia/ee589a0a89aae86802df7797d2c2eaa9def066dd/client/public/logo192.png -------------------------------------------------------------------------------- /client/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/henrylle/bia/ee589a0a89aae86802df7797d2c2eaa9def066dd/client/public/logo512.png -------------------------------------------------------------------------------- /client/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /client/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /client/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import { BrowserRouter as Router, Route } from "react-router-dom"; 3 | import Header from "./components/Header"; 4 | import Footer from "./components/Footer"; 5 | import Tasks from "./components/Tasks"; 6 | import AddTask from "./components/AddTask"; 7 | import About from "./components/About"; 8 | const apiUrl = process.env.REACT_APP_API_URL || "http://localhost:8080"; 9 | 10 | function App() { 11 | const [showAddTask, setShowAddTask] = useState(false); 12 | const [tasks, setTasks] = useState([]); 13 | 14 | useEffect(() => { 15 | const getTasks = async () => { 16 | const tasksFromServer = await fetchTasks(); 17 | setTasks(tasksFromServer); 18 | }; 19 | 20 | //Listar Tarefas 21 | const fetchTasks = async () => { 22 | const res = await fetch(`${apiUrl}/api/tarefas`); 23 | console.log(res); 24 | const data = await res.json(); 25 | return data; 26 | }; 27 | 28 | getTasks(); 29 | }, []); 30 | 31 | //Listar Tarefa 32 | const fetchTask = async (uuid) => { 33 | const res = await fetch(`${apiUrl}/api/tarefas/${uuid}`); 34 | const data = await res.json(); 35 | return data; 36 | }; 37 | 38 | //Alternar Importante 39 | const toggleReminder = async (uuid) => { 40 | const taskToToggle = await fetchTask(uuid); 41 | const updatedTask = { 42 | ...taskToToggle, 43 | importante: !taskToToggle.importante, 44 | }; 45 | 46 | const res = await fetch(`${apiUrl}/api/tarefas/update_priority/${uuid}`, { 47 | method: "PUT", 48 | headers: { 49 | "Content-type": "application/json", 50 | }, 51 | body: JSON.stringify(updatedTask), 52 | }); 53 | const data = await res.json(); 54 | setTasks( 55 | tasks.map((task) => 56 | task.uuid === uuid ? { ...task, importante: data.importante } : task 57 | ) 58 | ); 59 | }; 60 | 61 | //Adicionar Tarefa 62 | const addTask = async (task) => { 63 | const res = await fetch(`${apiUrl}/api/tarefas`, { 64 | method: "POST", 65 | headers: { 66 | "Content-type": "application/json", 67 | }, 68 | body: JSON.stringify(task), 69 | }); 70 | const data = await res.json(); 71 | setTasks([...tasks, data]); 72 | }; 73 | 74 | //Remover tarefa 75 | const deleteTask = async (uuid) => { 76 | await fetch(`${apiUrl}/api/tarefas/${uuid}`, { 77 | method: "DELETE", 78 | }); 79 | setTasks(tasks.filter((task) => task.uuid !== uuid)); 80 | }; 81 | 82 | return ( 83 | 84 |
85 |
setShowAddTask(!showAddTask)} 87 | showAdd={showAddTask} 88 | /> 89 | 90 | ( 94 | <> 95 | {showAddTask && } 96 | {tasks.length > 0 ? ( 97 | 102 | ) : ( 103 | "Nenhuma tarefa nesse momento" 104 | )} 105 | 106 | )} 107 | /> 108 | 109 |
110 |
111 |
112 | ); 113 | } 114 | 115 | export default App; 116 | -------------------------------------------------------------------------------- /client/src/components/About.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link } from "react-router-dom"; 3 | import DadosHenrylle from "./DadosHenrylle"; 4 | const About = () => { 5 | return ( 6 |
7 |

Versão 3.2.0

8 |
BIA 31/03 a 06/04/2025
9 | Voltar 10 | 11 |
12 | ); 13 | }; 14 | 15 | export default About; 16 | -------------------------------------------------------------------------------- /client/src/components/AddTask.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | 3 | const AddTask = ({ onAdd }) => { 4 | const [titulo, setTitulo] = useState(""); 5 | const [dia, setDia] = useState(""); 6 | const [importante, setImportante] = useState(false); 7 | 8 | const onSubmit = (e) => { 9 | e.preventDefault(); 10 | 11 | if (!titulo) { 12 | alert("Por favor, adicione uma tarefa"); 13 | return; 14 | } 15 | 16 | onAdd({ titulo, dia, importante }); 17 | 18 | setTitulo(""); 19 | setDia(""); 20 | setImportante(false); 21 | }; 22 | 23 | return ( 24 |
25 |
26 | 27 | setTitulo(e.target.value)} 32 | /> 33 |
34 |
35 | 36 | setDia(e.target.value)} 41 | /> 42 |
43 |
44 | 45 | setImportante(e.currentTarget.checked)} 50 | /> 51 |
52 | 53 |
54 | ); 55 | }; 56 | 57 | export default AddTask; 58 | -------------------------------------------------------------------------------- /client/src/components/Button.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const Button = ({ color, text, onClick }) => { 3 | return ( 4 | 11 | ); 12 | }; 13 | 14 | Button.defaultProps = { 15 | color: "steelblue", 16 | }; 17 | 18 | export default Button; 19 | -------------------------------------------------------------------------------- /client/src/components/DadosHenrylle.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const DadosHenrylle = () => { 4 | return ( 5 |
6 |
7 |
8 |
Links úteis:
9 | 56 |
57 | ); 58 | }; 59 | 60 | export default DadosHenrylle; 61 | -------------------------------------------------------------------------------- /client/src/components/Footer.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link } from "react-router-dom"; 3 | 4 | const Footer = () => { 5 | return ( 6 |
7 |

Copyright Formação AWS 2025

8 | Sobre a BIA 9 |
10 | ); 11 | }; 12 | 13 | export default Footer; 14 | -------------------------------------------------------------------------------- /client/src/components/Header.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useLocation } from "react-router-dom"; 3 | import Button from "./Button"; 4 | 5 | const Header = ({ title, onAdd, showAdd }) => { 6 | const location = useLocation(); 7 | return ( 8 |
9 |

{title}

10 | {/*

process.env.EMAIL_ALUNO

*/} 11 | {location.pathname === "/" && ( 12 |
19 | ); 20 | }; 21 | 22 | Header.defaultProps = { 23 | title: "BIA 2025", 24 | }; 25 | 26 | export default Header; 27 | -------------------------------------------------------------------------------- /client/src/components/Task.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { FaTimes } from "react-icons/fa"; 3 | const Task = ({ task, onDelete, onToggle }) => { 4 | return ( 5 |
onToggle(task.uuid)} 8 | > 9 |

10 | {task.titulo}{" "} 11 | onDelete(task.uuid)} 14 | /> 15 |

16 |

{task.dia_atividade}

17 |
18 | ); 19 | }; 20 | 21 | export default Task; 22 | -------------------------------------------------------------------------------- /client/src/components/Tasks.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Task from "./Task"; 3 | 4 | const Tasks = ({ tasks, onDelete, onToggle }) => { 5 | return ( 6 | <> 7 | {tasks.map((task) => ( 8 | 14 | ))} 15 | 16 | ); 17 | }; 18 | 19 | export default Tasks; 20 | -------------------------------------------------------------------------------- /client/src/index.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400&display=swap'); 2 | 3 | * { 4 | box-sizing: border-box; 5 | margin: 0; 6 | padding: 0; 7 | } 8 | 9 | body { 10 | font-family: 'Poppins', sans-serif; 11 | } 12 | 13 | .container { 14 | max-width: 500px; 15 | margin: 30px auto; 16 | overflow: auto; 17 | min-height: 300px; 18 | border: 1px solid steelblue; 19 | padding: 30px; 20 | border-radius: 5px; 21 | } 22 | 23 | .header { 24 | display: flex; 25 | justify-content: space-between; 26 | align-items: center; 27 | margin-bottom: 20px; 28 | } 29 | 30 | .btn { 31 | display: inline-block; 32 | background: #000; 33 | color: #fff; 34 | border: none; 35 | padding: 10px 20px; 36 | margin: 5px; 37 | border-radius: 5px; 38 | cursor: pointer; 39 | text-decoration: none; 40 | font-size: 15px; 41 | font-family: inherit; 42 | } 43 | 44 | .btn:focus { 45 | outline: none; 46 | } 47 | 48 | .btn:active { 49 | transform: scale(0.98); 50 | } 51 | 52 | .btn-block { 53 | display: block; 54 | width: 100%; 55 | } 56 | 57 | .task { 58 | background: #f4f4f4; 59 | margin: 5px; 60 | padding: 10px 20px; 61 | cursor: pointer; 62 | } 63 | 64 | .task.reminder { 65 | border-left: 5px solid green; 66 | } 67 | 68 | .task h3 { 69 | display: flex; 70 | align-items: center; 71 | justify-content: space-between; 72 | } 73 | 74 | .add-form { 75 | margin-bottom: 40px; 76 | } 77 | 78 | .form-control { 79 | margin: 20px 0; 80 | } 81 | 82 | .form-control label { 83 | display: block; 84 | } 85 | 86 | .form-control input { 87 | width: 100%; 88 | height: 40px; 89 | margin: 5px; 90 | padding: 3px 7px; 91 | font-size: 17px; 92 | } 93 | 94 | .form-control-check { 95 | display: flex; 96 | align-items: center; 97 | justify-content: space-between; 98 | } 99 | 100 | .form-control-check label { 101 | flex: 1; 102 | } 103 | 104 | .form-control-check input { 105 | flex: 2; 106 | height: 20px; 107 | } 108 | 109 | footer { 110 | margin-top: 30px; 111 | text-align: center; 112 | } 113 | ul li{ 114 | font-size: 14px; 115 | } -------------------------------------------------------------------------------- /client/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /client/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /config/database.js: -------------------------------------------------------------------------------- 1 | const { SecretsManagerClient, GetSecretValueCommand } = require("@aws-sdk/client-secrets-manager"); 2 | const { fromIni, fromEnv } = require("@aws-sdk/credential-providers"); 3 | const { STSClient, GetCallerIdentityCommand } = require("@aws-sdk/client-sts"); 4 | 5 | async function isLocalConnection() { 6 | // Lógica para determinar se a conexão é local 7 | return ( 8 | process.env.DB_HOST === undefined || 9 | process.env.DB_HOST === "database" || 10 | process.env.DB_HOST === "127.0.0.1" || 11 | process.env.DB_HOST === "localhost" 12 | ); 13 | } 14 | 15 | async function getRemoteDialectOptions() { 16 | // Configurações específicas para conexões remotas (útil a partir do pg 15) 17 | return { 18 | ssl: { 19 | require: true, 20 | rejectUnauthorized: false, 21 | }, 22 | }; 23 | } 24 | 25 | async function getConfig(){ 26 | let dbConfig = { 27 | username: process.env.DB_USER || "postgres", 28 | password: process.env.DB_PWD || "postgres", 29 | database: "bia", 30 | host: process.env.DB_HOST || "127.0.0.1", 31 | port: process.env.DB_PORT || 5433, 32 | dialect: "postgres", 33 | dialectOptions: await isLocalConnection() ? {} : await getRemoteDialectOptions(), 34 | }; 35 | 36 | if(process.env.DB_SECRET_NAME && process.env.DB_SECRET_NAME.trim() !== '' ){ 37 | const secretsManagerClient = await createSecretsManagerClient(); 38 | const secrets = await getSecrets(secretsManagerClient); 39 | 40 | if(secrets){ 41 | dbConfig.username = secrets.username; 42 | dbConfig.password = secrets.password; 43 | 44 | await imprimirSecrets(secrets); 45 | } 46 | } 47 | return dbConfig; 48 | } 49 | 50 | async function createSecretsManagerClient() { 51 | // Verifica se a variável de ambiente está definida e não está vazia 52 | let credentials; 53 | 54 | if (process.env.IS_LOCAL === "true") { 55 | credentials = fromEnv(); 56 | //credentials = fromIni({ profile: "SEU_PROFILE" }); 57 | } 58 | 59 | if (process.env.DB_SECRET_NAME) { 60 | // Instancia o cliente do Secrets Manager 61 | const client = new SecretsManagerClient({ 62 | region: process.env.DB_REGION, 63 | credentials 64 | }); 65 | 66 | if(process.env.DEBUG_SECRET === "true"){ 67 | const stsClient = new STSClient({ 68 | region: process.env.DB_REGION, 69 | credentials 70 | }); 71 | 72 | try { 73 | const identity = await stsClient.send(new GetCallerIdentityCommand({})); 74 | console.log('Credenciais carregadas com sucesso:', identity); 75 | console.log('Account ID:', identity.Account); 76 | } catch (error) { 77 | console.error('Erro ao carregar credenciais:', error); 78 | } 79 | } 80 | return client; 81 | } else { 82 | console.log('DB_SECRET_NAME não está definida. Se for usar secrets, informe também DB_REGION.'); 83 | return null; 84 | } 85 | } 86 | 87 | async function imprimirSecrets(secrets){ 88 | if(process.env.DEBUG_SECRET === "true") 89 | console.log(secrets); 90 | } 91 | 92 | async function getSecrets(secretsManagerClient) { 93 | try { 94 | if (!secretsManagerClient) { 95 | console.error('O cliente do Secrets Manager não foi instanciado.'); 96 | return; 97 | } 98 | console.log(`Vou trabalhar com o secrets ${process.env.DB_SECRET_NAME}`); 99 | const command = new GetSecretValueCommand({ SecretId: process.env.DB_SECRET_NAME }); 100 | const data = await secretsManagerClient.send(command); 101 | 102 | if ('SecretString' in data) { 103 | return JSON.parse(data.SecretString); 104 | } else { 105 | return Buffer.from(data.SecretBinary, 'base64'); 106 | } 107 | } catch (err) { 108 | console.error('Erro ao recuperar as credenciais do Secrets Manager:', err); 109 | throw err; 110 | } 111 | } 112 | 113 | module.exports = getConfig; 114 | 115 | -------------------------------------------------------------------------------- /config/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "server": { 3 | "port": 8080 4 | } 5 | } -------------------------------------------------------------------------------- /config/express.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | var cors = require("cors"); 3 | var path = require("path"); 4 | const config = require("config"); 5 | var bodyParser = require("body-parser"); 6 | 7 | module.exports = () => { 8 | const app = express(); 9 | 10 | // SETANDO VARIÁVEIS DA APLICAÇÃO 11 | app.set("port", process.env.PORT || config.get("server.port")); 12 | 13 | //Setando react 14 | app.use(express.static(path.join(__dirname, "../", "client", "build"))); 15 | 16 | // parse request bodies (req.body) 17 | app.use(express.urlencoded({ extended: true })); 18 | app.use(bodyParser.json()); 19 | 20 | app.use(cors()); 21 | 22 | require("../api/routes/tarefas")(app); 23 | require("../api/routes/versao")(app); 24 | 25 | return app; 26 | }; 27 | -------------------------------------------------------------------------------- /database/migrations/20210924000838-criar-tarefas.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = { 4 | up: async (queryInterface, Sequelize) => { 5 | return queryInterface.createTable("Tarefas", { 6 | uuid: { 7 | allowNull: false, 8 | primaryKey: true, 9 | defaultValue: Sequelize.UUIDV1, 10 | type: Sequelize.UUID, 11 | }, 12 | titulo: { 13 | allowNull: false, 14 | type: Sequelize.STRING, 15 | }, 16 | dia_atividade: { 17 | allowNull: true, 18 | type: Sequelize.STRING, 19 | }, 20 | importante: { 21 | allowNull: true, 22 | defaultValue: false, 23 | type: Sequelize.BOOLEAN, 24 | }, 25 | createdAt: { 26 | allowNull: false, 27 | type: Sequelize.DATE, 28 | }, 29 | updatedAt: { 30 | allowNull: false, 31 | type: Sequelize.DATE, 32 | }, 33 | }); 34 | }, 35 | 36 | down: async (queryInterface, Sequelize) => { 37 | await queryInterface.dropTable("Tarefas"); 38 | }, 39 | }; 40 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | server: 3 | build: . 4 | container_name: bia 5 | ports: 6 | - 3001:8080 7 | links: 8 | - database 9 | environment: 10 | DB_USER: postgres 11 | DB_PWD: postgres 12 | DB_HOST: database 13 | DB_PORT: 5432 14 | ## NAO PRECISA NO BOOTCAMP DAQUI PRA BAIXO ## 15 | # DB_SECRET_NAME: 16 | # DB_REGION: 17 | # AWS_ACCESS_KEY_ID: 18 | # AWS_SECRET_ACCESS_KEY: 19 | # DEBUG_SECRET: 20 | # IS_LOCAL: true 21 | # healthcheck: 22 | # test: ["CMD", "curl", "-f", "http://localhost:8080/api/versao"] 23 | # interval: 10s 24 | # timeout: 5s 25 | # retries: 3 26 | # start_period: 5s 27 | database: 28 | image: postgres:16.1 29 | container_name: database 30 | environment: 31 | - "POSTGRES_USER=postgres" 32 | - "POSTGRES_PASSWORD=postgres" 33 | - "POSTGRES_DB=bia" 34 | ports: 35 | - 5433:5432 36 | volumes: 37 | - db:/var/lib/postgresql/data 38 | volumes: 39 | db: 40 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Hello World Simple App 8 | 9 | 10 |
Hello World!
11 | 12 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var logger = require("morgan"); 3 | var path = require("path"); 4 | var session = require("express-session"); 5 | var methodOverride = require("method-override"); 6 | 7 | var app = express(); 8 | 9 | // define a custom res.message() method 10 | // which stores messages in the session 11 | app.response.message = function (msg) { 12 | // reference `req.session` via the `this.req` reference 13 | var sess = this.req.session; 14 | // simply add the msg to an array for later 15 | sess.messages = sess.messages || []; 16 | sess.messages.push(msg); 17 | return this; 18 | }; 19 | 20 | // log 21 | app.use(logger("dev")); 22 | 23 | // serve static files 24 | app.use(express.static(path.join(__dirname, "app", "public"))); 25 | app.use(express.static(path.join(__dirname, "client", "build"))); 26 | 27 | // session support 28 | app.use( 29 | session({ 30 | resave: false, // don't save session if unmodified 31 | saveUninitialized: false, // don't create session until something stored 32 | secret: "some secret here", 33 | }) 34 | ); 35 | 36 | // parse request bodies (req.body) 37 | app.use(express.urlencoded({ extended: true })); 38 | 39 | // allow overriding methods in query (?_method=put) 40 | app.use(methodOverride("_method")); 41 | 42 | // expose the "messages" local variable when views are rendered 43 | app.use(function (req, res, next) { 44 | var msgs = req.session.messages || []; 45 | 46 | // expose "messages" local variable 47 | res.locals.messages = msgs; 48 | 49 | // expose "hasMessages" 50 | res.locals.hasMessages = !!msgs.length; 51 | 52 | /* This is equivalent: 53 | res.locals({ 54 | messages: msgs, 55 | hasMessages: !! msgs.length 56 | }); 57 | */ 58 | 59 | next(); 60 | // empty or "flush" the messages so they 61 | // don't build up 62 | req.session.messages = []; 63 | }); 64 | 65 | // load controllers 66 | require("./lib/boot")(app, { verbose: false }); 67 | 68 | app.use(function (err, req, res, next) { 69 | // log it 70 | console.error(err.stack); 71 | 72 | // error page 73 | res.status(500).render("5xx"); 74 | }); 75 | 76 | // assume 404 since no middleware responded 77 | app.use(function (req, res, next) { 78 | res.status(404).render("404", { url: req.originalUrl }); 79 | }); 80 | 81 | app.listen(3000); 82 | console.log("Express started on port 3000"); 83 | -------------------------------------------------------------------------------- /lib/boot.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Module dependencies. 3 | */ 4 | 5 | var express = require("express"); 6 | var fs = require("fs"); 7 | var path = require("path"); 8 | 9 | module.exports = function (parent, options) { 10 | var dir = path.join(__dirname, "..", "app", "controllers"); 11 | var verbose = options.verbose; 12 | fs.readdirSync(dir).forEach(function (name) { 13 | var file = path.join(dir, name); 14 | if (!fs.statSync(file).isDirectory()) return; 15 | verbose && console.log("\n %s:", name); 16 | var obj = require(file); 17 | var name = obj.name || name; 18 | var prefix = obj.prefix || ""; 19 | var app = express(); 20 | var handler; 21 | var method; 22 | var url; 23 | 24 | // allow specifying the view engine 25 | if (obj.engine) app.set("view engine", obj.engine); 26 | app.set( 27 | "views", 28 | path.join(__dirname, "..", "app", "controllers", name, "views") 29 | ); 30 | 31 | // generate routes based 32 | // on the exported methods 33 | for (var key in obj) { 34 | // "reserved" exports 35 | if (~["name", "prefix", "engine", "before"].indexOf(key)) continue; 36 | // route exports 37 | switch (key) { 38 | case "show": 39 | method = "get"; 40 | url = "/" + name + "/:" + name + "_id"; 41 | break; 42 | case "list": 43 | method = "get"; 44 | url = "/" + name + "s"; 45 | break; 46 | case "edit": 47 | method = "get"; 48 | url = "/" + name + "/:" + name + "_id/edit"; 49 | break; 50 | case "update": 51 | method = "put"; 52 | url = "/" + name + "/:" + name + "_id"; 53 | break; 54 | case "create": 55 | method = "post"; 56 | url = "/" + name; 57 | break; 58 | case "index": 59 | method = "get"; 60 | url = "/"; 61 | break; 62 | default: 63 | /* istanbul ignore next */ 64 | throw new Error("unrecognized route: " + name + "." + key); 65 | } 66 | 67 | // setup 68 | handler = obj[key]; 69 | url = prefix + url; 70 | 71 | // before middleware support 72 | if (obj.before) { 73 | app[method](url, obj.before, handler); 74 | verbose && 75 | console.log( 76 | " %s %s -> before -> %s", 77 | method.toUpperCase(), 78 | url, 79 | key 80 | ); 81 | } else { 82 | app[method](url, handler); 83 | verbose && 84 | console.log(" %s %s -> %s", method.toUpperCase(), url, key); 85 | } 86 | } 87 | 88 | // mount the app 89 | parent.use(app); 90 | }); 91 | }; 92 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bia", 3 | "version": "3.2.0", 4 | "description": "### Período do evento: 31/03 a 06/04/2025 (Online e ao vivo às 20h)", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "jest tests/unit", 8 | "start": "node server", 9 | "start_db": "node config/database.js" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/henrylle/bia.git" 14 | }, 15 | "author": "", 16 | "license": "ISC", 17 | "bugs": { 18 | "url": "https://github.com/henrylle/bia/issues" 19 | }, 20 | "homepage": "https://github.com/henrylle/bia#readme", 21 | "dependencies": { 22 | "@aws-sdk/client-secrets-manager": "^3.583.0", 23 | "@aws-sdk/client-sts": "^3.583.0", 24 | "@aws-sdk/credential-providers": "^3.583.0", 25 | "@testing-library/jest-dom": "^5.11.4", 26 | "@testing-library/react": "^11.1.0", 27 | "@testing-library/user-event": "^12.1.10", 28 | "config": "^3.3.6", 29 | "cors": "^2.8.5", 30 | "ejs": "^3.1.6", 31 | "express": "^4.17.1", 32 | "express-session": "^1.17.2", 33 | "hbs": "^4.1.2", 34 | "json-server": "^0.17.4", 35 | "method-override": "^3.0.0", 36 | "morgan": "^1.10.0", 37 | "pg": "^8.7.1", 38 | "pg-hstore": "^2.3.4", 39 | "react": "^17.0.2", 40 | "react-dom": "^17.0.2", 41 | "react-icons": "^4.2.0", 42 | "react-router-dom": "^5.3.0", 43 | "react-scripts": "^5.0.1", 44 | "sequelize": "^6.6.5", 45 | "web-vitals": "^1.0.1" 46 | }, 47 | "eslintConfig": { 48 | "extends": [ 49 | "react-app" 50 | ] 51 | }, 52 | "devDependencies": { 53 | "jest": "^27.5.1", 54 | "sequelize-cli": "^6.2.0" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /rodar_app_local_unix.sh: -------------------------------------------------------------------------------- 1 | docker compose up -d database 2 | npm install --loglevel=error 3 | npm run build --prefix client --loglevel=error 4 | npx sequelize db:migrate 5 | npm start -------------------------------------------------------------------------------- /rodar_app_local_windows.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | docker compose up -d database 3 | if %errorlevel% neq 0 exit /b %errorlevel% 4 | call npm install -g npm@latest --loglevel=error 5 | call npm install --loglevel=error 6 | call npm run build --prefix client --loglevel=error 7 | call npx sequelize db:migrate 8 | npm start 9 | -------------------------------------------------------------------------------- /scripts/criar_role_ssm.sh: -------------------------------------------------------------------------------- 1 | role_name="role-acesso-ssm" 2 | policy_name="AmazonSSMManagedInstanceCore" 3 | 4 | if aws iam get-role --role-name "$role_name" &> /dev/null; then 5 | echo "A IAM role $role_name já existe." 6 | exit 1 7 | fi 8 | 9 | aws iam create-role --role-name $role_name --assume-role-policy-document file://ec2_principal.json 10 | # Cria o perfil de instância 11 | aws iam create-instance-profile --instance-profile-name $role_name 12 | 13 | # Adiciona a função IAM ao perfil de instância 14 | aws iam add-role-to-instance-profile --instance-profile-name $role_name --role-name $role_name 15 | 16 | aws iam attach-role-policy --role-name $role_name --policy-arn arn:aws:iam::aws:policy/$policy_name -------------------------------------------------------------------------------- /scripts/ec2_principal.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [{ 4 | "Effect": "Allow", 5 | "Principal": { 6 | "Service": "ec2.amazonaws.com" 7 | }, 8 | "Action": "sts:AssumeRole" 9 | }] 10 | } -------------------------------------------------------------------------------- /scripts/ecs/unix/build.sh: -------------------------------------------------------------------------------- 1 | ECR_REGISTRY="SEU_REGISTRY" 2 | aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin $ECR_REGISTRY 3 | docker build -t bia . 4 | docker tag bia:latest $ECR_REGISTRY/bia:latest 5 | docker push $ECR_REGISTRY/bia:latest 6 | -------------------------------------------------------------------------------- /scripts/ecs/unix/check-disponibilidade.sh: -------------------------------------------------------------------------------- 1 | url="https://www.uol.com.br" 2 | docker build -t check_disponibilidade -f Dockerfile_checkdisponibilidade . 3 | docker run --rm -ti -e URL=$url check_disponibilidade 4 | -------------------------------------------------------------------------------- /scripts/ecs/unix/deploy.sh: -------------------------------------------------------------------------------- 1 | ./build.sh 2 | aws ecs update-service --cluster [SEU_CLUSTER] --service [SEU_SERVICE] --force-new-deployment -------------------------------------------------------------------------------- /scripts/ecs/unix/testar-latencia.sh: -------------------------------------------------------------------------------- 1 | URL="https://www.uol.com.br" 2 | while true; do 3 | START=$(date '+%Y-%m-%d %H:%M:%S') 4 | START_MS=$(gdate +%s%3N) 5 | 6 | # Captura todos os cabeçalhos 7 | HEADERS=$(curl -s -I -X GET $URL) 8 | 9 | # Extração dos valores desejados 10 | X_CACHE=$(echo "$HEADERS" | grep -i x-cache | awk -F ': ' '{print $2}' | tr -d '\r') 11 | CACHE_CONTROL=$(echo "$HEADERS" | grep -i cache-control | awk -F ': ' '{print $2}' | tr -d '\r') 12 | 13 | END_MS=$(gdate +%s%3N) 14 | DURATION=$((END_MS - START_MS)) 15 | 16 | # Adiciona o Cache-Control apenas se X-Cache contiver "Miss from cloudfront" 17 | if [[ "$X_CACHE" == *"Miss from cloudfront"* ]]; then 18 | X_CACHE="$X_CACHE ($CACHE_CONTROL)" 19 | fi 20 | 21 | # Exibe o log com os cabeçalhos desejados 22 | echo "$START - $DURATION ms - ${X_CACHE:-N/A}" 23 | 24 | sleep 2; 25 | done 26 | -------------------------------------------------------------------------------- /scripts/ecs/windows/build.bat: -------------------------------------------------------------------------------- 1 | aws ecr get-login-password --region us-east-1 --profile [SEU_PROFILE] | docker login --username AWS --password-stdin [SEU_ECR] 2 | docker build -t bia . 3 | docker tag bia:latest [SEU_ECR]/bia:latest 4 | docker push [SEU_ECR]/bia:latest -------------------------------------------------------------------------------- /scripts/ecs/windows/build_rodando_powershell.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/henrylle/bia/ee589a0a89aae86802df7797d2c2eaa9def066dd/scripts/ecs/windows/build_rodando_powershell.PNG -------------------------------------------------------------------------------- /scripts/ecs/windows/check-disponibilidade.bat: -------------------------------------------------------------------------------- 1 | set url="https://www.uol.com.br" 2 | docker build -t check_disponibilidade -f Dockerfile_checkdisponibilidade . 3 | docker run --rm -ti -e URL=%url% check_disponibilidade 4 | -------------------------------------------------------------------------------- /scripts/ecs/windows/deploy.bat: -------------------------------------------------------------------------------- 1 | call build.bat 2 | aws ecs update-service --cluster [SEU_CLUSTER] --service [SEU_SERVICE] --force-new-deployment --profile [SEU_PROFILE] 3 | -------------------------------------------------------------------------------- /scripts/lancar_ec2_zona_a.sh: -------------------------------------------------------------------------------- 1 | vpc_id=$(aws ec2 describe-vpcs --filters Name=isDefault,Values=true --query "Vpcs[0].VpcId" --output text) 2 | subnet_id=$(aws ec2 describe-subnets --filters Name=vpc-id,Values=$vpc_id Name=availabilityZone,Values=us-east-1a --query "Subnets[0].SubnetId" --output text) 3 | security_group_id=$(aws ec2 describe-security-groups --group-names "bia-dev" --query "SecurityGroups[0].GroupId" --output text 2>/dev/null) 4 | 5 | if [ -z "$security_group_id" ]; then 6 | echo ">[ERRO] Security group bia-dev não foi criado na VPC $vpc_id" 7 | exit 1 8 | fi 9 | 10 | aws ec2 run-instances --image-id ami-02f3f602d23f1659d --count 1 --instance-type t3.micro \ 11 | --security-group-ids $security_group_id --subnet-id $subnet_id --associate-public-ip-address \ 12 | --block-device-mappings '[{"DeviceName":"/dev/xvda","Ebs":{"VolumeSize":15,"VolumeType":"gp2"}}]' \ 13 | --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=bia-dev}]' \ 14 | --iam-instance-profile Name=role-acesso-ssm --user-data file://user_data_ec2_zona_a.sh 15 | -------------------------------------------------------------------------------- /scripts/ligar_bia_local.sh: -------------------------------------------------------------------------------- 1 | nome="bia-dev" 2 | instance_id=$(aws ec2 describe-instances --query 'Reservations[].Instances[].InstanceId' --filters "Name=tag:Name,Values=$nome" --output text) 3 | aws ec2 start-instances --instance-ids $instance_id 4 | -------------------------------------------------------------------------------- /scripts/parar_bia_local.sh: -------------------------------------------------------------------------------- 1 | nome="bia-dev" 2 | instance_id=$(aws ec2 describe-instances --query 'Reservations[].Instances[].InstanceId' --filters "Name=tag:Name,Values=$nome" --output text) 3 | aws ec2 stop-instances --instance-ids $instance_id 4 | -------------------------------------------------------------------------------- /scripts/setup_bia_dev_ubuntu_ui.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sudo apt-get -y update 3 | 4 | # INSTALANDO DOCKER 5 | sudo apt-get install -y ca-certificates curl gnupg lsb-release 6 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --batch --yes --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg 7 | echo \ 8 | "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ 9 | $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null 10 | sudo apt-get -y update 11 | sudo apt-get install -y docker-ce docker-ce-cli containerd.io 12 | 13 | # Startando e habilitando docker para já iniciar ativo 14 | sudo systemctl enable docker.service 15 | sudo systemctl enable containerd.service 16 | 17 | # Instalando docker-compose 18 | sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 19 | sudo chmod +x /usr/local/bin/docker-compose 20 | 21 | # Instalando o Node 22 | sudo curl -fsSL https://deb.nodesource.com/setup_14.x | sudo -E bash - 23 | sudo apt-get install -y nodejs 24 | # Atualizando versao do NPM 25 | sudo npm install -g npm@latest --loglevel=error 26 | 27 | # Instalando AWS CLI 28 | # Pre-requisito (unzip) 29 | sudo apt-get install unzip -y 30 | 31 | # AWS CLI (Install) 32 | sudo curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" 33 | sudo unzip awscliv2.zip 34 | sudo ./aws/install 35 | 36 | # Configurando permissão no docker para não ter que ficar usando root 37 | sudo usermod -aG docker ubuntu 38 | newgrp docker 39 | 40 | 41 | -------------------------------------------------------------------------------- /scripts/setup_cloudshell_ssm.sh: -------------------------------------------------------------------------------- 1 | curl "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/linux_64bit/session-manager-plugin.rpm" -o "session-manager-plugin.rpm" 2 | sudo yum install -y session-manager-plugin.rpm -------------------------------------------------------------------------------- /scripts/setup_ui_ubuntu.sh: -------------------------------------------------------------------------------- 1 | # INSTALANDO UI 2 | sudo apt update -y && \ 3 | sudo apt upgrade -y && \ 4 | sudo apt install xfce4 xfce4-goodies -y 5 | 6 | # INSTALANDO CHROME REMOTE DESKTOP 7 | wget https://dl.google.com/linux/direct/chrome-remote-desktop_current_amd64.deb && \ 8 | sudo apt install ./chrome-remote-desktop_current_amd64.deb -y 9 | 10 | # DANDO PERMISSÕES NA PASTA 11 | sudo chmod 777 /home/ubuntu/.config/ -------------------------------------------------------------------------------- /scripts/setup_vscode+chrome.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Instalando VS CODE 4 | sudo snap install --classic code 5 | 6 | #Instalando Chrome 7 | wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb 8 | sudo dpkg -i google-chrome-stable_current_amd64.deb -------------------------------------------------------------------------------- /scripts/start-session-bash.sh: -------------------------------------------------------------------------------- 1 | INSTANCE_ID=$1 2 | echo "Conectando na instancia $INSTANCE_ID" 3 | aws ssm start-session --target $INSTANCE_ID --document-name AWS-StartInteractiveCommand --parameters command="bash -l" -------------------------------------------------------------------------------- /scripts/teste: -------------------------------------------------------------------------------- 1 | 7IvF8jYZK36OMfcvCMc 2 | -------------------------------------------------------------------------------- /scripts/user_data_ec2_zona_a.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Instalar Docker e Git 4 | sudo yum update -y 5 | sudo yum install git -y 6 | sudo yum install docker -y 7 | sudo usermod -a -G docker ec2-user 8 | sudo usermod -a -G docker ssm-user 9 | id ec2-user ssm-user 10 | sudo newgrp docker 11 | 12 | #Ativar docker 13 | sudo systemctl enable docker.service 14 | sudo systemctl start docker.service 15 | 16 | #Instalar docker compose 2 17 | sudo mkdir -p /usr/local/lib/docker/cli-plugins 18 | sudo curl -SL https://github.com/docker/compose/releases/download/v2.23.3/docker-compose-linux-x86_64 -o /usr/local/lib/docker/cli-plugins/docker-compose 19 | sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose 20 | 21 | 22 | #Adicionar swap 23 | sudo dd if=/dev/zero of=/swapfile bs=128M count=32 24 | sudo chmod 600 /swapfile 25 | sudo mkswap /swapfile 26 | sudo swapon /swapfile 27 | sudo echo "/swapfile swap swap defaults 0 0" >> /etc/fstab 28 | 29 | 30 | #Instalar node e npm 31 | curl -fsSL https://rpm.nodesource.com/setup_21.x | sudo bash - 32 | sudo yum install -y nodejs -------------------------------------------------------------------------------- /scripts/validar_recursos_zona_a.sh: -------------------------------------------------------------------------------- 1 | vpc_id=$(aws ec2 describe-vpcs --filters Name=isDefault,Values=true --query "Vpcs[0].VpcId" --output text 2>/dev/null) 2 | if [ $? -eq 0 ]; then 3 | echo "[OK] Tudo certo com a VPC" 4 | else 5 | echo ">[ERRO] Tenho um problema ao retornar a VPC default. Será se ela existe?" 6 | fi 7 | 8 | subnet_id=$(aws ec2 describe-subnets --filters Name=vpc-id,Values=$vpc_id Name=availabilityZone,Values=us-east-1a --query "Subnets[0].SubnetId" --output text 2>/dev/null) 9 | if [ $? -eq 0 ]; then 10 | echo "[OK] Tudo certo com a Subnet" 11 | else 12 | echo ">[ERRO] Tenho um problema ao retornar a subnet da zona a. Será se existe uma subnet na zona A?" 13 | fi 14 | 15 | security_group_id=$(aws ec2 describe-security-groups --group-names "bia-dev" --query "SecurityGroups[0].GroupId" --output text 2>/dev/null) 16 | if [ $? -eq 0 ]; then 17 | echo "[OK] Security Group bia-dev foi criado" 18 | 19 | # Validar inbound rule para o security group 'bia-dev' 20 | inbound_rule=$(aws ec2 describe-security-groups --group-ids $security_group_id --filters "Name=ip-permission.from-port,Values=3001" --filters "Name=ip-permission.cidr,Values=0.0.0.0/0" --output text) 21 | 22 | if [ -n "$inbound_rule" ]; then 23 | echo " [OK] Regra de entrada está ok" 24 | else 25 | echo " >[ERRO] Regra de entrada para a porta 3001 não encontrada ou não está aberta para o mundo todo. Reveja a aula do Henrylle" 26 | fi 27 | 28 | # Validar outbound rule para o security group 'bia-dev' 29 | outobund_rule=$(aws ec2 describe-security-groups --group-ids $security_group_id --query "SecurityGroups[0].IpPermissionsEgress[?IpProtocol=='-1' && IpRanges[0].CidrIp=='0.0.0.0/0']" --output text) 30 | 31 | if [ -n "$outobund_rule" ]; then 32 | echo " [OK] Regra de saída está correta" 33 | else 34 | echo " >[ERRO] Regra de saída para o mundo não encontrada. Reveja a aula do Henrylle" 35 | fi 36 | else 37 | echo ">[ERRO] Não achei o security group bia-dev. Ele foi criado?" 38 | fi 39 | 40 | if aws iam get-role --role-name role-acesso-ssm &>/dev/null; then 41 | echo "[OK] Tudo certo com a role 'role-acesso-ssm'" 42 | else 43 | echo ">[ERRO] A role 'role-acesso-ssm' não existe" 44 | fi 45 | -------------------------------------------------------------------------------- /scripts_evento/README.md: -------------------------------------------------------------------------------- 1 | ## Nova Localização do Conteúdo 2 | 3 | O conteúdo desta seção foi movido para [**scripts/ecs**](https://github.com/henrylle/bia/tree/main/scripts/ecs). 4 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const app = require("./config/express")(); 2 | const port = app.get("port"); 3 | 4 | // RODANDO NOSSA APLICAÇÃO NA PORTA SETADA 5 | 6 | app.listen(port, () => { 7 | console.log(`Servidor rodando na porta ${port}`); 8 | }); 9 | -------------------------------------------------------------------------------- /tests/unit/controllers/versao.test.js: -------------------------------------------------------------------------------- 1 | const versaoController = require('../../../api/controllers/versao'); 2 | 3 | describe('Versao Controller', () => { 4 | // Mock para simular o objeto req e res 5 | const req = {}; 6 | const res = { 7 | send: jest.fn(), 8 | }; 9 | 10 | beforeEach(() => { 11 | jest.clearAllMocks(); 12 | }); 13 | 14 | test('get deve retornar a string de resposta correta', () => { 15 | // Chama a função retornada pelo controller para obter o objeto controller 16 | const { get } = versaoController(); 17 | // Chama o método get do objeto controller 18 | get(req, res); 19 | 20 | expect(res.send).toHaveBeenCalledWith('Bia 2.0.0'); 21 | }); 22 | 23 | test('get deve retornar a string de resposta correta quando VERSAO_API não está definido', () => { 24 | // Simula o cenário onde VERSAO_API não está definido 25 | delete process.env.VERSAO_API; 26 | 27 | // Chama a função retornada pelo controller para obter o objeto controller 28 | const { get } = versaoController(); 29 | // Chama o método get do objeto controller 30 | get(req, res); 31 | 32 | expect(res.send).toHaveBeenCalledWith('Bia 2.0.0'); 33 | }); 34 | 35 | test('get deve retornar a string de resposta correta quando VERSAO_API está definido', () => { 36 | // Simula o cenário onde VERSAO_API está definido 37 | process.env.VERSAO_API = '1.0.0'; 38 | 39 | // Chama a função retornada pelo controller para obter o objeto controller 40 | const { get } = versaoController(); 41 | // Chama o método get do objeto controller 42 | get(req, res); 43 | 44 | expect(res.send).toHaveBeenCalledWith('Bia 1.0.0'); 45 | }); 46 | }); --------------------------------------------------------------------------------