├── public
├── favicon.png
├── img
│ ├── bc4.jpeg
│ └── screenshot.png
├── style.css
└── main.js
├── .gitignore
├── package.json
├── README.md
├── LICENSE
├── views
├── index.ejs
├── login.ejs
├── signup.ejs
├── connect-local.ejs
└── profile.ejs
├── app
├── models
│ └── user.js
└── routes.js
└── server.js
/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehfcodes/personal-auth/HEAD/public/favicon.png
--------------------------------------------------------------------------------
/public/img/bc4.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehfcodes/personal-auth/HEAD/public/img/bc4.jpeg
--------------------------------------------------------------------------------
/public/img/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehfcodes/personal-auth/HEAD/public/img/screenshot.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | lib-cov
2 | *.seed
3 | *.log
4 | *.csv
5 | *.dat
6 | *.out
7 | *.pid
8 | *.gz
9 |
10 | pids
11 | logs
12 | results
13 |
14 | npm-debug.log
15 | node_modules
16 | config
17 |
--------------------------------------------------------------------------------
/public/style.css:
--------------------------------------------------------------------------------
1 | body{
2 | padding-top:80px;
3 | word-wrap:break-word;
4 | color: green;
5 | }
6 | img{
7 | height: 200px;
8 | }
9 | main, header{
10 | text-align: center;
11 | }
12 | .messages{
13 | overflow-y: scroll;
14 | overflow-x: hidden;
15 | height: 230px;
16 | }
17 | .well{
18 | overflow: hidden;
19 | height:230px;
20 | }
21 | #username{
22 | font-weight: bold;
23 | }
24 | ul{
25 | list-style: none;
26 | }
27 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-authentication",
3 | "main": "server.js",
4 | "dependencies": {
5 | "express": "~4.14.0",
6 | "ejs": "~2.5.2",
7 | "mongoose": "~4.13.1",
8 | "passport": "~0.3.2",
9 | "passport-local": "~1.0.0",
10 | "passport-facebook": "~2.1.1",
11 | "passport-twitter": "~1.0.4",
12 | "passport-google-oauth": "~1.0.0",
13 | "connect-flash": "~0.1.1",
14 | "bcrypt-nodejs": "latest",
15 | "morgan": "~1.7.0",
16 | "body-parser": "~1.15.2",
17 | "cookie-parser": "~1.4.3",
18 | "method-override": "~2.3.6",
19 | "express-session": "~1.14.1"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Powerpuff Pals
2 | Poweruff girls forum where you can also watch the full power puff girls movie.
3 |
4 | 
5 |
6 | ## Installation
7 |
8 | 1. Clone repo
9 | 2. run `npm install`
10 |
11 | ## Usage
12 |
13 | 1. run `node server.js`
14 | 2. Navigate to `localhost:8080`
15 |
16 | ## Credit
17 | Modified from Scotch.io's auth tutorial
18 |
19 | ## How It's Made:
20 |
21 | **Tech used:** HTML, CSS, jQuery Javascript
22 |
23 | In this fullstack app, passport auth is utilized, and users can log in to discuss the power puff girls and watch the full Powerpuff Girls movie.
24 |
25 | ## Examples:
26 | Take a look at the rest of my portfolio.
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018 RC
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
13 | all 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
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/views/index.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Powerpuff Pals
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | Powerpuff Pals
15 |
16 | Sugar, spice, and everything nice these were the ingredients chosen to create the perfect little girls but Professor Utonium accidentally added an extra ingredient to the concotion -- Chemical X.
17 | Login
18 | Signup
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/models/user.js:
--------------------------------------------------------------------------------
1 | // load the things we need
2 | var mongoose = require('mongoose');
3 | var bcrypt = require('bcrypt-nodejs');
4 |
5 | // define the schema for our user model
6 | var userSchema = mongoose.Schema({
7 |
8 | local : {
9 | email : String,
10 | password : String
11 | },
12 | facebook : {
13 | id : String,
14 | token : String,
15 | name : String,
16 | email : String
17 | },
18 | twitter : {
19 | id : String,
20 | token : String,
21 | displayName : String,
22 | username : String
23 | },
24 | google : {
25 | id : String,
26 | token : String,
27 | email : String,
28 | name : String
29 | }
30 |
31 | });
32 |
33 | // generating a hash
34 | userSchema.methods.generateHash = function(password) {
35 | return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
36 | };
37 |
38 | // checking if password is valid
39 | userSchema.methods.validPassword = function(password) {
40 | return bcrypt.compareSync(password, this.local.password);
41 | };
42 |
43 | // create the model for users and expose it to our app
44 | module.exports = mongoose.model('User', userSchema);
45 |
--------------------------------------------------------------------------------
/views/login.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Powerpuff Pals
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | Login
14 | <% if (message.length > 0) { %>
15 |
16 | <% } %>
17 |
18 |
29 |
30 | Need an account? Signup
31 | Or go home .
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/views/signup.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Powerpuff Pals
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | Signup
14 | <% if (message.length > 0) { %>
15 |
18 | <% } %>
19 |
20 |
31 |
32 | Already have an account? Login
33 | Or go home .
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/views/connect-local.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Powerpuff Pals
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
Add Local Account
15 | <% if (message.length > 0) { %>
16 |
17 | <%= message %>
18 |
19 | <% } %>
20 |
21 |
32 |
33 |
Go back to profile
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | // server.js
2 |
3 | // set up ======================================================================
4 | // get all the tools we need
5 | var express = require('express');
6 | var app = express();
7 | var port = process.env.PORT || 8080;
8 | var mongoose = require('mongoose');
9 | var passport = require('passport');
10 | var flash = require('connect-flash');
11 |
12 | var morgan = require('morgan');
13 | var cookieParser = require('cookie-parser');
14 | var bodyParser = require('body-parser');
15 | var session = require('express-session');
16 |
17 | var configDB = require('./config/database.js');
18 |
19 | var db
20 |
21 | // configuration ===============================================================
22 | mongoose.connect(configDB.url, { useMongoClient: true }, (err, database) => {
23 | if (err) return console.log(err)
24 | db = database
25 | require('./app/routes.js')(app, passport, db);
26 | }); // connect to our database
27 |
28 |
29 |
30 | require('./config/passport')(passport); // pass passport for configuration
31 |
32 | // set up our express application
33 | app.use(morgan('dev')); // log every request to the console
34 | app.use(cookieParser()); // read cookies (needed for auth)
35 | app.use(bodyParser.json()); // get information from html forms
36 | app.use(bodyParser.urlencoded({ extended: true }));
37 | app.use(express.static('public'))
38 |
39 | app.set('view engine', 'ejs'); // set up ejs for templating
40 |
41 | // required for passport
42 | app.use(session({
43 | secret: 'rcbootcamp2018a', // session secret
44 | resave: true,
45 | saveUninitialized: true
46 | }));
47 | app.use(passport.initialize());
48 | app.use(passport.session()); // persistent login sessions
49 | app.use(flash()); // use connect-flash for flash messages stored in session
50 |
51 |
52 | // routes ======================================================================
53 | //require('./app/routes.js')(app, passport, db); // load our routes and pass in our app and fully configured passport
54 |
55 | // launch ======================================================================
56 | app.listen(port);
57 | console.log('The magic happens on port ' + port);
58 |
--------------------------------------------------------------------------------
/public/main.js:
--------------------------------------------------------------------------------
1 | var thumbUp = document.getElementsByClassName("fa-thumbs-up");
2 | var thumbDown = document.getElementsByClassName("fa-thumbs-down");
3 | var trash = document.getElementsByClassName("fa-trash");
4 |
5 | Array.from(thumbUp).forEach(function(element) {
6 | element.addEventListener('click', function(){
7 | const name = this.parentNode.parentNode.childNodes[1].innerText
8 | const msg = this.parentNode.parentNode.childNodes[3].innerText
9 | const thumbUp = parseFloat(this.parentNode.parentNode.childNodes[5].innerText)
10 | fetch('messages', {
11 | method: 'put',
12 | headers: {'Content-Type': 'application/json'},
13 | body: JSON.stringify({
14 | 'name': name,
15 | 'msg': msg,
16 | 'thumbUp':thumbUp
17 | })
18 | })
19 | .then(response => {
20 | if (response.ok) return response.json()
21 | })
22 | .then(data => {
23 | console.log(data)
24 | window.location.reload(true)
25 | })
26 | });
27 | });
28 |
29 | Array.from(thumbDown).forEach(function(element) {
30 | element.addEventListener('click', function(){
31 | const name = this.parentNode.parentNode.childNodes[1].innerText
32 | const msg = this.parentNode.parentNode.childNodes[3].innerText
33 | const thumbDown = parseFloat(this.parentNode.parentNode.childNodes[5].innerText)
34 | fetch('messagesDown', {
35 | method: 'put',
36 | headers: {'Content-Type': 'application/json'},
37 | body: JSON.stringify({
38 | 'name': name,
39 | 'msg': msg,
40 | 'thumbDown':thumbDown
41 | })
42 | })
43 | .then(response => {
44 | if (response.ok) return response.json()
45 | })
46 | .then(data => {
47 | console.log(data)
48 | window.location.reload(true)
49 | })
50 | });
51 | });
52 |
53 | Array.from(trash).forEach(function(element) {
54 | element.addEventListener('click', function(){
55 | const name = this.parentNode.parentNode.childNodes[1].innerText
56 | const msg = this.parentNode.parentNode.childNodes[3].innerText
57 | fetch('messages', {
58 | method: 'delete',
59 | headers: {
60 | 'Content-Type': 'application/json'
61 | },
62 | body: JSON.stringify({
63 | 'name': name,
64 | 'msg': msg
65 | })
66 | }).then(function (response) {
67 | window.location.reload()
68 | })
69 | });
70 | });
71 |
--------------------------------------------------------------------------------
/views/profile.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Powerpuff Pals
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | The Powerpuff Girls Movie
15 |
16 |
17 | VIDEO
18 |
19 |
20 |
24 |
25 |
26 |
27 | Local Pal
28 | <% if (user.local.email) { %>
29 |
30 | id : <%= user._id %>
31 | email : <%= user.local.email %>
32 | password : <%= user.local.password %>
33 |
34 | Delete Account
35 | <% } else { %>
36 | Connect Local
37 | <% } %>
38 |
39 |
40 |
41 | Messages
42 |
43 | <% for(var i=0; i
44 |
45 | <%= messages[i].name %>
46 | <%= messages[i].msg %>
47 | <%= messages[i].thumbUp %>
48 | <%= messages[i].trash %>
49 |
50 |
51 |
52 |
53 | <% } %>
54 |
55 | Leave a comment
56 | <% if (user.local.email) { %>
57 |
62 |
63 | <% } %>
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/app/routes.js:
--------------------------------------------------------------------------------
1 | module.exports = function(app, passport, db) {
2 |
3 | // normal routes ===============================================================
4 |
5 | // show the home page (will also have our login links)
6 | app.get('/', function(req, res) {
7 | res.render('index.ejs');
8 | });
9 |
10 | // PROFILE SECTION =========================
11 | app.get('/profile', isLoggedIn, function(req, res) {
12 | db.collection('messages').find().toArray((err, result) => {
13 | if (err) return console.log(err)
14 | res.render('profile.ejs', {
15 | user : req.user,
16 | messages: result
17 | })
18 | })
19 | });
20 |
21 | // LOGOUT ==============================
22 | app.get('/logout', function(req, res) {
23 | req.logout();
24 | res.redirect('/');
25 | });
26 |
27 | // message board routes ===============================================================
28 |
29 | app.post('/messages', (req, res) => {
30 | db.collection('messages').save({name: req.body.name, msg: req.body.msg, thumbUp: 0, thumbDown:0}, (err, result) => {
31 | if (err) return console.log(err)
32 | console.log('saved to database')
33 | res.redirect('/profile')
34 | })
35 | })
36 |
37 | app.put('/messages', (req, res) => {
38 | db.collection('messages')
39 | .findOneAndUpdate({name: req.body.name, msg: req.body.msg}, {
40 | $set: {
41 | thumbUp:req.body.thumbUp + 1
42 | }
43 | }, {
44 | sort: {_id: -1},
45 | upsert: true
46 | }, (err, result) => {
47 | if (err) return res.send(err)
48 | res.send(result)
49 | })
50 | })
51 |
52 | app.put('/messagesDown', (req, res) => {
53 | db.collection('messages')
54 | .findOneAndUpdate({name: req.body.name, msg: req.body.msg}, {
55 | $set: {
56 | thumbUp:req.body.thumbDown - 1
57 | }
58 | }, {
59 | sort: {_id: -1},
60 | upsert: true
61 | }, (err, result) => {
62 | if (err) return res.send(err)
63 | res.send(result)
64 | })
65 | })
66 |
67 | app.delete('/messages', (req, res) => {
68 | db.collection('messages').findOneAndDelete({name: req.body.name, msg: req.body.msg}, (err, result) => {
69 | if (err) return res.send(500, err)
70 | res.send('Message deleted!')
71 | })
72 | })
73 |
74 | // =============================================================================
75 | // AUTHENTICATE (FIRST LOGIN) ==================================================
76 | // =============================================================================
77 |
78 | // locally --------------------------------
79 | // LOGIN ===============================
80 | // show the login form
81 | app.get('/login', function(req, res) {
82 | res.render('login.ejs', { message: req.flash('loginMessage') });
83 | });
84 |
85 | // process the login form
86 | app.post('/login', passport.authenticate('local-login', {
87 | successRedirect : '/profile', // redirect to the secure profile section
88 | failureRedirect : '/login', // redirect back to the signup page if there is an error
89 | failureFlash : true // allow flash messages
90 | }));
91 |
92 | // SIGNUP =================================
93 | // show the signup form
94 | app.get('/signup', function(req, res) {
95 | res.render('signup.ejs', { message: req.flash('signupMessage') });
96 | });
97 |
98 | // process the signup form
99 | app.post('/signup', passport.authenticate('local-signup', {
100 | successRedirect : '/profile', // redirect to the secure profile section
101 | failureRedirect : '/signup', // redirect back to the signup page if there is an error
102 | failureFlash : true // allow flash messages
103 | }));
104 |
105 | // =============================================================================
106 | // UNLINK ACCOUNTS =============================================================
107 | // =============================================================================
108 | // used to unlink accounts. for social accounts, just remove the token
109 | // for local account, remove email and password
110 | // user account will stay active in case they want to reconnect in the future
111 |
112 | // local -----------------------------------
113 | app.get('/unlink/local', isLoggedIn, function(req, res) {
114 | var user = req.user;
115 | user.local.email = undefined;
116 | user.local.password = undefined;
117 | user.save(function(err) {
118 | res.redirect('/profile');
119 | });
120 | });
121 |
122 | };
123 |
124 | // route middleware to ensure user is logged in
125 | function isLoggedIn(req, res, next) {
126 | if (req.isAuthenticated())
127 | return next();
128 |
129 | res.redirect('/');
130 | }
131 |
--------------------------------------------------------------------------------