├── .editorConfig ├── .env.exemplos ├── .eslintrc.json ├── .github ├── dependabot.yml ├── issue_template.md └── pull_request_template.md ├── .gitignore ├── .sequelizerc ├── LICENSE ├── README.md ├── bin └── www ├── doc ├── desktop-1.png ├── desktop-2.png ├── desktop-3.png ├── desktop-4.png ├── desktop-5.png └── teste.md ├── jest.config.json ├── package-lock.json ├── package.json ├── public ├── css │ └── style.css ├── img │ ├── apple-touch-icon.png │ ├── cofferHub-logo-media.png │ ├── cofferHub-logo-mini-mini.png │ ├── cofferHub-logo-mini.png │ ├── cofferHub-logo.png │ ├── favicon.ico │ └── site.webmanifest └── scripts │ └── script.js ├── src ├── app.js ├── config │ ├── auth.js │ └── passport.js ├── controllers │ └── UserController.js ├── database │ ├── config │ │ └── database.js │ └── migrations │ │ └── 20200923001849-create-user.js ├── models │ ├── User.js │ └── index.js ├── routes │ └── index.js └── views │ ├── err │ └── index.ejs │ ├── layout │ ├── _partials │ │ ├── _footer.ejs │ │ ├── _head.ejs │ │ └── _header.ejs │ └── index.ejs │ └── page │ ├── about.ejs │ ├── auth.ejs │ ├── contact.ejs │ ├── index.ejs │ ├── login.ejs │ └── register.ejs └── test ├── sum.js └── sum.test.js /.editorConfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /.env.exemplos: -------------------------------------------------------------------------------- 1 | NODE_ENV= 2 | PORT= 3 | SESSION_SECRET_KEY= -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "node": true, 4 | "es2021": true, 5 | "jest": true 6 | }, 7 | "extends": [ 8 | "airbnb-base" 9 | ], 10 | "parserOptions": { 11 | "ecmaVersion": 12, 12 | "sourceType": "module" 13 | }, 14 | "rules": {} 15 | } 16 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "09:00" 8 | open-pull-requests-limit: 10 9 | reviewers: 10 | - Dheyson 11 | - AtilaAssuncao 12 | assignees: 13 | - AtilaAssuncao 14 | labels: 15 | - enhancement 16 | ignore: 17 | - dependency-name: sequelize 18 | versions: 19 | - 6.5.0 20 | - 6.5.1 21 | - 6.6.1 22 | - dependency-name: eslint 23 | versions: 24 | - 7.18.0 25 | - 7.19.0 26 | - 7.21.0 27 | - dependency-name: sucrase 28 | versions: 29 | - 3.17.0 30 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | ## Expected Behavior 2 | 3 | 4 | ## Actual Behavior 5 | 6 | 7 | ## Steps to Reproduce the Problem 8 | 9 | 1. 10 | 1. 11 | 1. 12 | 13 | ## Specifications 14 | 15 | - Version: 16 | - Platform: 17 | - Subsystem: 18 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. 4 | 5 | Fixes # (issue) 6 | 7 | ## Type of change 8 | 9 | Please delete options that are not relevant. 10 | 11 | - [ ] Bug fix (non-breaking change which fixes an issue) 12 | - [ ] New feature (non-breaking change which adds functionality) 13 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 14 | - [ ] This change requires a documentation update 15 | 16 | # How Has This Been Tested? 17 | 18 | Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration 19 | 20 | - [ ] Test A 21 | - [ ] Test B 22 | 23 | **Test Configuration**: 24 | * Firmware version: 25 | * Hardware: 26 | * Toolchain: 27 | * SDK: 28 | 29 | # Checklist: 30 | 31 | - [ ] My code follows the style guidelines of this project 32 | - [ ] I have performed a self-review of my own code 33 | - [ ] I have commented my code, particularly in hard-to-understand areas 34 | - [ ] I have made corresponding changes to the documentation 35 | - [ ] My changes generate no new warnings 36 | - [ ] I have added tests that prove my fix is effective or that my feature works 37 | - [ ] New and existing unit tests pass locally with my changes 38 | - [ ] Any dependent changes have been merged and published in downstream modules 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /.sequelizerc: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | module.exports = { 3 | 'config': path.resolve( __dirname, 'src', 'database' , 'config', 'database.js'), 4 | 'models-path': path.resolve( __dirname, 'src', 'models'), 5 | 'migrations-path': path.resolve( __dirname, 'src', 'database', 'migrations'), 6 | 'seeders-path': path.resolve( __dirname, 'src', 'database', 'seeders') 7 | }; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Atila 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Node.js MVC Template 2 | 3 | 4 | 5 | Photo by Jeffery Ho on Unsplash 6 | 7 | > A boilerplate of NodeJS with MVC architecture using sequelizeORM. 8 | 9 | ## Table of contents 10 | * [General info](#general-info) 11 | * [Screenshots](#screenshots) 12 | * [Technologies](#technologies) 13 | * [Structure](#structure) 14 | * [Setup](#setup) 15 | * [Features](#features) 16 | * [Contact](#contact) 17 | 18 | ## General info 19 | 20 | The main purpose of the project was to create a NodeJS template with a MVC Design Pattern. 21 | 22 | ## Screenshots 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 |
31 | 32 | ## Technologies 33 | 34 | * NodeJS - >= 13.0 35 | * Express Framework - >= ^4.17.1 36 | * ORM: Sequelize - >= ^6.6.2 37 | * BD: MySql >= 8.0.21 38 | * Template engine: EJS >= ^3.1.5 39 | * Front-end framework: MaterializeCss - ^1.0.0-rc.2 40 | 41 | ## Setup 42 | 43 | Describe how to install / setup your local environement / add link to demo version. 44 | 45 | ## Structure 46 | 47 | ``` 48 | ├── bin 49 | │ └── www 50 | │ 51 | ├── dist 52 | │ 53 | ├── public 54 | │ ├── css 55 | │ │ └── style.css 56 | │ ├── img 57 | │ │ └── favicon.ico 58 | │ └── scrits 59 | │ └── script.js 60 | │ 61 | ├── src 62 | │ ├── config 63 | │ │ ├── auth.js 64 | │ │ └── passport.js 65 | │ │ 66 | │ ├── controllers 67 | │ │ └── UserController.js 68 | │ │ 69 | │ ├── database 70 | │ │ ├── config 71 | │ │ │ └── database.js 72 | │ │ ├── migrations 73 | │ │ └── seeders 74 | │ │ 75 | │ ├── models 76 | │ │ ├── index.js 77 | │ │ └── User.js 78 | │ │ 79 | │ ├── routes 80 | │ │ └── index.js 81 | │ │ 82 | │ ├── views 83 | │ │ ├── err 84 | │ │ │ └── index.js 85 | │ │ ├── layout 86 | │ │ │ ├── _partials 87 | │ │ │ │ ├── _footer.js 88 | │ │ │ │ ├── _head.js 89 | │ │ │ │ └── _header.js 90 | │ │ │ └── index.js 91 | │ │ └── page 92 | │ │ ├── about.js 93 | │ │ ├── auth.js 94 | │ │ ├── contact.js 95 | │ │ ├── index.js 96 | │ │ ├── login.js 97 | │ │ └── register.js 98 | │ │ 99 | │ └── app.js 100 | │ 101 | ├── test 102 | │ ├── sum.js 103 | │ └── sum.test.js 104 | │ 105 | ├── .editorConfig 106 | ├── .eslintrc.json 107 | ├── .sequelizerc 108 | ├── jest.config.json 109 | ├── LICENSE 110 | ├── package.json 111 | └── README.md 112 | ``` 113 | 114 | ## Code Examples 115 | Show examples of usage: 116 | `put-your-code-here` 117 | 118 | ## Features 119 | List of features ready and TODOs for future development 120 | * Awesome feature 1 121 | * Awesome feature 2 122 | * Awesome feature 3 123 | 124 | To-do list: 125 | * Wow improvement to be done 1 126 | * Wow improvement to be done 2 127 | 128 | ## Contact 129 | Created by [CofferHub](https://github.com/CofferHub) - feel free to contact us! 130 | -------------------------------------------------------------------------------- /bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require('dotenv').config(); 4 | 5 | const ENV = process.env.NODE_ENV || 'development'; 6 | const PORT = process.env.PORT || 3000; 7 | 8 | const http = require('http'); 9 | const app = ENV === 'development' 10 | ? require('../src/app') 11 | : require('../dist/app'); 12 | 13 | const options = {}; // Http createServer configuration options 14 | 15 | const server = http.createServer(options, app.default); 16 | 17 | server.listen(PORT, () => { 18 | const serverAddress = server.address(); 19 | const bindServer = typeof serverAddress === 'string' 20 | ? 'pipe ' + serverAddress 21 | : 'port ' + serverAddress.port; 22 | console.log(`\nServer listening ${bindServer} \n`); 23 | }); -------------------------------------------------------------------------------- /doc/desktop-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CofferHub/nodejs-mvc-boilerplate/0eb0bbdf40ba86798d579a93ab8f14fc543ff2d6/doc/desktop-1.png -------------------------------------------------------------------------------- /doc/desktop-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CofferHub/nodejs-mvc-boilerplate/0eb0bbdf40ba86798d579a93ab8f14fc543ff2d6/doc/desktop-2.png -------------------------------------------------------------------------------- /doc/desktop-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CofferHub/nodejs-mvc-boilerplate/0eb0bbdf40ba86798d579a93ab8f14fc543ff2d6/doc/desktop-3.png -------------------------------------------------------------------------------- /doc/desktop-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CofferHub/nodejs-mvc-boilerplate/0eb0bbdf40ba86798d579a93ab8f14fc543ff2d6/doc/desktop-4.png -------------------------------------------------------------------------------- /doc/desktop-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CofferHub/nodejs-mvc-boilerplate/0eb0bbdf40ba86798d579a93ab8f14fc543ff2d6/doc/desktop-5.png -------------------------------------------------------------------------------- /doc/teste.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /jest.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "testRegex": "((\\.|/*.)(test))\\.js?$", 3 | "clearMocks": true 4 | } 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mvc-template", 3 | "version": "0.1.0", 4 | "description": "* Node framework: Express;\r * ORM: Sequelize;\r * BD: MySql;\r * Template engine: EJS.", 5 | "main": "./bin/www", 6 | "scripts": { 7 | "start": "node ./bin/www", 8 | "dev": "nodemon --exec sucrase-node ./bin/www", 9 | "test": "jest --config ./jest.config.json", 10 | "test:watch": "npm run test -- --watch", 11 | "lint": "eslint ./src ./test --ext .ts", 12 | "lint:fix": "eslint ./src ./test --ext .ts --fix", 13 | "clean": "rm -fr dist", 14 | "build": "sucrase ./src -d ./dist --transforms imports" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/CofferHub/nodejs-mvc-boilerplate.git" 19 | }, 20 | "author": "", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/CofferHub/nodejs-mvc-boilerplate/issues" 24 | }, 25 | "homepage": "https://github.com/CofferHub/nodejs-mvc-boilerplate#readme", 26 | "dependencies": { 27 | "bcryptjs": "^2.4.3", 28 | "body-parser": "^1.19.0", 29 | "ejs": "^3.1.6", 30 | "express": "^4.17.1", 31 | "express-ejs-layouts": "^2.5.1", 32 | "express-session": "^1.17.2", 33 | "materialize-css": "^1.0.0", 34 | "morgan": "^1.10.0", 35 | "multer": "^1.4.2", 36 | "multer-gridfs-storage": "^5.0.0", 37 | "mysql2": "^2.2.5", 38 | "passport": "^0.4.1", 39 | "passport-local": "^1.0.0", 40 | "dotenv": "^10.0.0" 41 | "sequelize": "^6.6.5", 42 | }, 43 | "devDependencies": { 44 | "eslint": "^7.22.0", 45 | "eslint-config-airbnb-base": "^14.2.1", 46 | "eslint-plugin-import": "^2.22.1", 47 | "jest": "^26.6.3", 48 | "nodemon": "^2.0.12", 49 | "sequelize-cli": "^6.2.0", 50 | "sucrase": "^3.20.0" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /public/css/style.css: -------------------------------------------------------------------------------- 1 | .blue-coffer-hub { background-color: rgb(11, 50, 119) !important;} 2 | 3 | body { 4 | display: flex; 5 | min-height: 100vh; 6 | flex-direction: column; 7 | } 8 | 9 | main { flex: 1 0 auto; } 10 | 11 | .mg-tp-0 { margin-top: 0;} 12 | .pd-tp-0 { padding-top: 0;} 13 | 14 | .box-img-logo { text-align: center; } 15 | 16 | .box-img-logo img { 17 | border-radius: 1em; 18 | width: 100px; 19 | } 20 | .box-img-logo-mini a { 21 | top: 17px; 22 | line-height: 100%; 23 | } 24 | .box-img-logo-mini img { 25 | border-radius: 0.2em; 26 | border: 1px solid antiquewhite; 27 | width: 32px; 28 | } -------------------------------------------------------------------------------- /public/img/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CofferHub/nodejs-mvc-boilerplate/0eb0bbdf40ba86798d579a93ab8f14fc543ff2d6/public/img/apple-touch-icon.png -------------------------------------------------------------------------------- /public/img/cofferHub-logo-media.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CofferHub/nodejs-mvc-boilerplate/0eb0bbdf40ba86798d579a93ab8f14fc543ff2d6/public/img/cofferHub-logo-media.png -------------------------------------------------------------------------------- /public/img/cofferHub-logo-mini-mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CofferHub/nodejs-mvc-boilerplate/0eb0bbdf40ba86798d579a93ab8f14fc543ff2d6/public/img/cofferHub-logo-mini-mini.png -------------------------------------------------------------------------------- /public/img/cofferHub-logo-mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CofferHub/nodejs-mvc-boilerplate/0eb0bbdf40ba86798d579a93ab8f14fc543ff2d6/public/img/cofferHub-logo-mini.png -------------------------------------------------------------------------------- /public/img/cofferHub-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CofferHub/nodejs-mvc-boilerplate/0eb0bbdf40ba86798d579a93ab8f14fc543ff2d6/public/img/cofferHub-logo.png -------------------------------------------------------------------------------- /public/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CofferHub/nodejs-mvc-boilerplate/0eb0bbdf40ba86798d579a93ab8f14fc543ff2d6/public/img/favicon.ico -------------------------------------------------------------------------------- /public/img/site.webmanifest: -------------------------------------------------------------------------------- 1 | {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} -------------------------------------------------------------------------------- /public/scripts/script.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CofferHub/nodejs-mvc-boilerplate/0eb0bbdf40ba86798d579a93ab8f14fc543ff2d6/public/scripts/script.js -------------------------------------------------------------------------------- /src/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // Import Models[node_modules] 3 | import express from 'express'; 4 | import bodyParser from 'body-parser'; 5 | import path from 'path'; 6 | import ejsLayouts from 'express-ejs-layouts'; 7 | import session from 'express-session'; 8 | import passport from 'passport'; 9 | import mogran from 'morgan'; 10 | 11 | // Import Models[pastas] 12 | import passportConfig from './config/passport'; 13 | import routes from './routes'; 14 | 15 | const app = express(); 16 | 17 | app.use(express.json()); 18 | 19 | // Morgan 20 | app.use(mogran('dev')); 21 | 22 | // Session 23 | app.use(session({ 24 | secret: process.env.SESSION_SECRET_KEY, 25 | resave: true, 26 | saveUninitialized: true, 27 | })); 28 | 29 | // PassPort 30 | passportConfig(passport); 31 | app.use(passport.initialize()); 32 | app.use(passport.session()); 33 | 34 | // Body Parser 35 | app.use(bodyParser.text()); 36 | app.use(bodyParser.json()); 37 | app.use(bodyParser.urlencoded({ extended: true })); 38 | 39 | // view engine setup 40 | app.use( ejsLayouts ); 41 | app.set( 'views', path.join( __dirname, 'views' )); 42 | app.set( 'view engine', 'ejs' ); 43 | 44 | // static files 45 | app.use(express.static(path.join( __dirname, '..','public'))); 46 | 47 | // Materialize 48 | app.use(express.static(path.join(__dirname , '..', 'node_modules', 'materialize-css', 'dist'))); 49 | 50 | // Rotas 51 | app.use(routes); 52 | 53 | export default app; -------------------------------------------------------------------------------- /src/config/auth.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import passport from 'passport'; 3 | 4 | const isAuthenticated = (req, res, next) => { 5 | if (req.isAuthenticated()) return next(); 6 | return res.redirect('/login'); // ADD rota de retorno caso não autenticado 7 | } 8 | 9 | const isNotAuthenticated = (req, res, next) => { 10 | if (!req.isAuthenticated()) return next(); 11 | return res.redirect('/auth'); // ADD rota de retorno caso não autenticado 12 | } 13 | 14 | const authenticateLogin = passport.authenticate('local-login' , { 15 | successRedirect: '/auth', // ADD rota de successo no login 16 | failureRedirect: '/login', // ADD rota de falha no login 17 | }); 18 | 19 | const authenticateRegister = passport.authenticate('local-register', { 20 | successRedirect: '/auth', // ADD rota de successo no register 21 | failureRedirect: '/register', // ADD rota de falha no register 22 | }); 23 | 24 | export { 25 | isAuthenticated, 26 | isNotAuthenticated, 27 | authenticateLogin, 28 | authenticateRegister 29 | }; -------------------------------------------------------------------------------- /src/config/passport.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import { Strategy as LocalStrategy } from "passport-local"; 3 | import { User } from "../models"; 4 | 5 | export default ( passport ) => { 6 | 7 | passport.use('local-login', new LocalStrategy( 8 | { 9 | usernameField: 'email', 10 | passwordField: 'password' 11 | }, 12 | (email, password, done) => { 13 | User.findOne({ where: {email} }) 14 | .then(user => { 15 | if (!user) { return done( null, false, {message: ''})} 16 | 17 | if (User.comparePassword(password, user)) 18 | return done(null, user); 19 | else 20 | return done(null, false, {message: ''}); 21 | }) 22 | .catch(err => done(null, false, {message: ''})); 23 | } 24 | )); 25 | 26 | passport.use('local-register', new LocalStrategy( 27 | { 28 | usernameField: 'email', 29 | passwordField: 'password', 30 | passReqToCallback: true 31 | }, 32 | (req, email, password, done) => { 33 | const {username} = req.body; 34 | User.create({username, email, password}) 35 | .then(user => done(null, user)) 36 | .catch(err => done(null, false, {message: ''})); 37 | } 38 | )); 39 | 40 | // passas os dados para sessão 41 | passport.serializeUser(( user, done ) => { 42 | done( null, user.id ); 43 | }); 44 | 45 | passport.deserializeUser(( id, done ) => { 46 | User.findByPk(id) 47 | .then((user) => done(null, user)) 48 | .catch((err) => done(err)); 49 | }); 50 | 51 | } 52 | 53 | -------------------------------------------------------------------------------- /src/controllers/UserController.js: -------------------------------------------------------------------------------- 1 | import {User} from "../models"; 2 | 3 | 4 | // Rotas GET 5 | const getLogin = (req , res) => { 6 | res.render('page/login', {session: false}); 7 | } 8 | 9 | const getRegister = (req, res) => { 10 | res.render('page/register', {session: false}); 11 | } 12 | 13 | const getIndex = (req, res) => { 14 | res.render('page'); 15 | } 16 | 17 | const getAbout = (req, res) => { 18 | res.render('page/about'); 19 | } 20 | 21 | const getContact = (req, res) => { 22 | res.render('page/contact'); 23 | } 24 | 25 | const getAuth = (req, res) => { 26 | res.render('page/auth'); 27 | } 28 | 29 | const getLogout = (req, res) => { 30 | req.logout(); 31 | res.redirect('/'); // ADD rota depois do logout 32 | } 33 | 34 | export default { 35 | getLogin, 36 | getRegister, 37 | getIndex, 38 | getAbout, 39 | getContact, 40 | getAuth, 41 | getLogout, 42 | }; -------------------------------------------------------------------------------- /src/database/config/database.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | development: { 3 | username: 'root', 4 | password: null, 5 | database: 'database_development', 6 | host: '127.0.0.1', 7 | dialect: 'mysql', 8 | operatorsAliases: 0, 9 | define: { 10 | timestamp: true, 11 | underscored: true 12 | }, 13 | pool: { 14 | max: 5, 15 | min: 0, 16 | acquire: 30000, 17 | idle: 10000 18 | } 19 | }, 20 | test: { 21 | username: '', 22 | password: '', 23 | database: '', 24 | host: '', 25 | dialect: '' 26 | }, 27 | production: { 28 | username: '', 29 | password: '', 30 | database: '', 31 | host: '', 32 | dialect: '' 33 | } 34 | }; -------------------------------------------------------------------------------- /src/database/migrations/20200923001849-create-user.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = { 3 | up: async (queryInterface, Sequelize) => { 4 | await queryInterface.createTable('Users', { 5 | id: { 6 | allowNull: false, 7 | autoIncrement: true, 8 | primaryKey: true, 9 | type: Sequelize.INTEGER 10 | }, 11 | username: { 12 | type: Sequelize.STRING(30), 13 | unique: true, 14 | allowNull: false, 15 | validate: { 16 | notEmpty: true, 17 | len: { 18 | args: [0, 6] 19 | } 20 | } 21 | }, 22 | email: { 23 | type: Sequelize.STRING(50), 24 | allowNull: false, 25 | unique: true, 26 | validate: { 27 | notEmpty: true, 28 | } 29 | }, 30 | password: { 31 | type: Sequelize.STRING, 32 | allowNull: false, 33 | }, 34 | password_key: { 35 | type: Sequelize.STRING(32), 36 | allowNull: false, 37 | }, 38 | created_at: { 39 | allowNull: false, 40 | type: Sequelize.DATE 41 | }, 42 | updated_at: { 43 | allowNull: false, 44 | type: Sequelize.DATE 45 | } 46 | }); 47 | }, 48 | down: async (queryInterface, Sequelize) => { 49 | await queryInterface.dropTable('Users'); 50 | } 51 | }; -------------------------------------------------------------------------------- /src/models/User.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import {Model} from 'sequelize'; 3 | import crypto from "crypto"; 4 | 5 | export default (sequelize, DataTypes) => { 6 | 7 | class User extends Model {}; 8 | 9 | User.init({ 10 | username: { 11 | type: DataTypes.STRING, 12 | validate: { 13 | notEmpty: {msg: ''} // ADD mensagem de erro 14 | } 15 | }, 16 | email: { 17 | type: DataTypes.STRING, 18 | validate: { 19 | notEmpty: {msg: ''} // ADD mensagem de erro 20 | } 21 | }, 22 | password: { 23 | type: DataTypes.STRING, 24 | validate: { 25 | notEmpty: {msg: ''} // ADD mensagem de erro 26 | } 27 | }, 28 | password_key: { 29 | type: DataTypes.STRING, 30 | validate: { 31 | notEmpty: {msg: ''} // ADD mensagem de erro 32 | } 33 | } 34 | }, { 35 | sequelize, 36 | modelName: 'User', 37 | }); 38 | 39 | User.associate = (models) => { /** define association here */ } 40 | 41 | User.beforeCreate(async (user, options) => { 42 | const saltHash = await crypto.randomBytes(32).toString(); 43 | const hashPassword = await crypto.pbkdf2Sync(user.password, saltHash, 10000, 64, 'sha512').toString('hex'); 44 | user.password = hashPassword; 45 | user.password_key = saltHash; 46 | }); 47 | 48 | User.comparePassword = async (password, user) => { 49 | const hashVerify = await crypto.pbkdf2Sync(password, user.password_key, 10000, 64, 'sha512').toString('hex'); 50 | return user.password_hash === hashVerify; 51 | } 52 | 53 | return User; 54 | }; -------------------------------------------------------------------------------- /src/models/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import fs from 'fs'; 4 | import path from 'path'; 5 | import Sequelize from 'sequelize'; 6 | import configDB from './../database/config/database'; 7 | const basename = path.basename(__filename); 8 | const env = process.env.NODE_ENV || 'development'; 9 | const config = configDB[env]; 10 | 11 | const db = {}; 12 | 13 | let sequelize; 14 | if (config.use_env_variable) { 15 | sequelize = new Sequelize(process.env[config.use_env_variable], config); 16 | } else { 17 | sequelize = new Sequelize(config.database, config.username, config.password, config); 18 | } 19 | 20 | sequelize 21 | .authenticate() 22 | .then(() => console.log('DB connection has been established successfully.')) 23 | .catch( err => console.error('Unable to connect to the database:', err)) 24 | 25 | 26 | fs 27 | .readdirSync(__dirname) 28 | .filter(file => { 29 | return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js'); 30 | }) 31 | .forEach(file => { 32 | const model = require(path.join(__dirname, file)).default(sequelize, Sequelize.DataTypes); 33 | // const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes); 34 | db[model.name] = model; 35 | }); 36 | 37 | Object 38 | .keys(db) 39 | .forEach(modelName => { 40 | if (db[modelName].associate) { 41 | db[modelName].associate(db); 42 | } 43 | }); 44 | 45 | db.sequelize = sequelize; 46 | db.Sequelize = Sequelize; 47 | 48 | module.exports = db; -------------------------------------------------------------------------------- /src/routes/index.js: -------------------------------------------------------------------------------- 1 | import {Router} from 'express'; 2 | import UserController from '../controllers/UserController'; 3 | import { 4 | isAuthenticated, 5 | isNotAuthenticated, 6 | authenticateLogin, 7 | authenticateRegister 8 | } from '../config/auth'; 9 | 10 | const router = Router(); 11 | 12 | // Rotas Get 13 | router.get('/', UserController.getIndex); 14 | router.get('/about', UserController.getAbout); 15 | router.get('/contact', UserController.getContact); 16 | 17 | router.get('/login', isNotAuthenticated, UserController.getLogin); 18 | router.get('/register', isNotAuthenticated, UserController.getRegister); 19 | router.get('/logout', UserController.getLogout); 20 | 21 | // Rota autenticada 22 | router.get('/auth', isAuthenticated, UserController.getAuth); 23 | 24 | // Rotas Post 25 | router.post('/register', authenticateRegister); 26 | router.post('/login', authenticateLogin); 27 | 28 | router.get('/error', (req,res) => { 29 | throw new Error('Erro Interno'); 30 | }) 31 | 32 | export default router; -------------------------------------------------------------------------------- /src/views/err/index.ejs: -------------------------------------------------------------------------------- 1 | 9 | 10 |

