Skip to content
Open
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: 5 additions & 0 deletions Backend/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,23 @@ dotenv.config();
const express = require('express');
const cors = require('cors');
const app = express();
const cookieParser = require('cookie-parser');
const connectToDb = require('./db/db');
const userRoutes = require('./routes/user.routes');
const captainRoutes = require('./routes/captain.routes');

connectToDb();

app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());


app.get('/',(req,res) =>{
res.send('hello world');
});
app.use('/users', userRoutes);

app.use('/captains', captainRoutes);
module.exports = app;
1 change: 1 addition & 0 deletions Backend/controllers/captain.controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const captainModel = require('../models/captain.model');
28 changes: 25 additions & 3 deletions Backend/controllers/user.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
const userModel = require('../models/user.model');
const userService = require('../services/user.service');
const { validationResult } = require('express-validator');
const blackListTokenModel = require('../models/blacklistToken.model');


module.exports.registerUSer = async (req, res,next) => {
module.exports.registerUser = async (req, res,next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
Expand All @@ -16,7 +17,7 @@ module.exports.registerUSer = async (req, res,next) => {

const hashedPassword = await userModel.hashPassword(password);

const user = await userService.createUSer({
const user = await userService.createUser({
firstname : fullname.firstname,
lastname : fullname.lastname,
email,
Expand Down Expand Up @@ -44,8 +45,29 @@ module.exports.loginUser = async (req, res, next) => {
if(!isMatch){
return res.status(401).json({message : 'Ivalid email or password'});
}

const token = user.generateAuthToken();

res.cookie('token', token);

res.status(200).json({token, user});

}

module.exports.getUserProfile = async (req, res, next) => {
res.status(200).json(req.user);
}

module.exports.logoutUser = async (req, res, next) => {

res.clearCookie('token');

const token = req.cookies.token || req.headers.authorization?.split(' ')[1];

await blackListTokenModel.create({ token });


res.status(200).json({message: 'Logged out successfully'});


}
23 changes: 23 additions & 0 deletions Backend/middlewares/auth.middleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const userModel = require('../models/user.model');
const becrypt = require('bcrypt');
const jwt = require('jsonwebtoken');

module.exports.authUser = async (req, res, next) => {
const token = req.cookies.token || (req.headers.authorization && req.headers.authorization.split(' ')[1]);

if(!token) {
return res.status(401).json({message: 'Unauthorized'});
}

const isBlacklisted = await userModel.findOne({ token: token });

try{
const decoded = jwt.verify(token,process.env.JWT_SECRET);
const user = await userModel.findById(decoded._id);

req.user = user;
return next();
}catch(err) {
return res.status(401).json({message: 'Unauthorized'});
}
}
8 changes: 8 additions & 0 deletions Backend/models/blacklistToken.model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const mongoose = require('mongoose');

const blacklistTokenSchema = new mongoose.Schema({
token: { type: String, required: true, unique: true },
createdAt: { type: Date, default: Date.now, expires: 86400 } // 24 hours TTL
});

module.exports = mongoose.model('BlacklistToken', blacklistTokenSchema);
98 changes: 98 additions & 0 deletions Backend/models/captain.model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');


const captainSchema = new mongoose.Schema({
fullname: {
firstname: {
type: String,
required: true,
minLength: [3, 'First name should contain at least three characters'],
},
lastname: {
type: String,

minLength: [3, 'Last name should contain at least three characters'],
}
},
email: {
type: String,
required: true,
unique: true,
lowercase: true,
match: [/.+\@.+\..+/, 'Please fill a valid email address'],
},
password: {
type: String,
required: true,
select: false,
},
socketId: {
type: String,
},

status:{
type: String,
enum: ['active', 'inactive'],
default: 'inactive',
},
vehicle : {
color: {
type: String,
required: true,
minLength: [3, 'Color should contain at least three characters'],
},
plate: {
type: String,
required: true,
minLength: [3, 'Plate should contain at least three characters'],
},
capacity : {
type: Number,
required: true,
min: [1, 'Capacity should be at least 1'],

},
vehicleType: {
type: String,
required: true,
enum: ['car', 'motorcycle','auto'],


}


},
location: {
lat:{
type : Number,
},
lng : {
type : Number,
}

}

})


captainSchema.methods.generateAuthToken = function() {
const token = jwt.sign(
{ _id: this._id },
process.env.JWT_SECRET,
{ expiresIn: '24h' }
);
return token;
}

captainSchema.methods.comparePassword = async function(password) {
return await bcrypt.compare(password, this.password);
}
captainSchema.statics.hashPassword = async function(password) {
return await bcrypt.hash(password, 10);
}

const captainModel = mongoose.model('Captain', captainSchema);

module.exports = captainModel;
6 changes: 5 additions & 1 deletion Backend/models/user.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ const userSchema = new mongoose.Schema({
})

userSchema.methods.generateAuthToken = function(){
const token = jwt.sign({_id: this._id},process.env.JWT_SECRET);
const token = jwt.sign(
{ _id: this._id },
process.env.JWT_SECRET,
{ expiresIn: '24h' }
);
return token;
}

Expand Down
20 changes: 20 additions & 0 deletions Backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"description": "",
"dependencies": {
"bcrypt": "^6.0.0",
"cookie-parser": "^1.4.7",
"cors": "^2.8.5",
"dotenv": "^17.0.0",
"express": "^5.1.0",
Expand Down
19 changes: 19 additions & 0 deletions Backend/routes/captain.routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const express = require('express');
const router = express.Router();
const {body} = require('express-validator');

router.post('/register',[
body('email').isEmail().withMessage('Please enter a valid email'),
body('password').isLength({min: 6}).withMessage('Password must be at least 6 characters long'),
body('fullname.firstname').isLength({min: 3}).withMessage('First name must be at least 3 characters long'),
body('vehicle.color').isLength({min: 3}).withMessage('Color must be at least 3 characters long'),
body('vehicle.plate').isLength({min: 3}).withMessage('Plate must be at least 3 characters long'),
body('vehicle.capacity').isInt({min: 1}).withMessage('Capacity must be at least 1'),
body('vehicle.vehicleType').isIn(['car', 'motorcycle', 'auto']).withMessage('Vehicle type must be one of car, motorcycle, or auto')

],
userController.registerUser);



module.exports = router;
5 changes: 4 additions & 1 deletion Backend/routes/user.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const express = require('express');
const router = express.Router();
const {body} = require("express-validator");
const userController = require('../controllers/user.controller');
const authMiddleware = require('../middlewares/auth.middleware');
router.post('/register', [
body('fullname.firstname').isLength({min: 3}).withMessage('First name should contain at least three characters'),

Expand All @@ -10,7 +11,7 @@ router.post('/register', [


],
userController.registerUSer);
userController.registerUser);

router.post('/login', [
body('email').isEmail().withMessage('Invalid Email'),
Expand All @@ -19,6 +20,8 @@ router.post('/login', [
userController.loginUser
)

router.get('/profile',authMiddleware.authUser, userController.getUserProfile);

router.get('/logout', authMiddleware.authUser, userController.logoutUser);

module.exports = router;
33 changes: 33 additions & 0 deletions Backend/services/captain.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const captainModel = require('../models/captain.model');

module.exports.createCaptain = async ({
firstname,
lastname,
email,
password,
color,
plate,
capacity,
vehicleType,
}) => {
if (!firstname || !lastname || !email || !password || !color || !plate || !capacity || !vehicleType) {
throw new Error('All fields are required');
}

const captain = captainModel.create({
fullname: {
firstname,
lastname,
},
email,
password,
vehicle: {
color,
plate,
capacity,
vehicleType,
},
});

return captain;
};