├── .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 |
14 | a mistyped address
15 | an out-of-date link
16 |
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 |
3 |
17 |
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 |
18 | <%- include('_partials/_footer.ejs'); %>
19 |
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 |
--------------------------------------------------------------------------------
/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 |
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 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | Email
18 |
19 |
20 |
21 |
22 |
23 | Password
24 |
25 |
26 |
27 |
28 |
29 |
30 | Remember me
31 |
32 |
33 |
34 |
35 |
36 | Login
37 |
38 |
39 |
40 |
41 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/views/page/register.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | Username
18 |
19 |
20 |
21 |
22 |
23 | Email
24 |
25 |
26 |
27 |
28 |
29 | Password
30 |
31 |
32 |
33 |
34 | Register
35 |
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 |
--------------------------------------------------------------------------------