├── .env ├── README.md ├── controllers ├── createPost.js ├── createUser.js ├── getPosts.js ├── homePage.js ├── login.js ├── loginStore.js ├── logout.js ├── postsNew.js └── userStore.js ├── index.js ├── middleware ├── auth.js ├── redirect.js └── storePost.js ├── models ├── Post.js └── User.js ├── package-lock.json ├── package.json ├── public ├── assets │ ├── favicon.ico │ └── img │ │ ├── about-bg.jpg │ │ ├── contact-bg.jpg │ │ ├── home-bg.jpg │ │ ├── post-bg.jpg │ │ └── post-sample-image.jpg ├── css │ └── styles.css ├── js │ └── scripts.js └── posts │ ├── + (3).png │ ├── photo_2021-11-18_22-28-27.jpg │ ├── photo_2021-11-20_16-01-01.jpg │ ├── photo_2021-11-20_16-01-05.jpg │ ├── photo_2021-11-20_16-01-07.jpg │ └── Дизайн без названия (2).png └── views ├── create.edge ├── index.edge ├── layouts └── app.edge ├── login.edge ├── not_found.edge ├── post.edge └── register.edge /.env: -------------------------------------------------------------------------------- 1 | MongoUrl='mongodb+srv://samar:zozmS9hwVNIpdsGr@cluster0.bbfkm.mongodb.net/node-blog' -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NodeJS-Blog 2 | Demo https://blog-node-rest-api.herokuapp.com/ 3 | 4 | Description: A large static online store and a complex REST API application. The project includes a huge amount of functions in which users can buy goods, sell or only show description and compare price with others. For every user having a profile page with this can change any information or add an avatar. If you add some goods with wrong information, it is no problem to change it. You can see more in the demo website, link below. 5 | -------------------------------------------------------------------------------- /controllers/createPost.js: -------------------------------------------------------------------------------- 1 | const Post = require("../models/Post"); 2 | const path = require("path"); 3 | 4 | module.exports = (req, res) => { 5 | const {image} = req.files; 6 | image.mv(path.resolve(__dirname, "..", "public/posts", image.name), (err) => { 7 | if(err) { 8 | console.log(err) 9 | } 10 | Post.create({...req.body, image: `/posts/${image.name}`, author: req.session.userId}, (err, post) => { 11 | res.redirect('/'); 12 | }) 13 | }) 14 | } -------------------------------------------------------------------------------- /controllers/createUser.js: -------------------------------------------------------------------------------- 1 | module.exports = (req, res) => { 2 | res.render("register", { 3 | errors: req.flash("registrationError"), 4 | data: req.flash("data")[0] 5 | }); 6 | } -------------------------------------------------------------------------------- /controllers/getPosts.js: -------------------------------------------------------------------------------- 1 | const Post = require("../models/Post"); 2 | 3 | module.exports = async (req, res) => { 4 | const post = await Post.findById(req.params.id).populate("author", "username"); 5 | res.render("post", {post}) 6 | } -------------------------------------------------------------------------------- /controllers/homePage.js: -------------------------------------------------------------------------------- 1 | const Post = require("../models/Post"); 2 | 3 | module.exports = async (req, res) => { 4 | console.log(req.session); 5 | const posts = await Post.find().populate("author", "username"); 6 | console.log(posts); 7 | res.render("index", {posts}); 8 | } -------------------------------------------------------------------------------- /controllers/login.js: -------------------------------------------------------------------------------- 1 | module.exports = (req, res) => { 2 | res.render("login"); 3 | } -------------------------------------------------------------------------------- /controllers/loginStore.js: -------------------------------------------------------------------------------- 1 | const bcrypt = require('bcrypt') 2 | const User = require('../models/User') 3 | 4 | module.exports = (req, res) => { 5 | const { email, password } = req.body; 6 | User.findOne({ email }, async (error, user) => { 7 | if (user) { 8 | const validPassword = await bcrypt.compare(password, user.password); 9 | if(validPassword) { 10 | req.session.userId = user._id; 11 | res.redirect("/"); 12 | }else{ 13 | res.redirect("/login"); 14 | } 15 | } else { 16 | return res.redirect('/login') 17 | } 18 | }) 19 | } -------------------------------------------------------------------------------- /controllers/logout.js: -------------------------------------------------------------------------------- 1 | module.exports = (req, res) => { 2 | req.session.destroy(() => { 3 | res.redirect("/"); 4 | }) 5 | } -------------------------------------------------------------------------------- /controllers/postsNew.js: -------------------------------------------------------------------------------- 1 | module.exports = (req, res) => { 2 | res.render("create"); 3 | } -------------------------------------------------------------------------------- /controllers/userStore.js: -------------------------------------------------------------------------------- 1 | const User = require("../models/User"); 2 | const bcrypt = require("bcrypt"); 3 | 4 | module.exports = (req, res) => { 5 | User.create(req.body, async (err, user) => { 6 | if(err) { 7 | const registrationError = Object.keys(err.errors).map(key => err.errors[key].message); 8 | req.flash("registrationError", registrationError); 9 | req.flash("data", req.body); 10 | 11 | return res.redirect("/reg") 12 | } 13 | const salt = await bcrypt.genSalt(10); 14 | user.password = await bcrypt.hash(user.password, salt); 15 | user.save(); 16 | res.redirect("/login"); 17 | }) 18 | } -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const expressEdge = require("express-edge"); 3 | const mongoose = require("mongoose"); 4 | const fileUpload = require("express-fileupload"); 5 | const expressSession = require("express-session"); 6 | const mongoStore = require("connect-mongo"); 7 | const connectFlash = require("connect-flash"); 8 | 9 | const homePageController = require("./controllers/homePage"); 10 | const getPostsController = require("./controllers/getPosts"); 11 | const postsNewController = require("./controllers/postsNew"); 12 | const createPostController = require("./controllers/createPost"); 13 | const createUserController = require("./controllers/createUser"); 14 | const storeUserController = require("./controllers/userStore"); 15 | const loginController = require("./controllers/login"); 16 | const loginStoreController = require("./controllers/loginStore"); 17 | const logoutController = require("./controllers/logout"); 18 | 19 | const app = express(); 20 | 21 | const storePostMiddleware = require("./middleware/storePost"); 22 | const authMiddleware = require("./middleware/auth"); 23 | const redirectIfAuth = require("./middleware/redirect"); 24 | 25 | const MongoUrl = process.env.MongoUrl 26 | 27 | mongoose.connect(MongoUrl); 28 | 29 | app.use(expressSession({ 30 | secret: "samar", 31 | store: mongoStore.create({mongoUrl: MongoUrl}) 32 | })); 33 | app.use(fileUpload()); 34 | app.use(express.static("public")); 35 | app.use(expressEdge.engine); 36 | app.use(express.json()); 37 | app.use(express.urlencoded({extended: true})); 38 | app.use(connectFlash()) 39 | 40 | app.set("views", `${__dirname}/views`); 41 | 42 | app.use((req, res, next) => { 43 | app.locals.auth = req.session.userId; 44 | next(); 45 | }) 46 | 47 | app.get("/", homePageController); 48 | app.get("/post/:id", getPostsController); 49 | app.get("/logout", authMiddleware, logoutController); 50 | app.get("/posts/new", authMiddleware, postsNewController); 51 | app.post("/posts/create", authMiddleware, storePostMiddleware, createPostController); 52 | app.get("/reg", redirectIfAuth, createUserController); 53 | app.post("/auth/reg", storeUserController); 54 | app.get("/login", redirectIfAuth, loginController); 55 | app.post("/auth/log", loginStoreController); 56 | app.use((req, res) => res.render("not_found")); 57 | 58 | app.listen(5000, () => {console.log("Server has been started on Port 5000...")}); -------------------------------------------------------------------------------- /middleware/auth.js: -------------------------------------------------------------------------------- 1 | const User = require("../models/User"); 2 | 3 | module.exports = (req, res, next) => { 4 | User.findById(req.session.userId, (err, user) => { 5 | if(err || !user) { 6 | return res.redirect("/") 7 | } 8 | next(); 9 | }) 10 | } -------------------------------------------------------------------------------- /middleware/redirect.js: -------------------------------------------------------------------------------- 1 | module.exports = (req, res, next) => { 2 | if(req.session.userId) { 3 | return res.redirect("/"); 4 | } 5 | next(); 6 | } -------------------------------------------------------------------------------- /middleware/storePost.js: -------------------------------------------------------------------------------- 1 | module.exports = (req, res, next) => { 2 | if(!(req.files && req.files.image) || !req.body.title || !req.body.description || !req.body.content) { 3 | return res.redirect("/posts/new") 4 | } 5 | next(); 6 | } 7 | -------------------------------------------------------------------------------- /models/Post.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const PostSchema = new mongoose.Schema({ 4 | title: String, 5 | description: String, 6 | content: String, 7 | author: { 8 | type: mongoose.Schema.ObjectId, 9 | ref: "User", 10 | required: true 11 | }, 12 | image: String, 13 | createdAt: { 14 | type: Date, 15 | default: new Date() 16 | } 17 | }) 18 | 19 | const Post = mongoose.model("Post", PostSchema); 20 | module.exports = Post; -------------------------------------------------------------------------------- /models/User.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | const bcrypt = require("bcrypt"); 3 | 4 | const UserSchema = mongoose.Schema({ 5 | username: { 6 | type: String, 7 | required: [true, "Please, provide your username"] 8 | }, 9 | email: { 10 | type: String, 11 | required: [true, "Please, provide your email"], 12 | unique: true 13 | }, 14 | password: { 15 | type: String, 16 | required: [true, "Please, provide your password"] 17 | } 18 | }) 19 | 20 | const User = mongoose.model("User", UserSchema); 21 | module.exports = User; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blog", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js", 8 | "dev": "nodemon index.js" 9 | }, 10 | "keywords": [], 11 | "author": "Samar Badriddinov", 12 | "license": "ISC", 13 | "dependencies": { 14 | "bcrypt": "^5.0.1", 15 | "connect-flash": "^0.1.1", 16 | "connect-mongo": "^4.6.0", 17 | "edge.js": "^5.3.2", 18 | "express": "^4.17.1", 19 | "express-edge": "^2.0.2", 20 | "express-fileupload": "^1.2.1", 21 | "express-session": "^1.17.2", 22 | "mongoose": "^6.0.13" 23 | }, 24 | "devDependencies": { 25 | "nodemon": "^2.0.15" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /public/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SameerBadriddinov/NodeJS-Blog/26ae776a76c2283ad6e361ebfa5c2443e3124fa5/public/assets/favicon.ico -------------------------------------------------------------------------------- /public/assets/img/about-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SameerBadriddinov/NodeJS-Blog/26ae776a76c2283ad6e361ebfa5c2443e3124fa5/public/assets/img/about-bg.jpg -------------------------------------------------------------------------------- /public/assets/img/contact-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SameerBadriddinov/NodeJS-Blog/26ae776a76c2283ad6e361ebfa5c2443e3124fa5/public/assets/img/contact-bg.jpg -------------------------------------------------------------------------------- /public/assets/img/home-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SameerBadriddinov/NodeJS-Blog/26ae776a76c2283ad6e361ebfa5c2443e3124fa5/public/assets/img/home-bg.jpg -------------------------------------------------------------------------------- /public/assets/img/post-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SameerBadriddinov/NodeJS-Blog/26ae776a76c2283ad6e361ebfa5c2443e3124fa5/public/assets/img/post-bg.jpg -------------------------------------------------------------------------------- /public/assets/img/post-sample-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SameerBadriddinov/NodeJS-Blog/26ae776a76c2283ad6e361ebfa5c2443e3124fa5/public/assets/img/post-sample-image.jpg -------------------------------------------------------------------------------- /public/js/scripts.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Start Bootstrap - Clean Blog v6.0.7 (https://startbootstrap.com/theme/clean-blog) 3 | * Copyright 2013-2021 Start Bootstrap 4 | * Licensed under MIT (https://github.com/StartBootstrap/startbootstrap-clean-blog/blob/master/LICENSE) 5 | */ 6 | window.addEventListener('DOMContentLoaded', () => { 7 | let scrollPos = 0; 8 | const mainNav = document.getElementById('mainNav'); 9 | const headerHeight = mainNav.clientHeight; 10 | window.addEventListener('scroll', function() { 11 | const currentTop = document.body.getBoundingClientRect().top * -1; 12 | if ( currentTop < scrollPos) { 13 | // Scrolling Up 14 | if (currentTop > 0 && mainNav.classList.contains('is-fixed')) { 15 | mainNav.classList.add('is-visible'); 16 | } else { 17 | console.log(123); 18 | mainNav.classList.remove('is-visible', 'is-fixed'); 19 | } 20 | } else { 21 | // Scrolling Down 22 | mainNav.classList.remove(['is-visible']); 23 | if (currentTop > headerHeight && !mainNav.classList.contains('is-fixed')) { 24 | mainNav.classList.add('is-fixed'); 25 | } 26 | } 27 | scrollPos = currentTop; 28 | }); 29 | }) 30 | -------------------------------------------------------------------------------- /public/posts/+ (3).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SameerBadriddinov/NodeJS-Blog/26ae776a76c2283ad6e361ebfa5c2443e3124fa5/public/posts/+ (3).png -------------------------------------------------------------------------------- /public/posts/photo_2021-11-18_22-28-27.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SameerBadriddinov/NodeJS-Blog/26ae776a76c2283ad6e361ebfa5c2443e3124fa5/public/posts/photo_2021-11-18_22-28-27.jpg -------------------------------------------------------------------------------- /public/posts/photo_2021-11-20_16-01-01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SameerBadriddinov/NodeJS-Blog/26ae776a76c2283ad6e361ebfa5c2443e3124fa5/public/posts/photo_2021-11-20_16-01-01.jpg -------------------------------------------------------------------------------- /public/posts/photo_2021-11-20_16-01-05.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SameerBadriddinov/NodeJS-Blog/26ae776a76c2283ad6e361ebfa5c2443e3124fa5/public/posts/photo_2021-11-20_16-01-05.jpg -------------------------------------------------------------------------------- /public/posts/photo_2021-11-20_16-01-07.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SameerBadriddinov/NodeJS-Blog/26ae776a76c2283ad6e361ebfa5c2443e3124fa5/public/posts/photo_2021-11-20_16-01-07.jpg -------------------------------------------------------------------------------- /public/posts/Дизайн без названия (2).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SameerBadriddinov/NodeJS-Blog/26ae776a76c2283ad6e361ebfa5c2443e3124fa5/public/posts/Дизайн без названия (2).png -------------------------------------------------------------------------------- /views/create.edge: -------------------------------------------------------------------------------- 1 | @layout('layouts.app') 2 | 3 | @section("content") 4 |
5 |
6 |
7 |
8 |
9 |

