<commit_before>import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import validator from 'validator';
import isEmpty from 'lodash/isEmpty';
import nodemailer from 'nodemailer';
import smtpTransport from 'nodemailer-smtp-transport';
import crypto from 'crypto';
import models from '../models';
import validateInput from '../../client/validations/signupValidation';

const saltRounds = 7;
const salt = bcrypt.genSaltSync(saltRounds);


export default {
  // Method to signup a user
  signup(req, res) {
    const { errors, valid } = validateInput(req.body);

    if (!valid) {
      res.status(400).send(errors);
    } else {
      models.User.findOne({
        where: {
          username: req.body.username
        },
      })
      .then((existingUsername, err) => {
        if (existingUsername) {
          errors.username = 'Username already exists';
        }
        models.User.findOne({
          where: {
            email: req.body.email
          },
        })
        .then((existingUser, err) => {
          if (existingUser) {
            errors.email = 'Email already exists';
          }

          if (!isEmpty(errors)) {
            res.status(400).send(errors);
          } else {
            const userData = {
              firstname: req.body.firstname,
              lastname: req.body.lastname,
              username: req.body.username,
              mobile: `234${req.body.phone.slice(1)}`,
              email: req.body.email,
              password: <PASSWORD>.hashSync(req.body.password, salt)
            };
            models.User.create(userData)
            .then((user) => {
              const token = jwt.sign({ data: { id: user.id, username: user.username } }, process.env.TOKEN_SECRET);
              res.status(201).send({ success: true, message: 'Signup was successful', token });
            })
            .catch(error => res.status(400).send(error.message));
          }
        })
        .catch(err => res.status(400).send(err.message));
      });
    }
  },

  // Method to sign in a user
  signin(req, res) {
    const errors = {};
    if (!req.body.identifier && !req.body.password) {
      errors.identifier = 'This field is required';
      errors.password = 'This field is required';
      res.status(401).send(errors);
    } else if (!req.body.identifier) {
      errors.identifier = 'This field is required';
      res.status(401).send(errors);
    } else if (!req.body.password) {
      errors.password = 'This field is required';
      res.status(401).send(errors);
    } else {
      models.User.findOne({
        where: {
          $or: [{ username: req.body.identifier }, { email: req.body.identifier }]
        },
      })
      .then((user, err) => {
        if (err) throw err;
        if (!user) {
          errors.identifier = 'Invalid username or password';
          res.status(401).send(errors);
        } else if (user) {
          if (bcrypt.compareSync(req.body.password, user.password)) {
            const token = jwt.sign({ data: { id: user.id, username: user.username } }, process.env.TOKEN_SECRET);

            res.status(201).send({
              success: true,
              message: 'User successfully logged in',
              token
            });
          } else {
            errors.identifier = 'Invalid username or password';
            res.status(401).send(errors);
          }
        }
      })
      .catch(err => res.status(400).send(err.message));
    }
  },

  // Method to get the groups a user belongs to
  getUserGroups(req, res) {
    if (req.params.user_id) {
      models.User.findOne({
        where: { id: req.params.user_id },
        attributes: [['id', 'user_id'], 'firstname', 'lastname', 'email'],
        include: [{
          model: models.Group,
          as: 'group',
          attributes: ['id', ['group_name', 'name']],
          through: { attributes: [] }
        }]
      })
      .then((user) => {
        res.status(201).send(user);
      })
      .catch(err => res.status(400).send(err.message));
    }
  },

   // Method to send password reset link
  sendResetPasswordLink(req, res) {
    let error = '';
    if (!req.body.email) {
      error = 'Email field is required';
      res.status(401).send(error);
    } else if (!validator.isEmail(req.body.email)) {
      error = 'Invalid email address';
      res.status(401).send(error);
    } else {
      User.findOne({
        where: { email: req.body.email }
      }).then(user => {
        if (user) {
          const resetPasswordHash = crypto.randomBytes(20).toString('hex');
          const resetPasswordExpires = Date.now() + 3600000;
          const transporter = nodemailer.createTransport(smtpTransport({
            service: 'gmail',
            port: 465,
            auth: {
              user: '<EMAIL>',
              pass: <PASSWORD>.EMAIL_PASSWORD
            }
          }));
          const mailOptions = {
            from: '<EMAIL>',
            to: user.email,
            subject: 'Reset your Post It Password',
            html: `Hello ${user.firstname} ${user.lastname}, 
            <br><br>You recently made a request to reset your Post It password. 
            Please click the link below to complete the process. 
            <br><br><a href='http://${req.headers.host}/newpassword/${resetPasswordHash}'>Reset now ></a>
            <br><br>----------------------<br>
            The Post It Team`
          };
          ForgotPassword.findOne({
            where: { user_id: user.id }
          }).then((userAlreadyRequested) => {
            if (userAlreadyRequested) {
              ForgotPassword.update({
                hash: resetPasswordHash,
                expiry_time: Date.now() + 3600000
              }, {
                where: { user_id: user.id }
              }).then(() => {
                // send email
                transporter.sendMail(mailOptions, (err, info) => {
                  if (err) {
                    console.log(err);
                  } else {
                    console.log(`Email sent:${info.response}`);
                  }
                });
                res.status(200).send('Email sent');
              }).catch(err => res.status(400).send(err.message));
            } else {
              ForgotPassword.create({
                user_id: user.id,
                hash: resetPasswordHash,
                expiry_time: resetPasswordExpires
              })
              .then(() => {
                // send email
                transporter.sendMail(mailOptions, (err, info) => {
                  if (err) {
                    console.log(err);
                  } else {
                    console.log(`Email sent:${info.response}`);
                  }
                });
                res.status(200).send('Email sent');
              });
            }
          })
          .catch(err => res.status(400).send(err.message));
        } else {
          res.status(404).send('User does not exist');
        }
      })<commit_msg>Updates models in sendResetPasswordLink method<commit_after>import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import validator from 'validator';
import isEmpty from 'lodash/isEmpty';
import nodemailer from 'nodemailer';
import smtpTransport from 'nodemailer-smtp-transport';
import crypto from 'crypto';
import models from '../models';
import validateInput from '../../client/validations/signupValidation';

const saltRounds = 7;
const salt = bcrypt.genSaltSync(saltRounds);


export default {
  // Method to signup a user
  signup(req, res) {
    const { errors, valid } = validateInput(req.body);

    if (!valid) {
      res.status(400).send(errors);
    } else {
      models.User.findOne({
        where: {
          username: req.body.username
        },
      })
      .then((existingUsername, err) => {
        if (existingUsername) {
          errors.username = 'Username already exists';
        }
        models.User.findOne({
          where: {
            email: req.body.email
          },
        })
        .then((existingUser, err) => {
          if (existingUser) {
            errors.email = 'Email already exists';
          }

          if (!isEmpty(errors)) {
            res.status(400).send(errors);
          } else {
            const userData = {
              firstname: req.body.firstname,
              lastname: req.body.lastname,
              username: req.body.username,
              mobile: `234${req.body.phone.slice(1)}`,
              email: req.body.email,
              password: <PASSWORD>.hashSync(req.body.password, salt)
            };
            models.User.create(userData)
            .then((user) => {
              const token = jwt.sign({ data: { id: user.id, username: user.username } }, process.env.TOKEN_SECRET);
              res.status(201).send({ success: true, message: 'Signup was successful', token });
            })
            .catch(error => res.status(400).send(error.message));
          }
        })
        .catch(err => res.status(400).send(err.message));
      });
    }
  },

  // Method to sign in a user
  signin(req, res) {
    const errors = {};
    if (!req.body.identifier && !req.body.password) {
      errors.identifier = 'This field is required';
      errors.password = '<PASSWORD>';
      res.status(401).send(errors);
    } else if (!req.body.identifier) {
      errors.identifier = 'This field is required';
      res.status(401).send(errors);
    } else if (!req.body.password) {
      errors.password = '<PASSWORD>';
      res.status(401).send(errors);
    } else {
      models.User.findOne({
        where: {
          $or: [{ username: req.body.identifier }, { email: req.body.identifier }]
        },
      })
      .then((user, err) => {
        if (err) throw err;
        if (!user) {
          errors.identifier = 'Invalid username or password';
          res.status(401).send(errors);
        } else if (user) {
          if (bcrypt.compareSync(req.body.password, user.password)) {
            const token = jwt.sign({ data: { id: user.id, username: user.username } }, process.env.TOKEN_SECRET);

            res.status(201).send({
              success: true,
              message: 'User successfully logged in',
              token
            });
          } else {
            errors.identifier = 'Invalid username or password';
            res.status(401).send(errors);
          }
        }
      })
      .catch(err => res.status(400).send(err.message));
    }
  },

  // Method to get the groups a user belongs to
  getUserGroups(req, res) {
    if (req.params.user_id) {
      models.User.findOne({
        where: { id: req.params.user_id },
        attributes: [['id', 'user_id'], 'firstname', 'lastname', 'email'],
        include: [{
          model: models.Group,
          as: 'group',
          attributes: ['id', ['group_name', 'name']],
          through: { attributes: [] }
        }]
      })
      .then((user) => {
        res.status(201).send(user);
      })
      .catch(err => res.status(400).send(err.message));
    }
  },

   // Method to send password reset link
  sendResetPasswordLink(req, res) {
    let error = '';
    if (!req.body.email) {
      error = 'Email field is required';
      res.status(401).send(error);
    } else if (!validator.isEmail(req.body.email)) {
      error = 'Invalid email address';
      res.status(401).send(error);
    } else {
      models.User.findOne({
        where: { email: req.body.email }
      }).then(user => {
        if (user) {
          const resetPasswordHash = crypto.randomBytes(20).toString('hex');
          const resetPasswordExpires = Date.now() + 3600000;
          const transporter = nodemailer.createTransport(smtpTransport({
            service: 'gmail',
            port: 465,
            auth: {
              user: '<EMAIL>',
              pass: <PASSWORD>.EMAIL_PASSWORD
            }
          }));
          const mailOptions = {
            from: '<EMAIL>',
            to: user.email,
            subject: 'Reset your Post It Password',
            html: `Hello ${user.firstname} ${user.lastname}, 
            <br><br>You recently made a request to reset your Post It password. 
            Please click the link below to complete the process. 
            <br><br><a href='http://${req.headers.host}/newpassword/${resetPasswordHash}'>Reset now ></a>
            <br><br>----------------------<br>
            The Post It Team`
          };
          models.ForgotPassword.findOne({
            where: { user_id: user.id }
          }).then((userAlreadyRequested) => {
            if (userAlreadyRequested) {
              models.ForgotPassword.update({
                hash: resetPasswordHash,
                expiry_time: Date.now() + 3600000
              }, {
                where: { user_id: user.id }
              }).then(() => {
                // send email
                transporter.sendMail(mailOptions, (err, info) => {
                  if (err) {
                    console.log(err);
                  } else {
                    console.log(`Email sent:${info.response}`);
                  }
                });
                res.status(200).send('Email sent');
              }).catch(err => res.status(400).send(err.message));
            } else {
              models.ForgotPassword.create({
                user_id: user.id,
                hash: resetPasswordHash,
                expiry_time: resetPasswordExpires
              })
              .then(() => {
                // send email
                transporter.sendMail(mailOptions, (err, info) => {
                  if (err) {
                    console.log(err);
                  } else {
                    console.log(`Email sent:${info.response}`);
                  }
                });
                res.status(200).send('Email sent');
              });
            }
          })
          .catch(err => res.status(400).send(err.message));
        } else {
          res.status(404).send('User does not exist');
        }
      })
{'fraction_non_alphanumeric': 0.14309128482861827, 'fraction_numerical': 0.012399344402479869, 'mean_word_length': 1.6384658770445573, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 67, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '512984', 'n_tokens_mistral': 4062, 'n_tokens_neox': 3864, 'n_words': 836}