HEX
Server: Apache/2.4.52 (Ubuntu)
System: Linux spn-python 5.15.0-89-generic #99-Ubuntu SMP Mon Oct 30 20:42:41 UTC 2023 x86_64
User: arjun (1000)
PHP: 8.1.2-1ubuntu2.20
Disabled: NONE
Upload Files
File: //proc/thread-self/root/home/arjun/projects/good-life-be/api/Auth/service.js
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';

import BadRequest from '../../helper/exception/badRequest.js';
import Login from '../../models/Login.js';
import User from '../../models/User.js';
import sendEmails from '../../helper/sendEmail.js';

export const loginSevice = async (body) => {
  const { email, password } = body;
  const { JWT_SECRET } = process.env;

  // Find login by email
  const login = await Login.findOne({
    where: { email },
    include: { model: User, where: { is_deleted: false } },
    raw: true,
  });

  if (!login) throw new BadRequest('No User found with this email or password');

  if (!login['user.is_verified']) {
    throw new BadRequest('Please verify your email before logging in.');
  }

  if (login['user.status'] === 'blocked') {
    throw new BadRequest(
      'Your Account has been blocked.Please contact Admin for further assistance.'
    );
  }

  // Compare passwords
  const isPasswordValid = await bcrypt.compare(password, login.password);
  if (!isPasswordValid) {
    throw new BadRequest('Invalid email or password.');
  }

  // Generate JWT token
  const token = jwt.sign(
    {
      id: login.id,
      email: login.email,
    },
    JWT_SECRET,
    { expiresIn: '30d' } // Token expiration time set to 30 days
  );

  return {
    token,
    userId: login['user.id'],
    role: login['user.role'],
  };
};

export const signUpService = async (body) => {
  const { email, password, firstName, secondName } = body;
  const role = 'user';

  // Check if the email already exists
  const existingLogin = await Login.findOne({
    where: { email },
    include: { model: User, where: { is_deleted: false, status: 'active' } },
  });
  if (existingLogin) {
    throw new BadRequest('Email is already registered.');
  }

  // Create a new User
  const newUser = await User.create({
    first_name: firstName,
    second_name: secondName,
    role,
  });

  // Create a Login record associated with the User
  await Login.create({
    email,
    password,
    user_id: newUser.id,
  });

  // ----------------->>>> Email <<<<---------------------
  const { MAILER_NAME, MAILER_AUTH_USER, WEB_DOMAIN } = process.env;
  const token = newUser.verification_token;
  const verificationLink = `${WEB_DOMAIN}/verify-email?token=${token}`;

  const mailOptions = {
    from: `${MAILER_NAME} ${MAILER_AUTH_USER}`,
    to: email,
    subject: 'New Registration Verification',
  };

  const contentVarialbles = {
    name: `${newUser.first_name} ${newUser.second_name}`,
    verificationLink,
  };

  const fileName = 'registerationNotify.ejs';

  sendEmails({ mailOptions, fileName, contentVarialbles });
};

export const verifyEmail = async (query) => {
  const { token } = query;
  // Find user with the verification token
  const user = await User.findOne({
    where: { verification_token: token },
  });

  if (!user) {
    throw new BadRequest('User is already verified');
  }

  const login = await Login.findOne({
    where: { user_id: user?.id },
    attributes: ['email'],
  });

  // Update the user's verification status
  user.is_verified = true;
  user.verification_token = null; // Token is no longer needed after verification
  user.status = 'active';
  await user.save();

  // ----------------->>>> Email <<<<---------------------

  const { MAILER_NAME, MAILER_AUTH_USER, WEB_DOMAIN } = process.env;

  const mailOptions = {
    from: `${MAILER_NAME} ${MAILER_AUTH_USER}`,
    to: login.email,
    subject: 'Welcome to Balance Calendar',
  };

  const contentVarialbles = {
    name: `${user.first_name} ${user.second_name}`,
    feUrl: WEB_DOMAIN,
  };

  const fileName = 'welcome.ejs';

  sendEmails({ mailOptions, fileName, contentVarialbles });
};

export async function forgotPassword(email) {
  const { JWT_SECRET, MAILER_NAME, MAILER_AUTH_USER } = process.env;

  const existingUser = await Login.findOne({
    where: { email },
    include: {
      model: User,
      where: { is_deleted: false, status: 'active' },
      attributes: ['first_name', 'second_name', 'role'],
    },
  });

  if (!existingUser) {
    throw new BadRequest('No account is related to this email.');
  }

  // if (existingUser.user?.role !== 'admin') {
  //   throw new BadRequest('Only admins can access this functionality.');
  // }
  const token = jwt.sign({ email: email.toLowerCase() }, JWT_SECRET, {
    expiresIn: '1h',
  });

  const mailOptions = {
    from: `${MAILER_NAME} ${MAILER_AUTH_USER}`,
    to: email.toLowerCase(),
    subject: 'Reset Your Password',
  };

  const contentVarialbles = {
    url: `${existingUser.user.role === 'user' ? process.env.WEB_DOMAIN : process.env.WEB_DOMAIN_ADMIN}/reset-password/${token}`,
    name: `${existingUser.user?.first_name} ${existingUser.user?.second_name}`,
  };

  const fileName = 'forgotPassword.ejs';
  sendEmails({ mailOptions, fileName, contentVarialbles });
  return { token };
}

export async function resetPasswordService(token, newPassword) {
  const { JWT_SECRET } = process.env;
  let hashedNewPassword;
  let decoded;
  let isSamePassword;

  // Verify the tokentry{}
  try {
    decoded = jwt?.verify(token, JWT_SECRET);
    console.log('decoded', decoded);
  } catch (error) {
    throw new BadRequest('Link Expired', 400);
  }

  if (!decoded.email) {
    throw new BadRequest('Invalid token or token expired', 400);
  }

  // Fetch the user by email
  const existingUser = await Login.findOne({
    where: { email: decoded.email },
  });

  if (!existingUser) {
    throw new BadRequest('User not found', 404);
  }
  console.log('newPassword', newPassword);
  if (newPassword !== undefined) {
    isSamePassword = await bcrypt.compare(newPassword, existingUser.password);
    if (isSamePassword) {
      throw new BadRequest(
        'New password cannot be the same as the previous password.'
      );
    }

    hashedNewPassword = await bcrypt.hash(newPassword, 10);
    await Login.update(
      {
        password: hashedNewPassword,
      },
      { where: { email: decoded.email } }
    );
  }
  // Check if the new password is the same as the current password

  // Update the user's password
}