Skip to content

Commit

Permalink
fix
Browse files Browse the repository at this point in the history
  • Loading branch information
praisejah-moses committed Sep 21, 2023
2 parents d3d5c4f + 970d364 commit a1add65
Show file tree
Hide file tree
Showing 17 changed files with 307 additions and 185 deletions.
6 changes: 4 additions & 2 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const errorHandlerMiddleware = require('./middlewares/error-handler');
const userRoutes = require('./routes/users');
const orgRoutes = require('./routes/orgRoutes');
const lunchRoutes = require('./routes/lunchRoutes');
const authRoutes = require('./routes/auth.route');
const sequelize = require('./db/db');

const app = express();
Expand All @@ -15,13 +16,14 @@ app.use(express.json());
app.use(helmet());
const PORT = process.env.PORT || 4000;

app.use('/api/organization', orgRoutes);
app.use('/api/', userRoutes);
app.use('/api/auth', authRoutes);
app.use('/api/organization', orgRoutes);
app.use('/api/lunch', lunchRoutes);

// Middlewares
app.use(notFound);
app.use(errorHandlerMiddleware);
app.use(notFound);

sequelize.sync().then(() => {
// Remove console.log() before production
Expand Down
143 changes: 143 additions & 0 deletions controllers/authController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/* eslint-disable camelcase */
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
const User = require('../models/user.model');
const { createCustomError } = require('../errors/custom-errors');
const Invite = require('../models/organisation_invite.model');

const secretKey = process.env.JWT_SECRET_KEY;

async function createUser(req, res, next) {
try {
const {
first_name,
last_name,
email,
phone,
password,
is_admin,
profile_pic,
org_id,
lunch_credit_balance,
refresh_token,
bank_code,
bank_name,
bank_number,
token,
} = req.body;

// Validate input data

if (!first_name || !last_name || !email || !password || !token) {
// TODO: truly validate data
throw createCustomError('Missing required fields', 400);
}

// Check if the token is valid and retrieve org_id
const invite = await Invite.findOne({ where: { token } });

if (!invite || new Date() > invite.ttl) {
throw createCustomError('Invalid or expired invitation token', 400);
}

const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(password, salt);

const user = {
first_name,
last_name,
email,
phone,
password_hash: hashedPassword,
is_admin,
profile_pic,
org_id,
lunch_credit_balance,
refresh_token,
bank_code,
bank_name,
bank_number,
};

const newUser = await User.create(user);
delete newUser.password_hash;

const userWithoutPassword = Object.assign(newUser.toJSON);
delete userWithoutPassword.password_hash;
console.log(userWithoutPassword);

return res.status(200).json({
success: true,
message: 'User registered successfully',
data: {
user: userWithoutPassword,
},
});
} catch (error) {
if (error.name === 'SequelizeUniqueConstraintError') {
// Unique constraint violation (duplicate email)
let errorMessage = error.errors[0].message;
errorMessage = errorMessage[0].toUpperCase() + errorMessage.slice(1);
next(createCustomError(errorMessage, 400));
}
next(error.message);
}
}

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

try {
if (!email || !password) {
throw createCustomError('Fill all required fields', 400);
}

console.log(1);
const user = await User.findOne({ where: { email } });
if (!user) {
throw createCustomError('Invalid credentials', 404);
}

const isPasswordValid = await bcrypt.compare(password, user.password_hash);

if (!isPasswordValid) {
throw createCustomError('Invalid credentials', 401);
}

const token = jwt.sign({ id: user.id }, secretKey, {
expiresIn: '1h',
});

// Sending the token in the response

return res.status(200).json({
message: 'User authenticated successfully',
statusCode: 200,
data: {
access_token: token,
email: user.email,
id: user.id,
isAdmin: user.is_admin,
},
});
} catch (error) {
next(error);
}
};

const logoutUser = (req, res) => {
try {
const token = req.header('Authorization').replace('Bearer ', '');

jwt.verify(token, process.env.JWT_SECRET_KEY);
if (!token) {
createCustomError('User is not logged in.', 401);
}

return res.status(200).json({ message: 'User logged out successfully.' });
} catch (error) {
return res.status(200).json({ message: 'User logged out successfully.' });
}
};

module.exports = { createUser, loginUser, logoutUser };
Empty file removed controllers/index.js
Empty file.
94 changes: 94 additions & 0 deletions controllers/mailController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// import bcrypt from "bcryptjs"
const dotenv = require('dotenv');
// const { transport } = require('../config/nodemailerConfig.js');

const { transport } = {};

dotenv.config();
// const teamMail = process.env.TEAM_MAIL;

const issueOtp = async () => {
const otp = `${Math.floor(1000 + Math.random() * 9000)}`;
// const saltRounds = 12; //This should be in environment variable

// const hashedOTP = await bcrypt.hash(otp, saltRounds);

//Save hased otp with userId and email for confirmation purposes
//Hased OTP should be saved to db for confirmation later,then deleted upon successful authentication

return {
userOtp: otp,
timeLeft: `1 hour`,
};
};

const otpMessage = (otp, timeLeft) => {
const template = `
<div style="max-width: 700px;text-align: center;background: #f4f8fd;
margin:auto; border: 10px solid #ddd; padding: 50px 20px; font-size: 110%;">
<h2 style="color: #FF7F50;">Welcome to XXXX 2.0</h2>
<div style="text-align:center ; color:black;"><br>
<h3 style="color: teal;">Your OTP is ${otp}</h3>
<h4 style="color: teal;">It expires in ${timeLeft}</h4>
</div>
</div>
`;
return template;
};

// Function to send email with otp code
const sendEmail = async (email, message) => {
const mailOptions = {
from: '[email protected]', //This should be in environement variable
subject: 'Verify your email',
to: email,
html: message,
};

return new Promise((resolve, reject) => {
transport.sendMail(mailOptions, (err, info) => {
if (err) reject(err);
resolve(info);
});
});
};

const sendUserOtp = async (userId, email) => {
try {
if (!userId || !email) {
return {
status: false,
message: `User details cannot be empty`,
};
}

//generate a new otp
const otp = await issueOtp(userId, email);
const message = otpMessage(otp.userOtp, otp.timeLeft);

//send mail with otp details
await sendEmail(email, message);

return {
status: true,
message: 'otp sent successfully',
data: null,
};
} catch (error) {
console.log(error);
return {
status: false,
message: `internal server error`,
};
}
};

module.exports = {
issueOtp,
otpMessage,
sendEmail,
sendUserOtp,
};

//call this function to test controller
// sendUserOtp('1','[email protected]')
13 changes: 7 additions & 6 deletions controllers/organizationController.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ const Organization = require('../models/organization.model');
const LunchWallet = require('../models/org_lunch_wallet.model');
const { createCustomError } = require('../errors/custom-errors');
const orgInvites = require('../models/organisation_invite.model');
const {
generateUniqueToken,
sendInvitationEmail,
} = require('../utils/sendOTP');

const { generateUniqueToken, sendInvitationEmail } = {
generateUniqueToken: '',
sendInvitationEmail: '',
};

// Create a new organization and user (Admin user only)
const createOrganization = async (req, res, next) => {
Expand Down Expand Up @@ -40,7 +41,7 @@ const createOrganization = async (req, res, next) => {
}
};

async function sendInvitation(req, res, next) {
async function sendInvite(req, res, next) {
try {
const { email, organizationId } = req.body;

Expand All @@ -67,4 +68,4 @@ async function sendInvitation(req, res, next) {
}
}

module.exports = { sendInvitation, createOrganization };
module.exports = { sendInvite, createOrganization };
Loading

0 comments on commit a1add65

Please sign in to comment.