임태민

Update Project directory

- 포스팅 구현
- 회원가입, 로그인, 로그아웃 구현
1 +var passport = require('passport');
2 +var LocalStrategy = require('passport-local').Strategy; // 1
3 +var User = require('../models/User');
4 +
5 +// serialize & deserialize User // 2
6 +passport.serializeUser(function(user, done) {
7 + done(null, user.id);
8 +});
9 +passport.deserializeUser(function(id, done) {
10 + User.findOne({_id:id}, function(err, user) {
11 + done(err, user);
12 + });
13 +});
14 +
15 +// local strategy // 3
16 +passport.use('local-login',
17 + new LocalStrategy({
18 + usernameField : 'username', // 3-1
19 + passwordField : 'password', // 3-1
20 + passReqToCallback : true
21 + },
22 + function(req, username, password, done) { // 3-2
23 + User.findOne({username:username})
24 + .select({password:1})
25 + .exec(function(err, user) {
26 + if (err) return done(err);
27 +
28 + if (user && user.authenticate(password)){ // 3-3
29 + return done(null, user);
30 + }
31 + else {
32 + req.flash('username', username);
33 + req.flash('errors', {login:'The username or password is incorrect.'});
34 + return done(null, false);
35 + }
36 + });
37 + }
38 + )
39 +);
40 +
41 +module.exports = passport;
...\ No newline at end of file ...\ No newline at end of file
1 -const express = require('express'); 1 +var express = require('express');
2 -const mongoose = require('mongoose'); 2 +var mongoose = require('mongoose');
3 -const bodyParser = require('body-parser'); 3 +var bodyParser = require('body-parser');
4 -const methodOverride = require('body-parser'); 4 +var methodOverride = require('method-override');
5 -const app = express(); 5 +var flash = require('connect-flash');
6 +var session = require('express-session');
7 +var passport = require('./config/passport');
8 +//require('./config/passport');
6 9
10 +var app = express();
7 11
8 // DB Setting 12 // DB Setting
9 mongoose.set('useNewUrlParser', true); 13 mongoose.set('useNewUrlParser', true);
...@@ -36,11 +40,32 @@ app.engine('html', require('ejs').renderFile); ...@@ -36,11 +40,32 @@ app.engine('html', require('ejs').renderFile);
36 app.use(bodyParser.json()); 40 app.use(bodyParser.json());
37 app.use(bodyParser.urlencoded({extended:true})); 41 app.use(bodyParser.urlencoded({extended:true}));
38 app.use(methodOverride('_method')); 42 app.use(methodOverride('_method'));
43 +app.use(flash());
44 +app.use(session({
45 + secret:'MySecret',
46 + resave:true,
47 + saveUninitialized:true
48 +}));
49 +
50 +
51 +
52 +// Passport
53 +app.use(passport.initialize());
54 +app.use(passport.session());
55 +
56 +
57 +// Custom Middlewares
58 +app.use(function(req,res,next){
59 + res.locals.isAuthenticated = req.isAuthenticated();
60 + res.locals.currentUser = req.user;
61 + next();
62 +});
39 63
40 64
41 // Routes 65 // Routes
42 app.use('/', require('./routes/home')); 66 app.use('/', require('./routes/home'));
43 app.use('/posts', require('./routes/posts')); 67 app.use('/posts', require('./routes/posts'));
68 +app.use('/users', require('./routes/users'))
44 69
45 70
46 // Server 71 // Server
......
1 +var mongoose = require('mongoose');
2 +var bcrypt = require('bcryptjs'); // 1
3 +
4 +// schema //1
5 +var userSchema = mongoose.Schema({
6 + username:{
7 + type:String,
8 + required:[true,'Username is required!'],
9 + match:[/^.{4,12}$/,'Should be 4-12 characters!'],
10 + trim:true,
11 + unique:true
12 + },
13 + password:{
14 + type:String,
15 + required:[true,'Password is required!'],
16 + select:false
17 + },
18 + name:{
19 + type:String,
20 + required:[true,'Name is required!'],
21 + match:[/^.{4,12}$/,'Should be 4-12 characters!'],
22 + trim:true
23 + },
24 + email:{
25 + type:String,
26 + match:[/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,'Should be a vaild email address!'],
27 + trim:true
28 + }
29 +},{
30 + toObject:{virtuals:true}
31 +});
32 +
33 +
34 +// virtuals // 2
35 +userSchema.virtual('passwordConfirmation')
36 + .get(function(){ return this._passwordConfirmation; })
37 + .set(function(value){ this._passwordConfirmation=value; });
38 +
39 +userSchema.virtual('originalPassword')
40 + .get(function(){ return this._originalPassword; })
41 + .set(function(value){ this._originalPassword=value; });
42 +
43 +userSchema.virtual('currentPassword')
44 + .get(function(){ return this._currentPassword; })
45 + .set(function(value){ this._currentPassword=value; });
46 +
47 +userSchema.virtual('newPassword')
48 + .get(function(){ return this._newPassword; })
49 + .set(function(value){ this._newPassword=value; });
50 +
51 +
52 +// password validation // 2
53 +var passwordRegex = /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,16}$/;
54 +var passwordRegexErrorMessage = 'Should be minimum 8 characters of alphabet and number combination!';
55 +userSchema.path('password').validate(function(v) {
56 + var user = this;
57 +
58 +
59 + // create user
60 + if(user.isNew){
61 + if(!user.passwordConfirmation){
62 + user.invalidate('passwordConfirmation', 'Password Confirmation is required.');
63 + }
64 +
65 + if(!passwordRegex.test(user.password)){
66 + user.invalidate('password', passwordRegexErrorMessage);
67 + }
68 + else if(user.password !== user.passwordConfirmation) {
69 + user.invalidate('passwordConfirmation', 'Password Confirmation does not matched!');
70 + }
71 + }
72 +
73 + // update user
74 + if(!user.isNew){
75 + if(!user.currentPassword){
76 + user.invalidate('currentPassword', 'Current Password is required!');
77 + }
78 + else if(!bcrypt.compareSync(user.currentPassword, user.originalPassword)){
79 + user.invalidate('currentPassword', 'Current Password is invalid!');
80 + }
81 +
82 + if(user.newPassword && !passwordRegex.test(user.newPassword)){
83 + user.invalidate("newPassword", passwordRegexErrorMessage);
84 + }
85 + else if(user.newPassword !== user.passwordConfirmation) {
86 + user.invalidate('passwordConfirmation', 'Password Confirmation does not matched!');
87 + }
88 + }
89 +});
90 +
91 +userSchema.pre('save', function (next){
92 + var user = this;
93 + if(!user.isModified('password')){ // 3-1
94 + return next();
95 + }
96 + else {
97 + user.password = bcrypt.hashSync(user.password); //3-2
98 + return next();
99 + }
100 +});
101 +
102 +// model methods // 4
103 +userSchema.methods.authenticate = function (password) {
104 + var user = this;
105 + return bcrypt.compareSync(password,user.password);
106 +};
107 +
108 +// model & export
109 +var User = mongoose.model('user',userSchema);
110 +module.exports = User;
...\ No newline at end of file ...\ No newline at end of file
This diff is collapsed. Click to expand it.
...@@ -10,10 +10,15 @@ ...@@ -10,10 +10,15 @@
10 "author": "", 10 "author": "",
11 "license": "ISC", 11 "license": "ISC",
12 "dependencies": { 12 "dependencies": {
13 + "bcryptjs": "^2.4.3",
13 "body-parser": "^1.19.0", 14 "body-parser": "^1.19.0",
15 + "connect-flash": "^0.1.1",
14 "ejs": "^3.1.6", 16 "ejs": "^3.1.6",
15 "express": "^4.17.1", 17 "express": "^4.17.1",
18 + "express-session": "^1.17.1",
16 "method-override": "^3.0.0", 19 "method-override": "^3.0.0",
17 - "mongoose": "^5.12.8" 20 + "mongoose": "^5.12.8",
21 + "passport": "^0.4.1",
22 + "passport-local": "^1.0.0"
18 } 23 }
19 } 24 }
......
1 body { 1 body {
2 - font-family: 'Open Sans', sans-serif; 2 +
3 -} 3 + }
4 - 4 + .h1 {
5 -h1 {
6 font-family: 'PT Serif', serif; 5 font-family: 'PT Serif', serif;
7 -}
...\ No newline at end of file ...\ No newline at end of file
6 + }
7 + .breadcrumb-item {
8 + font-size: 0.8em !important;
9 + }
10 + .ellipsis{
11 + display: block;
12 + width: 100%;
13 + white-space: nowrap;
14 + overflow: hidden;
15 + text-overflow: ellipsis; /* 1 */
16 + }
17 +
18 + .board-table {
19 + table-layout: fixed;
20 + }
21 + .board-table .date {
22 + width: 100px;
23 + }
24 +
25 + .post-body{
26 + white-space: pre-line; /* 2 */
27 + }
28 + .post-info{
29 + font-size: 0.8em;
30 + }
31 +
32 + .user-form {
33 + width: 400px;
34 + }
...\ No newline at end of file ...\ No newline at end of file
......
1 +$(function(){
2 + function get2digits (num){
3 + return ('0' + num).slice(-2);
4 + }
5 +
6 + function getDate(dateObj){
7 + if(dateObj instanceof Date)
8 + return dateObj.getFullYear() + '-' + get2digits(dateObj.getMonth()+1)+ '-' + get2digits(dateObj.getDate());
9 + }
10 +
11 + function getTime(dateObj){
12 + if(dateObj instanceof Date)
13 + return get2digits(dateObj.getHours()) + ':' + get2digits(dateObj.getMinutes())+ ':' + get2digits(dateObj.getSeconds());
14 + }
15 +
16 + function convertDate(){
17 + $('[data-date]').each(function(index,element){
18 + var dateString = $(element).data('date');
19 + if(dateString){
20 + var date = new Date(dateString);
21 + $(element).html(getDate(date));
22 + }
23 + });
24 + }
25 +
26 + function convertDateTime(){
27 + $('[data-date-time]').each(function(index,element){
28 + var dateString = $(element).data('date-time');
29 + if(dateString){
30 + var date = new Date(dateString);
31 + $(element).html(getDate(date)+' '+getTime(date));
32 + }
33 + });
34 + }
35 +
36 + convertDate();
37 + convertDateTime();
38 + });
...\ No newline at end of file ...\ No newline at end of file
1 -const express = require('express'); 1 +var express = require('express');
2 -const router = express.Router(); 2 +var router = express.Router();
3 +var passport = require('passport');
4 +require('../config/passport');
3 5
4 router.get('/', function(req,res){ 6 router.get('/', function(req,res){
5 res.render('home/welcome'); 7 res.render('home/welcome');
...@@ -9,4 +11,53 @@ router.get('/about', function(req,res){ ...@@ -9,4 +11,53 @@ router.get('/about', function(req,res){
9 res.render('home/about'); 11 res.render('home/about');
10 }); 12 });
11 13
14 +//Login
15 +router.get('/login', function(req,res){
16 + var username = req.flash('username')[0];
17 + var errors = req.flash('errors')[0] || {};
18 + res.render('home/login',{
19 + username:username,
20 + errors:errors
21 + });
22 +});
23 +
24 +
25 +//Post login
26 +router.post('/login',
27 + function(req,res,next){
28 + var errors = {};
29 + var isValid = true;
30 +
31 + if(!req.body.username){
32 + isValid = false;
33 + errors.username = 'Username is required!';
34 + }
35 + if(!req.body.password){
36 + isValid = false;
37 + errors.password = 'Password is required!';
38 + }
39 +
40 + if(isValid){
41 + next();
42 + }
43 + else{
44 + req.flash('errors',errors);
45 + res.redirect('/login');
46 + }
47 + },
48 + passport.authenticate('local-login', {
49 + successRedirect : '/posts',
50 + failureRedirect : '/login'
51 + }
52 +));
53 +
54 +
55 +// Logout
56 +router.get('/logout', function(req,res){
57 + req.logout();
58 + res.redirect('/');
59 +});
60 +
61 +
62 +
12 module.exports = router; 63 module.exports = router;
...\ No newline at end of file ...\ No newline at end of file
......
1 -const express = require('express'); 1 +var express = require('express');
2 -const router = express.Router(); 2 +var router = express.Router();
3 -const Post = require('../models/Post'); 3 +var Post = require('../models/Post');
4 4
5 5
6 // Post home 6 // Post home
......
1 +var express = require('express');
2 +var router = express.Router();
3 +var User = require('../models/User');
4 +
5 +// Index // 1
6 +router.get('/', function(req, res){
7 + User.find({})
8 + .sort({username:1})
9 + .exec(function(err, users){
10 + if(err) return res.json(err);
11 + res.render('users/index', {users:users});
12 + });
13 +});
14 +
15 +// New
16 +router.get('/new', function(req, res){
17 + var user = req.flash('user')[0] || {};
18 + var errors = req.flash('errors')[0] || {};
19 + res.render('users/new', {user:user, errors:errors});
20 +});
21 +
22 +// create
23 +router.post('/', function(req, res){
24 + User.create(req.body, function(err, user){
25 + if(err){
26 + req.flash('user', req.body);
27 + req.flash('errors', parseError(err));
28 + return res.redirect('/users/new');
29 + }
30 + res.redirect('/users');
31 + });
32 +});
33 +
34 +// show
35 +router.get('/:username', function(req, res){
36 + User.findOne({username:req.params.username}, function(err, user){
37 + if(err) return res.json(err);
38 + res.render('users/show', {user:user});
39 + });
40 +});
41 +
42 +// edit
43 +router.get('/:username/edit', function(req, res){
44 + var user = req.flash('user')[0];
45 + var errors = req.flash('errors')[0] || {};
46 + if(!user){
47 + User.findOne({username:req.params.username}, function(err, user){
48 + if(err) return res.json(err);
49 + res.render('users/edit', {username:req.params.username, user:user, errors:errors});
50 + });
51 + }
52 + else{
53 + res.render('users/edit', {username:req.params.username, user:user, errors:errors });
54 + }
55 +});
56 +
57 +// update
58 +router.put('/:username', function(req, res, next){
59 + User.findOne({username:req.params.username}) // 2-1
60 + .select('password') // 2-2
61 + .exec(function(err, user){
62 + if(err) return res.json(err);
63 +
64 + // update user object
65 + user.originalPassword = user.password;
66 + user.password = req.body.newPassword? req.body.newPassword : user.password; // 2-3
67 + for(var p in req.body){ // 2-4
68 + user[p] = req.body[p];
69 + }
70 +
71 + // save updated user
72 + user.save(function(err, user){
73 + if(err){
74 + req.flash('user', req.body);
75 + req.flash('errors', parseError(err));
76 + return res.redirect('/users/'+req.params.username+'/edit');
77 + }
78 + res.redirect('/users/'+user.username);
79 + });
80 + });
81 +});
82 +
83 +// destroy
84 +router.delete('/:username', function(req, res){
85 + User.deleteOne({username:req.params.username}, function(err){
86 + if(err) return res.json(err);
87 + res.redirect('/users');
88 + });
89 +});
90 +
91 +module.exports = router;
92 +
93 +function parseError(errors){
94 + var parsed = {};
95 + if(errors.name == 'ValidationError'){
96 + for(var name in errors.errors){
97 + var validationError = errors.errors[name];
98 + parsed[name] = {message:validationError.message};
99 + }
100 + }
101 + else if(errors.code == '11000' && errors.errmsg.indexOf('username') > 0){
102 + parsed.username = {message:'Already exists!'};
103 + }
104 + else {
105 + parsed.unhandled = JSON.stringify(errors);
106 + }
107 + return parsed;
108 +}
...\ No newline at end of file ...\ No newline at end of file
1 +<!DOCTYPE html>
2 +<html>
3 + <head>
4 + <%- include('../partials/head') %>
5 + </head>
6 + <body>
7 + <%- include('../partials/nav') %>
8 +
9 + <div class="container">
10 +
11 + <h3 class="mb-3">Login</h3>
12 +
13 + <form class="user-form" action="/login" method="post">
14 +
15 + <div class="form-group row">
16 + <label for="username" class="col-sm-3 col-form-label">Username</label>
17 + <div class="col-sm-9">
18 + <input type="text" id="username" name="username" value="<%= username %>" class="form-control <%= (errors.username)?'is-invalid':'' %>">
19 + <% if(errors.username){ %>
20 + <span class="invalid-feedback"><%= errors.username %></span>
21 + <% } %>
22 + </div>
23 + </div>
24 +
25 + <div class="form-group row">
26 + <label for="password" class="col-sm-3 col-form-label">Password</label>
27 + <div class="col-sm-9">
28 + <input type="password" id="password" name="password" value="" class="form-control <%= (errors.password)?'is-invalid':'' %>">
29 + <% if(errors.password){ %>
30 + <span class="invalid-feedback"><%= errors.password %></span>
31 + <% } %>
32 + </div>
33 + </div>
34 +
35 + <% if(errors.login){ %>
36 + <div class="invalid-feedback d-block"><%= errors.login %></div>
37 + <% } %>
38 +
39 + <div class="mt-3">
40 + <input class="btn btn-primary" type="submit" value="Submit">
41 + </div>
42 +
43 + </form>
44 +
45 + </div>
46 + </body>
47 +</html>
...\ No newline at end of file ...\ No newline at end of file
...@@ -13,4 +13,8 @@ ...@@ -13,4 +13,8 @@
13 <!-- my css --> 13 <!-- my css -->
14 <link rel="stylesheet" href="/css/master.css"> 14 <link rel="stylesheet" href="/css/master.css">
15 15
16 +<!-- my js -->
17 +<script src="/js/script.js"></script>
18 +
19 +
16 <title>Mapmory</title> 20 <title>Mapmory</title>
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -8,6 +8,17 @@ ...@@ -8,6 +8,17 @@
8 <ul class="navbar-nav"> 8 <ul class="navbar-nav">
9 <li class="nav-item"><a href="/" class="nav-link">Home</a></li> 9 <li class="nav-item"><a href="/" class="nav-link">Home</a></li>
10 <li class="nav-item"><a href="/about" class="nav-link">About</a></li> 10 <li class="nav-item"><a href="/about" class="nav-link">About</a></li>
11 + <li class="nav-item"><a href="/posts" class="nav-link">Posts</a></li>
12 + </ul>
13 +
14 + <ul class="navbar-nav ml-auto"> <!-- 우측 정렬 -->
15 + <% if(isAuthenticated){ %>
16 + <li class="nav-item"><a href="/users/<%= currentUser.username %>" class="nav-link">My Account</a></li>
17 + <li class="nav-item"><a href="/logout" class="nav-link">Logout</a></li>
18 + <% } else { %>
19 + <li class="nav-item"><a href="/users/new" class="nav-link">Sign Up</a></li>
20 + <li class="nav-item"><a href="/login" class="nav-link">Login</a></li>
21 + <% } %>
11 </ul> 22 </ul>
12 </div> 23 </div>
13 </div> 24 </div>
......
1 +<!DOCTYPE html>
2 +<html>
3 + <head>
4 + <%- include('../partials/head') %>
5 + </head>
6 + <body>
7 + <%- include('../partials/nav') %>
8 +
9 + <div class="container mb-3">
10 +
11 + <nav aria-label="breadcrumb">
12 + <ol class="breadcrumb p-1 pl-2 pr-2">
13 + <li class="breadcrumb-item"><a href="/">Home</a></li>
14 + <li class="breadcrumb-item"><a href="/posts">Board</a></li>
15 + <li class="breadcrumb-item"><a href="/posts/<%= post._id %>"><%= post.title %></a></li>
16 + <li class="breadcrumb-item active" aria-current="page">Edit Post</li>
17 + </ol>
18 + </nav>
19 +
20 + <form action="/posts/<%= post._id %>?_method=put" method="post">
21 +
22 + <div class="form-group">
23 + <label for="title">Title</label>
24 + <input type="text" id="title" name="title" value="<%= post.title %>" class="form-control">
25 + </div>
26 +
27 + <div class="form-group">
28 + <label for="body">Body</label>
29 + <textarea id="body" name="body" rows="5" class="form-control"><%= post.body %></textarea>
30 + </div>
31 +
32 + <div>
33 + <a class="btn btn-primary" href="/posts/<%= post._id %>">Back</a>
34 + <button type="submit" class="btn btn-primary">Submit</button>
35 + </div>
36 +
37 + </form>
38 +
39 + </div>
40 + </body>
41 +</html>
...\ No newline at end of file ...\ No newline at end of file
......
1 +<!DOCTYPE html>
2 +<html>
3 + <head>
4 + <%- include('../partials/head') %>
5 + </head>
6 + <body>
7 + <%- include('../partials/nav') %>
8 +
9 + <div class="container mb-3">
10 +
11 + <h2 class="mb-3">Board</h2>
12 +
13 + <table class="board-table table table-sm border-bottom">
14 +
15 + <thead class="thead-light">
16 + <tr>
17 + <th scope="col">Title</th>
18 + <th scope="col" class="date">Date</th>
19 + </tr>
20 + </thead>
21 +
22 + <tbody>
23 + <% if(posts == null || posts.length == 0){ %>
24 + <tr>
25 + <td colspan=2> EMPTY </td>
26 + </tr>
27 + <% } %>
28 + <% posts.forEach(function(post) { %>
29 + <tr>
30 + <td>
31 + <a href="/posts/<%= post._id %>"><div class="ellipsis"><%= post.title %></div></a>
32 + </td>
33 + <td class="date">
34 + <span data-date="<%= post.createdAt %>"></span>
35 + </td>
36 + </tr>
37 + <% }) %>
38 + </tbody>
39 +
40 + </table>
41 +
42 + <div>
43 + <a class="btn btn-primary" href="/posts/new">New</a>
44 + </div>
45 +
46 + </div>
47 + </body>
48 +</html>
...\ No newline at end of file ...\ No newline at end of file
......
1 +<!DOCTYPE html>
2 +<html>
3 + <head>
4 + <%- include('../partials/head') %>
5 + </head>
6 + <body>
7 + <%- include('../partials/nav') %>
8 +
9 + <div class="container mb-3">
10 +
11 + <nav aria-label="breadcrumb"> <!-- 1 -->
12 + <ol class="breadcrumb p-1 pl-2 pr-2">
13 + <li class="breadcrumb-item"><a href="/">Home</a></li>
14 + <li class="breadcrumb-item"><a href="/posts">Board</a></li>
15 + <li class="breadcrumb-item active" aria-current="page">New Post</li>
16 + </ol>
17 + </nav>
18 +
19 + <form action="/posts" method="post">
20 +
21 + <div class="form-group">
22 + <label for="title">Title</label>
23 + <input type="text" id="title" name="title" value="" class="form-control">
24 + </div>
25 +
26 + <div class="form-group">
27 + <label for="body">Body</label>
28 + <textarea id="body" name="body" rows="5" class="form-control"></textarea>
29 + </div>
30 +
31 + <div>
32 + <a class="btn btn-primary" href="/posts">Back</a>
33 + <button type="submit" class="btn btn-primary">Submit</button>
34 + </div>
35 +
36 + </form>
37 +
38 + </div>
39 + </body>
40 +</html>
...\ No newline at end of file ...\ No newline at end of file
......
1 +<!DOCTYPE html>
2 +<html>
3 + <head>
4 + <%- include('../partials/head') %>
5 + </head>
6 + <body>
7 + <%- include('../partials/nav') %>
8 +
9 + <div class="container mb-3">
10 +
11 + <nav aria-label="breadcrumb">
12 + <ol class="breadcrumb p-1 pl-2 pr-2">
13 + <li class="breadcrumb-item"><a href="/">Home</a></li>
14 + <li class="breadcrumb-item"><a href="/posts">Board</a></li>
15 + <li class="breadcrumb-item active" aria-current="page"><%= post.title %></li>
16 + </ol>
17 + </nav>
18 +
19 + <div class="card">
20 + <h5 class="card-header p-2"><%= post.title %></h5>
21 + <div class="row"> <!-- 1 -->
22 +
23 + <div class="col-md-7 col-lg-8 col-xl-9 order-sm-2 order-md-1"> <!-- 1 -->
24 + <div class="post-body p-2"><%= post.body %></div>
25 + </div>
26 +
27 + <div class="col-md-5 col-lg-4 col-xl-3 order-sm-1 order-md-2"> <!-- 1 -->
28 + <div class="post-info card m-2 p-2">
29 + <div><span>Created</span> : <span data-date-time="<%= post.createdAt %>"></span></div> <!-- 2 -->
30 + <% if(post.updatedAt) { %>
31 + <div><span>Updated</span> : <span data-date-time="<%= post.updatedAt %>"></span></div> <!-- 2 -->
32 + <% } %>
33 + </div>
34 + </div>
35 +
36 + </div>
37 + </div>
38 +
39 + <div class="mt-3">
40 + <a class="btn btn-primary" href="/posts">Back</a>
41 + <a class="btn btn-primary" href="/posts/<%= post._id %>/edit">Edit</a>
42 + <form action="/posts/<%= post._id %>?_method=delete" method="post" class="d-inline">
43 + <a class="btn btn-primary" href="javascript:void(0)" onclick="confirm('Do you want to delete this?')?this.parentElement.submit():null;">Delete</a>
44 + </form>
45 + </div>
46 +
47 + </div>
48 + </body>
49 +</html>
...\ No newline at end of file ...\ No newline at end of file
......
1 +<!DOCTYPE html>
2 +<html>
3 + <head>
4 + <%- include('../partials/head') %>
5 + </head>
6 + <body>
7 + <%- include('../partials/nav') %>
8 +
9 + <div class="container mb-3">
10 +
11 + <h3 class="mb-3">Edit User</h3>
12 +
13 + <form action="/users/<%= username %>?_method=put" method="post"> <!-- 1 -->
14 +
15 + <div class="form-group row">
16 + <label for="currentPassword" class="col-sm-3 col-form-label">Current Password*</label>
17 + <div class="col-sm-9 col-sm-offset-3">
18 + <input type="password" id="currentPassword" name="currentPassword" value="" class="form-control <%= (errors.currentPassword)?'is-invalid':'' %>"> <!-- 2 -->
19 + <% if(errors.currentPassword){ %> <!-- 3 -->
20 + <span class="invalid-feedback"><%= errors.currentPassword.message %></span>
21 + <% } %>
22 + </div>
23 + </div>
24 +
25 + <hr></hr>
26 +
27 + <div class="form-group row">
28 + <label for="username" class="col-sm-3 col-form-label">Username*</label>
29 + <div class="col-sm-9">
30 + <input type="text" id="username" name="username" value="<%= user.username %>" class="form-control <%= (errors.username)?'is-invalid':'' %>"> <!-- 2 -->
31 + <% if(errors.username){ %> <!-- 3 -->
32 + <span class="invalid-feedback"><%= errors.username.message %></span>
33 + <% } %>
34 + </div>
35 + </div>
36 +
37 + <div class="form-group row">
38 + <label for="name" class="col-sm-3 col-form-label">Name*</label>
39 + <div class="col-sm-9">
40 + <input type="text" id="name" name="name" value="<%= user.name %>" class="form-control <%= (errors.name)?'is-invalid':'' %>"> <!-- 2 -->
41 + <% if(errors.name){ %> <!-- 3 -->
42 + <span class="invalid-feedback"><%= errors.name.message %></span>
43 + <% } %>
44 + </div>
45 + </div>
46 +
47 + <div class="form-group row">
48 + <label for="email" class="col-sm-3 col-form-label">Email</label>
49 + <div class="col-sm-9">
50 + <input type="text" id="email" name="email" value="<%= user.email %>" class="form-control <%= (errors.email)?'is-invalid':'' %>"> <!-- 2 -->
51 + <% if(errors.email){ %> <!-- 3 -->
52 + <span class="invalid-feedback"><%= errors.email.message %></span>
53 + <% } %>
54 + </div>
55 + </div>
56 +
57 + <div class="form-group row">
58 + <label for="newPassword" class="col-sm-3 col-form-label">New Password</label>
59 + <div class="col-sm-9 col-sm-offset-3">
60 + <input type="password" id="newPassword" name="newPassword" value="" class="form-control <%= (errors.newPassword)?'is-invalid':'' %>"> <!-- 2 -->
61 + <% if(errors.newPassword){ %> <!-- 3 -->
62 + <span class="invalid-feedback"><%= errors.newPassword.message %></span>
63 + <% } %>
64 + </div>
65 + </div>
66 +
67 + <div class="form-group row">
68 + <label for="passwordConfirmation" class="col-sm-3 col-form-label">Password Confirmation</label>
69 + <div class="col-sm-9 col-sm-offset-3">
70 + <input type="password" id="passwordConfirmation" name="passwordConfirmation" value="" class="form-control <%= (errors.passwordConfirmation)?'is-invalid':'' %>"> <!-- 2 -->
71 + <% if(errors.passwordConfirmation){ %> <!-- 3 -->
72 + <span class="invalid-feedback"><%= errors.passwordConfirmation.message %></span>
73 + <% } %>
74 + </div>
75 + </div>
76 +
77 + <p>
78 + <small>*Required</small>
79 + </p>
80 +
81 + <% if(errors.unhandled){ %> <!-- 4 -->
82 + <div class="alert alert-danger">
83 + <%= errors.unhandled %>
84 + </div>
85 + <% } %>
86 +
87 + </form>
88 +
89 + </div>
90 + </body>
91 +</html>
...\ No newline at end of file ...\ No newline at end of file
1 +<!DOCTYPE html>
2 +<html>
3 + <head>
4 + <%- include('../partials/head') %>
5 + </head>
6 + <body>
7 + <%- include('../partials/nav') %>
8 +
9 + <div class="container mb-3">
10 +
11 + <h3 class="mb-3">Users</h3>
12 +
13 + <ul class="list-group">
14 + <% if(users == null || users.length == 0){ %>
15 + <li class="list-group-item"> There is no user yet.</li>
16 + <% } %>
17 + <% users.forEach(function(user) { %>
18 + <li class="list-group-item">
19 + <a href="/users/<%= user.username %>"><%= user.username %></a>
20 + </li>
21 + <% }) %>
22 + </ul>
23 +
24 + </div>
25 + </body>
26 +</html>
...\ No newline at end of file ...\ No newline at end of file
1 +<!DOCTYPE html>
2 +<html>
3 + <head>
4 + <%- include('../partials/head') %>
5 + </head>
6 + <body>
7 + <%- include('../partials/nav') %>
8 +
9 + <div class="container mb-3">
10 +
11 + <h3 class="contentBoxTop mb-3">New User</h3>
12 +
13 + <form action="/users" method="post">
14 +
15 + <div class="form-group row">
16 + <label for="username" class="col-sm-3 col-form-label">Username*</label>
17 + <div class="col-sm-9">
18 + <input type="text" id="username" name="username" value="<%= user.username %>" class="form-control <%= (errors.username)?'is-invalid':'' %>"> <!-- 1, 2 -->
19 + <% if(errors.username){ %> <!-- 3 -->
20 + <span class="invalid-feedback"><%= errors.username.message %></span>
21 + <% } %>
22 + </div>
23 + </div>
24 + <div class="form-group row">
25 + <label for="name" class="col-sm-3 col-form-label">Name*</label>
26 + <div class="col-sm-9">
27 + <input type="text" id="name" name="name" value="<%= user.name %>" class="form-control <%= (errors.name)?'is-invalid':'' %>"> <!-- 1, 2 -->
28 + <% if(errors.name){ %> <!-- 3 -->
29 + <span class="invalid-feedback"><%= errors.name.message %></span>
30 + <% } %>
31 + </div>
32 + </div>
33 + <div class="form-group row">
34 + <label for="email" class="col-sm-3 col-form-label">Email</label>
35 + <div class="col-sm-9">
36 + <input type="text" id="email" name="email" value="<%= user.email %>" class="form-control <%= (errors.email)?'is-invalid':'' %>"> <!-- 1, 2 -->
37 + <% if(errors.email){ %>
38 + <span class="invalid-feedback"><%= errors.email.message %></span>
39 + <% } %>
40 + </div>
41 + </div>
42 + <div class="form-group row">
43 + <label for="password" class="col-sm-3 col-form-label">Password*</label>
44 + <div class="col-sm-9">
45 + <input type="password" id="password" name="password" value="" class="form-control <%= (errors.password)?'is-invalid':'' %>"> <!-- 1, 2 -->
46 + <% if(errors.password){ %> <!-- 3 -->
47 + <span class="invalid-feedback"><%= errors.password.message %></span>
48 + <% } %>
49 + </div>
50 + </div>
51 + <div class="form-group row">
52 + <label for="passwordConfirmation" class="col-sm-3 col-form-label">Password Confirmation*</label>
53 + <div class="col-sm-9 col-sm-offset-3">
54 + <input type="password" id="passwordConfirmation" name="passwordConfirmation" value="" class="form-control <%= (errors.passwordConfirmation)?'is-invalid':'' %>"> <!-- 1, 2 -->
55 + <% if(errors.passwordConfirmation){ %> <!-- 3 -->
56 + <span class="invalid-feedback"><%= errors.passwordConfirmation.message %></span>
57 + <% } %>
58 + </div>
59 + </div>
60 + <p>
61 + <small>*Required</small>
62 + </p>
63 +
64 + <% if(errors.unhandled){ %> <!-- 4 -->
65 + <div class="alert alert-danger">
66 + <%= errors.unhandled %>
67 + </div>
68 + <% } %>
69 +
70 + <div class="form-group">
71 + <button type="submit" class="btn btn-primary">Submit</button>
72 + </div>
73 + </form>
74 +
75 + </div>
76 + </body>
77 +</html>
...\ No newline at end of file ...\ No newline at end of file
1 +<!DOCTYPE html>
2 +<html>
3 + <head>
4 + <%- include('../partials/head') %>
5 + </head>
6 + <body>
7 + <%- include('../partials/nav') %>
8 +
9 + <div class="container mb-3">
10 +
11 + <h3 class="contentBoxTop"><%= user.username %></h3>
12 +
13 + <form class="user-form" action="/users" method="post">
14 + <fieldset disabled>
15 + <div class="form-group row">
16 + <label for="name" class="col-sm-3 col-form-label">Name</label>
17 + <div class="col-sm-9">
18 + <input class="form-control" type="text" id="name" name="name" value="<%= user.name %>">
19 + </div>
20 + </div>
21 + <div class="form-group row">
22 + <label for="email" class="col-sm-3 col-form-label">Email</label>
23 + <div class="col-sm-9">
24 + <input class="form-control" type="text" id="email" name="email" value="<%= user.email %>">
25 + </div>
26 + </div>
27 + </fieldset>
28 + </form>
29 +
30 + <div>
31 + <a class="btn btn-primary" href="/users">Back</a>
32 + <a class="btn btn-primary" href="/users/<%= user.username %>/edit">Edit</a>
33 + <form action="/users/<%= user.username %>?_method=delete" method="post" class="d-inline">
34 + <a class="btn btn-primary" href="javascript:void(0)" onclick="confirm('Do you want to delete this?')?this.parentElement.submit():null;">Delete</a>
35 + </form>
36 + </div>
37 +
38 + </div>
39 + </body>
40 +</html>
...\ No newline at end of file ...\ No newline at end of file