Create Post

10 | You can say everythink what do you want... 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 | @endsection 43 | 44 | @section("styles") 45 | 46 | 47 | 48 | 49 | 50 | 51 | @endsection 52 | 53 | @section("scripts") 54 | 55 | 60 | @endsection -------------------------------------------------------------------------------- /views/index.edge: -------------------------------------------------------------------------------- 1 | @layout("layouts.app") 2 | 3 | @section("content") 4 | 5 |
6 |
7 |
8 |
9 |
10 |

Clean Blog

11 | A Blog Theme by Start Bootstrap 12 |
13 |
14 |
15 |
16 |
17 | 18 |
19 |
20 |
21 | @each(post in posts) 22 | 23 |
24 | 25 |

{{post.title}}

26 |

{{post.description}}

27 |
28 | 33 |
34 | 35 |
36 | @endeach 37 | 38 | 39 |
40 |
41 |
42 | @endsection -------------------------------------------------------------------------------- /views/layouts/app.edge: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Clean Blog - Start Bootstrap Theme 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | @!section("styles") 18 | 19 | 20 | 21 | 41 | {{-- MAIN Content --}} 42 | @!section("content") 43 | 44 | 79 | 80 | 81 | 82 | 83 | @!section("scripts") 84 | 85 | 86 | -------------------------------------------------------------------------------- /views/login.edge: -------------------------------------------------------------------------------- 1 | @layout('layouts.app') 2 | 3 | @section("content") 4 |
5 |
6 |
7 |
8 |
9 |