<%= message + ' ' + error.status %>:(

11 |

Sorry, but the page you were trying to view does not exist.

12 |

It looks like this was the result of either:

13 | 17 | 20 | -------------------------------------------------------------------------------- /src/views/layout/_partials/_footer.ejs: -------------------------------------------------------------------------------- 1 | <% if( true ) { %> 2 | 12 | <% } %> -------------------------------------------------------------------------------- /src/views/layout/_partials/_head.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | const config = { 3 | title: 'MVC Boilerplate', 4 | decription: 'Description here ...', 5 | abstract: 'Dbstract description here ...', 6 | keywords: 'MVC, Boilerplate, MVC Boilerplate, node, sequelize, mysql, express, passport, ejs', 7 | siteUrl: 'https://github.com/CofferHub/nodejs-mvc-boilerplate', 8 | imageUrl: '#', 9 | } 10 | %> 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | <%= config.title %> 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/views/layout/_partials/_header.ejs: -------------------------------------------------------------------------------- 1 | <% if( true ) { %> 2 | 18 | <% } %> -------------------------------------------------------------------------------- /src/views/layout/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%- include('_partials/_head.ejs'); %> 5 | 6 | 7 |
8 | <%- include('_partials/_header.ejs'); %> 9 |
10 | 11 |
12 |
13 | <%- body %> 14 |
15 |
16 | 17 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/views/page/about.ejs: -------------------------------------------------------------------------------- 1 |
2 |

About

3 |

This is the About page. You may modify the following file to customize its content:

4 | 5 |
-------------------------------------------------------------------------------- /src/views/page/auth.ejs: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |

authenticate!

5 | 6 | 7 | Logout 8 | 9 |
10 | 11 |
-------------------------------------------------------------------------------- /src/views/page/contact.ejs: -------------------------------------------------------------------------------- 1 |
2 |

Contact

3 |

4 | If you have business inquiries or other questions, please fill out the following form to contact us. Thank you. 5 |

6 | 7 |
8 |
9 |
10 |
11 |
12 | 13 | 14 |
15 |
16 |
17 |
18 | 19 | 20 |
21 |
22 |
23 |
24 | 25 | 26 |
27 |
28 | 29 |
30 |
31 | 32 | 33 |
34 |
35 |
36 | 39 |
40 |
41 |
42 |
43 | 44 |
-------------------------------------------------------------------------------- /src/views/page/index.ejs: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |

Welcome!

5 | 6 |

This is the template of the cofferHub organization, it is structured in the MVC standard and uses ESJ as the HTML rendering engine, Materializecss as the frontEnd framework and the ORM Sequelize.

7 | 8 |

It also has some features already configured like Multer and Passport

9 | 10 |
11 | 12 |
-------------------------------------------------------------------------------- /src/views/page/login.ejs: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | 8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | 17 | 18 |
19 |
20 |
21 |
22 | 23 | 24 |
25 |
26 |
27 |
28 | 32 |
33 |
34 |
35 | 38 |
39 |
40 |
41 | 44 | 45 |
46 |
47 |
-------------------------------------------------------------------------------- /src/views/page/register.ejs: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | 8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | 17 | 18 |
19 |
20 |
21 |
22 | 23 | 24 |
25 |
26 |
27 |
28 | 29 | 30 |
31 |
32 |
33 | 36 |
37 |
38 |
39 | 40 |
41 |
42 |
-------------------------------------------------------------------------------- /test/sum.js: -------------------------------------------------------------------------------- 1 | function sum(a, b) { 2 | return a + b; 3 | } 4 | 5 | module.exports = sum; 6 | -------------------------------------------------------------------------------- /test/sum.test.js: -------------------------------------------------------------------------------- 1 | const sum = require('./sum'); 2 | 3 | describe('sum function', () => { 4 | it('sums up two integers', () => { 5 | expect(sum(1, 2)).toEqual(3); 6 | }); 7 | }); 8 | --------------------------------------------------------------------------------