Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance Course Recommendations Section with Thumbnails and Responsive Design #46

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion backend/.env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
DB_URI=<YOUR MONGO URI>
PORT=<YOUR PORT>


REFRESH_TOKEN_SECRET=<YOUR REFRESH TOKEN SECRET>
REFRESH_TOKEN_EXPIRY=<YOUR REFRESH TOKEN EXPIRY>
ACCESS_TOKEN_SECRET=<YOUR ACCESS TOKEN SECRET>
ACCESS_TOKEN_EXPIRY=<YOUR ACCESS TOKEN EXPIRY>
3 changes: 3 additions & 0 deletions backend/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import dotenv from 'dotenv';
import express from 'express';
import connectDB from './config/db.js';
import courseRoutes from './routes/courseRoutes.js';
import userRoutes from './routes/userRoutes.js';
import morgan from 'morgan';
dotenv.config();
const app = express();
Expand All @@ -16,9 +17,11 @@ connectDB();
// Middleware
app.use(express.json()); // For parsing application/json
app.use(morgan('dev'));
app.use(express.urlencoded({ extended: true }));

// API Routes
app.use('/api', courseRoutes);
app.use('/api/user', userRoutes);

// Handle 404
app.use((req, res) => {
Expand Down
100 changes: 100 additions & 0 deletions backend/controllers/userController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { User } from "../models/user.js";
import { asyncHandler } from "../middlewares/asyncHandler.js";
import {ApiError} from "../validations/apiErrors.js";

const generateAccessAndRefereshTokens = async (userId) => {
try {
const user = await User.findById(userId);
const accessToken = user.generateAccessToken();
const refreshToken = user.generateRefreshToken();
user.refreshToken = refreshToken;
await user.save({ validateBeforeSave: false });

return { accessToken, refreshToken };
} catch (error) {
throw new ApiError(
500, "Something went wrong while generating referesh and access token"
);
}
};

export const signupUser = asyncHandler(async (req, res) => {
const { fullName, email, username, password } = req.body;

if (
[fullName, email, username, password].some((field) => field?.trim() === "")
) {
throw new ApiError(400, "All fields are required");
}

const existUser = await User.findOne({
$or: [{ email }, { username }],
});

if (existUser) {
throw new ApiError(409, "User with email or username already exists")
}


const user = await User.create({
fullName,
email,
password,
username: username.toLowerCase(),
});

const createdUser = await User.findById(user._id).select(
"-password -refreshToken"
);

if (!createdUser) {
throw new ApiError(500, "Something went wrong while registering the user")
}

return res.status(200).json({ createdUser });
});

export const loginUser = asyncHandler(async (req, res) => {
const { email, username, password } = req.body;

if (!username && !email) {
throw new ApiError(400, "username or email is required")
}

const user = await User.findOne({
$or: [{ username }, { email }],
});

if (!user) {
throw new ApiError(404, "User does not exist")
}

const isPasswordValid = await user.isPasswordCorrect(password);

if (!isPasswordValid) {
throw new ApiError(401, "Invalid user credentials")
}

const { accessToken, refreshToken } = await generateAccessAndRefereshTokens(
user._id
);

const loggedInUser = await User.findById(user._id).select(
"-password -refreshToken"
);

const options = {
httpOnly: true,
secure: true,
};

return res
.status(200)
.cookie("accessToken", accessToken, options)
.cookie("refreshToken", refreshToken, options)
.json({
user: loggedInUser,
accessToken,
refreshToken,
});
});
13 changes: 13 additions & 0 deletions backend/middlewares/asyncHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const asyncHandler = (fn) => {
return async (req, res, next) => {
try {
await fn(req, res, next);
} catch (error) {
console.log("asyncHandler error: ", error);

}
}

}

export {asyncHandler};
75 changes: 75 additions & 0 deletions backend/models/user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import mongoose, { Schema } from "mongoose";
import jwt from "jsonwebtoken";
import bcrypt from "bcrypt";

const userSchema = new Schema(
{
username: {
type: String,
required: true,
unique: true,
lowercase: true,
trim: true,
},
email: {
type: String,
required: true,
lowercase: true,
unique: true,
trim: true,
},
password: {
type: String,
required: true,
},
fullName: {
type: String,
trim: true,
},
refreshToken: {
type: String,
},
},
{
timestamps: true,
}
);
userSchema.pre("save", async function (next) {
if (!this.isModified("password")) return next();

this.password = await bcrypt.hash(this.password, 10);
next();
});

userSchema.methods.isPasswordCorrect = async function (password) {
return await bcrypt.compare(password, this.password);
};

userSchema.methods.generateAccessToken = function () {
return jwt.sign(
{
_id: this._id,
username: this.username,
email: this.email,
fullName: this.fullName,
},
process.env.ACCESS_TOKEN_SECRET,
{
expiresIn: process.env.ACCESS_TOKEN_EXPIRY,
}
);
};

userSchema.methods.generateRefreshToken = function () {
return jwt.sign(
{
_id: this._id,
},
process.env.REFRESH_TOKEN_SECRET,
{
expiresIn: process.env.REFRESH_TOKEN_EXPIRY,
}
);
};

export const User = mongoose.model("User", userSchema);
Loading