Log In

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 | @endsection -------------------------------------------------------------------------------- /views/not_found.edge: -------------------------------------------------------------------------------- 1 | @layout("layouts.app") 2 | 3 | @section("content") 4 | 5 |
6 |
7 |
8 |
9 |
10 |

404 Page Not Found

11 | Return a home page 12 |
13 |
14 |
15 |
16 |
17 | @endsection -------------------------------------------------------------------------------- /views/post.edge: -------------------------------------------------------------------------------- 1 | @layout("layouts.app") 2 | 3 | @section("content") 4 | 5 |
6 |
7 |
8 |
9 |
10 |

{{post.title}}

11 |

{{post.description}}

12 | 13 | Posted by 14 | {{post.author.username}} 15 | {{post.createdAt.toDateString()}} 16 | 17 |
18 |
19 |
20 |
21 |
22 | 23 |
24 |
25 |
26 |
27 |

{{post.title}}

28 |

{{{post.content}}}

29 |
30 |
31 |
32 |
33 | @endsection -------------------------------------------------------------------------------- /views/register.edge: -------------------------------------------------------------------------------- 1 | @layout('layouts.app') 2 | 3 | @section("content") 4 |
5 |
6 |
7 |
8 |
9 |

Register

10 | After register you can create any post... 11 |
12 |
13 |
14 |
15 |
16 | 17 |
18 |
19 |
20 | @if(errors.length > 0) 21 |
    22 | @each(err in errors) 23 |
  • {{err}}
  • 24 | @endeach 25 |
26 | @endif 27 |
28 |
29 | 30 | 31 |
32 |
33 | 34 | 35 |
36 |
37 | 38 | 39 |
40 |
41 | 42 |
43 |
44 |
45 |
46 |
47 | @endsection --------------------------------------------------------------------------------