Skip to content

droy41259/Airbnb

Repository files navigation

Airbnb Clone Notes

This application is a simple Express + MongoDB Airbnb-style clone that renders EJS templates and stores listings and reviews in MongoDB. The guide below captures the basics for bootstrapping and then walks through a recommended authentication stack for the project.

Quick Start

  1. Install dependencies once: npm install.
  2. Make sure MongoDB is running locally (default connection string lives in app.js).
  3. Launch the dev server: node app.js (defaults to port 8080).

Authentication Blueprint

Authentication is not wired in yet, but the project already includes express-session, so the pieces below reuse it to add username/password login. The snippets assume CommonJS modules to match the rest of the repo.

1. Create a User model

// models/user.js
const mongoose = require("mongoose");
const bcrypt = require("bcrypt");

const userSchema = new mongoose.Schema({
  username: { type: String, required: true, unique: true, trim: true },
  email: { type: String, required: true, unique: true, lowercase: true },
  passwordHash: { type: String, required: true },
});

userSchema.statics.register = async function ({ username, email, password }) {
  const passwordHash = await bcrypt.hash(password, 12);
  return this.create({ username, email, passwordHash });
};

userSchema.methods.validatePassword = function (password) {
  return bcrypt.compare(password, this.passwordHash);
};

module.exports = mongoose.model("User", userSchema);

2. Wire session + flash primitives

Add flash-style helpers once after the session middleware in app.js:

const flash = require("connect-flash");
app.use(flash());

app.use((req, res, next) => {
  res.locals.currentUserId = req.session.userId;
  res.locals.success = req.flash("success");
  res.locals.error = req.flash("error");
  next();
});

If you plan to deploy or restart the server often, swap the in-memory session store for MongoDB: npm install connect-mongo and pass a store option into session(sessionOptions).

3. Add authentication routes

Create routes/auth.js for register/login/logout flows:

const express = require("express");
const router = express.Router();
const User = require("../models/user");

router.get("/register", (req, res) => res.render("auth/register"));
router.post("/register", async (req, res, next) => {
  try {
    const user = await User.register(req.body);
    req.session.userId = user._id;
    req.flash("success", "Welcome!");
    res.redirect("/listings");
  } catch (err) {
    next(err);
  }
});

router.get("/login", (req, res) => res.render("auth/login"));
router.post("/login", async (req, res, next) => {
  try {
    const user = await User.findOne({ username: req.body.username });
    if (!user || !(await user.validatePassword(req.body.password))) {
      req.flash("error", "Invalid credentials");
      return res.redirect("/login");
    }
    req.session.userId = user._id;
    req.flash("success", "Logged in");
    res.redirect("/listings");
  } catch (err) {
    next(err);
  }
});

router.post("/logout", (req, res) => {
  req.session.userId = null;
  req.flash("success", "Logged out");
  res.redirect("/listings");
});

module.exports = router;

Mount it in app.js with app.use("/", require("./routes/auth"));.

4. Guard routes with middleware

Drop a reusable guard (for example in utils/auth.js):

module.exports.isLoggedIn = (req, res, next) => {
  if (!req.session.userId) {
    req.flash("error", "You must be signed in first.");
    return res.redirect("/login");
  }
  next();
};

Use the guard anywhere privileged actions happen, e.g. wrap the /listings/new, POST /listings, /listings/:id/edit, update, and delete handlers.

5. Associate listings with owners (optional but recommended)

Add an owner field to the listing schema:

owner: {
  type: mongoose.Schema.Types.ObjectId,
  ref: "User",
  required: true,
},

When creating a listing, set listing.owner = req.session.userId, and expose a helper that ensures only the owner can edit or delete.

6. Add basic EJS forms

Create simple views under views/auth/ for register/login with method="POST" and fields username, email, and password. Include a logout <form action="/logout" method="POST">.

7. Error handling tips

  • Use Joi to validate registration and login payloads before calling the model.
  • Handle duplicate key errors (Mongo code 11000) to display friendly “username taken” flashes.
  • Keep the session secret and MongoDB credentials in environment variables for production.

With these pieces in place, the application gains session-backed authentication and route protection without introducing a heavier framework. Adjust hashing rounds, session cookie attributes, and CSRF protection to fit your deployment environment.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors