front/controllers/user/index.js

/* ============================================================================ *\
|| ########################################################################## ||
|| # Auction Software Marketplace          Release: 0.6   Build 0.7         # ||
|| # ---------------------------------------------------------------------- # ||
|| # License # 35YAHCNR9344X6O666C123AB                                     # ||
|| # ---------------------------------------------------------------------- # ||
|| # Copyright ©2014–2021 Develop Scripts LLC. All Rights Reserved          # ||
|| # This file may not be redistributed in whole or significant part.       # ||
|| # ------------- AUCTION SOFTWARE IS NOT FREE SOFTWARE ------------------ # ||
|| # http://www.auctionsoftwaremarketplace.com|support@auctionsoftware.com  # ||
|| # ---------------------------------------------------------------------- # ||
|| ########################################################################## ||
\* ============================================================================ */

const md5 = require('md5')
const jwt = require('jsonwebtoken')
let config = require('config')
const userModule = require('../../modules/user').default
const cryptosFunction = require('../../../common/cryptos')
const commonFunction = require('../../../common/function').default
const sendgridModule = require('../../../common/thirdparty/sendgrid').default
const twilioModule = require('../../../common/thirdparty/twilio').default
const schemaModule = require('./schema').default

const kountCtrl = require('../kount')

config = config.get('JwtToken')

const { jsonResponse } = require('../logger')

const updateProfileFunction = async (req) => {
    await Promise.all([userModule.updateProfile(req, req.body)])
    if (global.configColumns.custom_users.enabled) {
        await Promise.all([userModule.updateCustomUsersProfile(req, req.body)])
    }
    return true
}

module.exports = {
    /**
     * Login User
     *
     * @memberOf frontend.user
     * @param {userModule.updateLastLogin} modules
     * @param {userModule.userViews} modules
     * @param {userModule.checkEmailExisting} modules
     * @param {userModule.loginWithEmail} modules
     * @param {userModule.updateSocialID} modules
     */
    loginUser: async (req, res) => {
        try {
            await schemaModule.login().validateSync(req.body)

            const successLogin = async (row) => {
                await Promise.all([
                    userModule.updateLastLogin(row[0].id, req.sessionID),
                    userModule.userViews(req, row[0].id),
                ])
                const obj = {
                    id: row[0].id,
                }

                // const [userBidAverage, userCategory, userCondition] = await Promise.all([
                //     commonFunction.userAvgPrefDetails(row[0].id),
                //     commonFunction.userCategoryPrefDetails(row[0].id),
                //     commonFunction.userConditionPrefDetails(row[0].id),
                // ])
                // obj.averageBidAmount = userBidAverage[0].averageBidAmount
                // obj.averageCategoryType = userCategory
                // obj.averageConditionType = userCondition

                const token = jwt.sign(obj, config.get('secret'), {
                    expiresIn: '168h',
                })
                if (row[0].isemp === '1') {
                    jsonResponse(res, 'success', {
                        responseType: 6,
                        token,
                        message: 'Logged in succesfully',
                    })
                } else {
                    jsonResponse(res, 'success', {
                        responseType: 3,
                        token,
                        message: 'Logged in succesfully',
                    })
                }
            }
            const processObject = async (row) => {
                if (row.length > 0) {
                    if (row[0].status === 'moderate') {
                        jsonResponse(res, 'error', {
                            responseType: 2,
                            message: 'Account has not been approved by admin yet',
                        })
                    } else if (row[0].status === 'deleted') {
                        jsonResponse(res, 'error', {
                            responseType: 2,
                            message: 'Account has been suspended',
                        })
                    } else if (row[0].status === 'deactivate') {
                        jsonResponse(res, 'error', {
                            responseType: 2,
                            message: 'Account has been suspended',
                        })
                    } else {
                        successLogin(row)
                    }
                } else if (req.body.google_id || req.body.facebook_id) {
                    req.body.email = req.body.email.toLowerCase()
                    const resultuser = await Promise.all([
                        userModule.checkEmailExisting(req.body.email),
                    ])
                    if (resultuser[0].length > 0) {
                        const [updateSocial, afterSuccess] = await Promise.all([
                            userModule.updateSocialID(req, resultuser[0][0].id),
                            userModule.loginWithEmail(req.body.email),
                        ])
                        if (afterSuccess.length > 0) {
                            if (afterSuccess[0].status === 'moderate') {
                                jsonResponse(res, 'error', {
                                    responseType: 2,
                                    message: 'Account has not been approved by admin yet',
                                })
                            } else if (afterSuccess[0].status === 'deleted') {
                                jsonResponse(res, 'error', {
                                    responseType: 2,
                                    message: 'Account has been suspended',
                                })
                            } else if (afterSuccess[0].status === 'deactivate') {
                                jsonResponse(res, 'error', {
                                    responseType: 2,
                                    message: 'Account has been suspended',
                                })
                            } else {
                                successLogin(afterSuccess)
                            }
                        } else {
                            jsonResponse(res, 'error', {
                                responseType: 2,
                                message: 'Invalid Email/Password',
                            })
                        }
                    } else {
                        jsonResponse(res, 'error', {
                            responseType: 2,
                            message: 'Invalid Email/Password',
                        })
                    }
                } else {
                    jsonResponse(res, 'error', {
                        responseType: 2,
                        message: 'Invalid Email/Password',
                    })
                }
            }
            userModule.process(req, processObject)
        } catch (e) {
            console.error(e)
            jsonResponse(res, 'error', {
                responseType: 3,
                message: 'Internal Server error!',
            })
        }
    },

    /**
     * Register User
     *
     * @memberOf frontend.user
     * @param {userModule.checkEmailExisting} modules
     * @param {userModule.registerUser} modules
     * @param {userModule.registerUserCustom} modules
     * @param {userModule.insertEmailVerifyToken} modules
     * @param {userModule.manualInsertUsernotify} modules
     */
    registerUser: async (req, res) => {
        try {
            const successRegistration = () => {
                jsonResponse(res, 'success', {
                    responseType: 1,
                    message: 'Successfully registered!',
                })
            }
            await schemaModule.register().validateSync(req.body)
            req.body.email = req.body.email.toLowerCase()
            const resultuser = await Promise.all([userModule.checkEmailExisting(req.body.email)])
            if (resultuser[0].length > 0) {
                jsonResponse(res, 'error', {
                    responseType: 2,
                    message: 'Registration Failed! Email Already Exists.',
                })
            } else {
                let kountResponse = { status: 'success' }
                if (global.configFeatures.kount_register.enabled) {
                    ;[kountResponse] = await Promise.all([kountCtrl.getRegistrationValidation(req)])
                }

                if (kountResponse.status === 'success') {
                    // req.body.password = Math.random().toString(36).slice(2);
                    const firstname = req.body.first_name
                    const lastname = req.body.last_name

                    const results = await Promise.all([userModule.registerUser(req, req.body)])

                    if (global.configColumns.custom_users.enabled) {
                        await Promise.all([
                            userModule.registerUserCustom(req, req.body, results[0].insertId),
                        ])
                    }

                    if (global.configFeatures.register_email.enabled) {
                        const [resultsEmail] = await Promise.all([
                            commonFunction.mailtemps('register_user'),
                        ])
                        let { template, subject } = resultsEmail[0]
                        template = template.replace('{{event.user}}', `${firstname} ${lastname}`)

                        if (global.configFeatures.register_email_verification.enabled) {
                            req.body.token = cryptosFunction.encrypt(req.body.email.toLowerCase())
                            await Promise.all([
                                userModule.insertEmailVerifyToken(
                                    results[0].insertId,
                                    req.body.email,
                                    req.body.token,
                                ),
                            ])
                            const verifyurl = `${global.react_url.front_end}/verify_email/${req.body.token}`
                            template = template.replace(/{{event.verifyurl}}/g, verifyurl)
                        }

                        sendgridModule.sendEmail(
                            subject,
                            req.body.email,
                            template,
                            1,
                            results[0].insertId,
                        )
                    }

                    await Promise.all([userModule.manualInsertUsernotify(results[0].insertId)])

                    if (global.configFeatures.register_sms.enabled && req.body.phone) {
                        const [resultsSMS] = await Promise.all([
                            commonFunction.smstemps('register_user'),
                        ])

                        let { template: templateSMS } = resultsSMS[0]
                        templateSMS = templateSMS.replace(
                            '{{event.user}}',
                            `${firstname} ${lastname}`,
                        )
                        twilioModule.sendsms(templateSMS, req.body.phone, results[0].insertId)
                    }
                    successRegistration()
                } else {
                    jsonResponse(res, 'error', {
                        responseType: kountResponse.responseType,
                        message: kountResponse.message,
                        responseData: kountResponse.responseData,
                    })
                }
            }
        } catch (e) {
            console.error(e)
            jsonResponse(res, 'error', {
                responseType: 3,
                message: 'Internal Server error!',
            })
        }
    },

    /**
     * Verify Email
     *
     * @memberOf frontend.user
     * @param {userModule.getEmailVerifyToken} modules
     * @param {userModule.updateEmailVerified} modules
     * @param {userModule.updateEmailVerifiedToken} modules
     */
    verifyEmail: async (req, res) => {
        try {
            req.body.email = cryptosFunction.decrypt(req.body.user_token)
            const [userExist] = await Promise.all([
                userModule.getEmailVerifyToken(req.body.email, req.body.user_token),
            ])
            if (userExist.length > 0) {
                const [results2] = await Promise.all([
                    commonFunction.mailtemps('email_verified'),
                    userModule.updateEmailVerified(userExist[0]),
                    userModule.updateEmailVerifiedToken(userExist[0]),
                ])
                if (results2.length > 0) {
                    let { template } = results2[0]
                    const { subject } = results2[0]
                    template = template.replace(
                        '{{event.user}}',
                        `${userExist[0].first_name} ${userExist[0].last_name}`,
                    )
                    const loginurl = `${global.react_url.front_end}/login`
                    template = template.replace(/{{event.loginurl}}/g, loginurl)
                    sendgridModule.sendEmail(subject, req.body.email, template, 1, userExist[0].id)
                    jsonResponse(res, 'success', {
                        responseType: 1,
                        message: 'Email verified successfully.',
                    })
                } else {
                    jsonResponse(res, 'error', {
                        responseType: 1,
                        message: 'Email template does not exists',
                    })
                }
            } else {
                jsonResponse(res, 'success', {
                    responseType: 1,
                    message: 'Not a valid request!',
                })
            }
        } catch (e) {
            console.error(e)
            jsonResponse(res, 'error', {
                responseType: 3,
                message: 'Not a valid request!',
            })
        }
    },

    /**
     * Check User Token
     *
     * @memberOf frontend.user
     * @param {userModule.userDetails} modules
     */
    checkTokenUser: async (req, res) => {
        try {
            const results = await Promise.all([userModule.userDetails(req.user.id)])
            if (results[0].length > 0) {
                jsonResponse(res, 'success', {
                    responseType: 1,
                    message: 'Details successfully retrieved!',
                    responseData: results[0][0],
                })
            } else {
                jsonResponse(res, 'error', {
                    responseType: 2,
                    message: 'User details not available!',
                })
            }
        } catch (e) {
            console.error(e)
            jsonResponse(res, 'error', {
                responseType: 3,
                message: 'Internal Server error!',
            })
        }
    },

    /**
     * Check User Validation
     *
     * @memberOf frontend.user
     * @param {userModule.checkEmailExisting} modules
     */
    checkValidation: async (req, res) => {
        try {
            await schemaModule.checkValidation().validateSync(req.body)

            if (req.body.type === 'email') {
                req.body.text = req.body.text.toLowerCase()
                const resultuser = await Promise.all([userModule.checkEmailExisting(req.body.text)])
                if (resultuser[0].length > 0) {
                    jsonResponse(res, 'error', {
                        responseType: 2,
                        message: 'Email Already Exists!',
                    })
                } else {
                    jsonResponse(res, 'success', {
                        responseType: 1,
                        message: 'Email available!',
                    })
                }
            } else {
                jsonResponse(res, 'error', {
                    responseType: 4,
                    message: 'Unknown type!',
                })
            }
        } catch (e) {
            console.error(e)
            jsonResponse(res, 'error', {
                responseType: 3,
                message: 'Internal Server error!',
            })
        }
    },

    /**
     * Update User Profile
     *
     * @memberOf frontend.user
     * @param {userModule.userDetails} modules
     * @param {userModule.updateProfile} modules
     * @param {userModule.updateCustomUsersProfile} modules
     */
    updateProfile: async (req, res) => {
        try {
            if (req.body.change_password) {
                const results = await Promise.all([userModule.userDetails(req.user.id)])
                if (results[0].length > 0) {
                    const currentUserPasswordSalt = results[0][0].password_salt
                    const encryptCurrentUserOldPassword = results[0][0].password_hash
                    req.body.password_hash = md5(
                        md5(req.body.new_password) + currentUserPasswordSalt,
                    )
                    const encryptOldPasswordFromRequest = md5(
                        md5(req.body.current_password) + currentUserPasswordSalt,
                    )
                    if (encryptOldPasswordFromRequest !== encryptCurrentUserOldPassword) {
                        jsonResponse(res, 'error', {
                            responseType: 2,
                            message: 'Current password not match!',
                        })
                    } else {
                        await Promise.all([updateProfileFunction(req)])
                        jsonResponse(res, 'success', {
                            responseType: 1,
                            message: 'Password changed successfully',
                        })
                    }
                } else {
                    jsonResponse(res, 'error', {
                        responseType: 2,
                        message: 'User details not available!',
                    })
                }
            } else {
                await Promise.all([updateProfileFunction(req)])
                jsonResponse(res, 'success', {
                    responseType: 1,
                    message: 'Profile updated successfully',
                })
            }
        } catch (e) {
            console.error(e)
            jsonResponse(res, 'error', {
                responseType: 3,
                message: 'Internal Server error!',
            })
        }
    },

    /**
     * Add to watchlist
     *
     * @memberOf frontend.user
     * @param {userModule.isinWatchlist} modules
     * @param {userModule.updateWatchlist} modules
     * @param {userModule.addWatchlist} modules
     */
    addWatchlist: async (req, res) => {
        try {
            const projectID = req.body.project_id
            const [watchexist] = await Promise.all([userModule.isinWatchlist(req, projectID)])
            if (watchexist.length > 0) {
                await Promise.all([userModule.updateWatchlist(req, projectID)])
            } else {
                await Promise.all([userModule.addWatchlist(req, projectID)])
            }
            const responseData = { project_id: projectID, status: 'added' }
            jsonResponse(res, 'success', {
                responseType: 1,
                message: 'Successfully added to watchlist!',
                responseData,
            })
        } catch (e) {
            console.error(e)
            jsonResponse(res, 'error', {
                responseType: 3,
                message: 'Internal Server error!',
            })
        }
    },

    /**
     * Remove from watchlist
     *
     * @memberOf frontend.user
     * @param {userModule.removeWatchlist} modules
     */
    removeWatchlist: async (req, res) => {
        try {
            const projectID = req.body.project_id
            await Promise.all([userModule.removeWatchlist(req, projectID)])
            const responseData = { project_id: projectID, status: 'removed' }
            jsonResponse(res, 'success', {
                responseType: 1,
                message: 'Successfully removed from watchlist!',
                responseData,
            })
        } catch (e) {
            console.error(e)
            jsonResponse(res, 'error', {
                responseType: 3,
                message: 'Internal Server error!',
            })
        }
    },

    /**
     * Forgot Password
     *
     * @memberOf frontend.user
     * @param {userModule.checkForgotUserExists} modules
     * @param {userModule.inserUserToken} modules
     */
    forgotPassword: async (req, res) => {
        try {
            const emailID = req.body.email
            const [userExist] = await Promise.all([userModule.checkForgotUserExists(emailID)])
            if (userExist.length > 0) {
                req.body.token = cryptosFunction.encrypt(req.body.email.toLowerCase())
                const verifyurl = `${global.react_url.front_end}/reset_password/${req.body.token}`
                const [results2] = await Promise.all([
                    commonFunction.mailtemps('forgot_password'),
                    userModule.inserUserToken(userExist[0], req.body.token),
                ])
                console.log('results2[0]', results2[0])
                if (results2[0]) {
                    let { template, subject } = results2[0]
                    template = template.replace(
                        '{{event.user}}',
                        `${userExist[0].first_name} ${userExist[0].last_name}`,
                    )
                    template = template.replace(/{{event.siteurl}}/g, global.url)
                    template = template.replace(/{{event.verifyurl}}/g, verifyurl)
                    sendgridModule.sendEmail(subject, req.body.email, template, 1, userExist[0].id)
                    jsonResponse(res, 'success', {
                        responseType: 1,
                        message: 'Email sent out successfully',
                    })
                } else {
                    jsonResponse(res, 'error', {
                        responseType: 3,
                        message: 'Email Template does not exist',
                    })
                }
            } else {
                jsonResponse(res, 'error', {
                    responseType: 3,
                    message: 'Email did not match with record',
                })
            }
        } catch (e) {
            console.error(e)
            jsonResponse(res, 'error', {
                responseType: 3,
                message: 'Internal Server error!',
            })
        }
    },

    /**
     * Reset Password
     *
     * @memberOf frontend.user
     * @param {userModule.getForgotUserToken} modules
     * @param {userModule.updateResetPassword} modules
     * @param {userModule.updateForgotUserToken} modules
     */
    resetPassword: async (req, res) => {
        try {
            await schemaModule.resetPassword().validateSync(req.body)
            req.body.email = cryptosFunction.decrypt(req.body.user_token)
            const [userExist] = await Promise.all([
                userModule.getForgotUserToken(req.body.email, req.body.user_token),
            ])
            if (userExist.length > 0) {
                console.log('<=====change-password=====>')
                const [results2] = await Promise.all([
                    commonFunction.mailtemps('password_changed'),
                    userModule.updateResetPassword(req.body.password, userExist[0]),
                    userModule.updateForgotUserToken(userExist[0]),
                ])
                if (results2.length > 0) {
                    let { template, subject } = results2[0]
                    template = template.replace(
                        '{{event.user}}',
                        `${userExist[0].first_name} ${userExist[0].last_name}`,
                    )
                    const loginurl = `${global.react_url.front_end}/login`
                    template = template.replace(/{{event.loginurl}}/g, loginurl)
                    template = template.replace('{{event.email}}', req.body.email)
                    sendgridModule.sendEmail(subject, req.body.email, template, 1, userExist[0].id)
                    jsonResponse(res, 'success', {
                        responseType: 1,
                        message: 'Password changed successfully.',
                    })
                } else {
                    jsonResponse(res, 'error', {
                        responseType: 1,
                        message: 'Email template does not exists',
                    })
                }
            } else {
                jsonResponse(res, 'success', {
                    responseType: 1,
                    message: 'Not a valid request!',
                })
            }
        } catch (e) {
            console.error(e)
            jsonResponse(res, 'error', {
                responseType: 3,
                message: 'Not a valid request!',
            })
        }
    },

    /**
     * Send Phone Verification Code
     *
     * @memberOf frontend.user
     * @param {userModule.getPhoneVerifyToken} modules
     * @param {userModule.insertPhoneVerifyToken} modules
     * @param {userModule.updatePhoneVerifyExpiry} modules
     */
    sendPhoneVerifyCode: async (req, res) => {
        try {
            const [userExist] = await Promise.all([userModule.getPhoneVerifyToken(req.body.phone)])
            req.body.token = Math.floor(100000 + Math.random() * 900000)
            req.body.ip = typeof req.headers.ipaddress === 'undefined' ? '' : req.headers.ipaddress
            if (userExist.length > 0) {
                const [results2] = await Promise.all([commonFunction.smstemps('verify_phone')])
                if (results2.length > 0) {
                    if (new Date() >= userExist[0].expires_at) {
                        await Promise.all([
                            userModule.insertPhoneVerifyToken(
                                req.body.phone,
                                req.body.token,
                                req.body.ip,
                            ),
                        ])
                        let { template: templateSMS } = results2[0]
                        templateSMS = templateSMS.replace('{{event.code}}', req.body.token)
                        twilioModule.sendsms(
                            templateSMS,
                            req.body.phone,
                            req.user ? req.user.id : 0,
                        )
                        jsonResponse(res, 'success', {
                            responseType: 1,
                            message: 'SMS sent for verification!',
                        })
                    } else {
                        await Promise.all([userModule.updatePhoneVerifyExpiry(userExist[0].id)])
                        let { template: templateSMS } = results2[0]
                        templateSMS = templateSMS.replace('{{event.code}}', userExist[0].code)
                        twilioModule.sendsms(
                            templateSMS,
                            req.body.phone,
                            req.user ? req.user.id : 0,
                        )
                        jsonResponse(res, 'success', {
                            responseType: 1,
                            message: 'SMS resent for verification!',
                        })
                    }
                } else {
                    jsonResponse(res, 'error', {
                        responseType: 3,
                        message: 'SMS Template does not exist',
                    })
                }
            } else {
                const [results2] = await Promise.all([
                    commonFunction.smstemps('verify_phone'),
                    userModule.insertPhoneVerifyToken(req.body.phone, req.body.token, req.body.ip),
                ])
                if (results2.length > 0) {
                    let { template: templateSMS } = results2[0]
                    templateSMS = templateSMS.replace('{{event.code}}', req.body.token)
                    twilioModule.sendsms(templateSMS, req.body.phone, req.user.id || 0)
                    jsonResponse(res, 'success', {
                        responseType: 1,
                        message: 'SMS sent for verification!',
                    })
                } else {
                    jsonResponse(res, 'error', {
                        responseType: 3,
                        message: 'SMS Template does not exist',
                    })
                }
            }
        } catch (e) {
            console.error(e)
            jsonResponse(res, 'error', {
                responseType: 3,
                message: 'Internal Server error!',
            })
        }
    },

    /**
     * Verify Phone Verification Code
     *
     * @memberOf frontend.user
     * @param {userModule.getPhoneVerifyToken} modules
     * @param {userModule.updatePhoneVerified} modules
     */
    verifyPhoneVerifyCode: async (req, res) => {
        try {
            const [userExist] = await Promise.all([userModule.getPhoneVerifyToken(req.body.phone)])
            if (userExist.length > 0) {
                if (userExist[0].code !== req.body.verify_code) {
                    jsonResponse(res, 'error', {
                        responseType: 1,
                        message: 'Invalid verification code!',
                    })
                } else if (new Date() >= userExist[0].expires_at) {
                    jsonResponse(res, 'error', {
                        responseType: 1,
                        message: 'Code Expired! Try again',
                    })
                } else {
                    await Promise.all([userModule.updatePhoneVerified(userExist[0].id)])
                    jsonResponse(res, 'success', {
                        responseType: 1,
                        message: 'Phone number verified successfully',
                    })
                }
            } else {
                jsonResponse(res, 'error', {
                    responseType: 1,
                    message: 'No Code. Resent SMS Verification!',
                })
            }
        } catch (e) {
            console.error(e)
            jsonResponse(res, 'error', {
                responseType: 3,
                message: 'Internal Server error!',
            })
        }
    },

    /**
     * Update User Preference
     *
     * @memberOf frontend.user
     * @param {userModule.selectUserPreference} req.modules
     * @param {userModule.updatePreference} req.modules
     * @param {userModule.insertPreference} req.modules
     */
    updatePreference: async (req, res) => {
        try {
            const [notificationExist] = await Promise.all([
                userModule.selectUserPreference(req.user.id),
            ])
            if (notificationExist.length > 0) {
                await Promise.all([userModule.updatePreference(req, notificationExist[0].id)])
                jsonResponse(res, 'success', {
                    responseType: 1,
                    message: 'Successfully updated notification preference!',
                })
            } else {
                await Promise.all([userModule.insertPreference(req)])
                jsonResponse(res, 'success', {
                    responseType: 1,
                    message: 'Successfully added notification preference!',
                })
            }
        } catch (e) {
            console.error(e)
            jsonResponse(res, 'error', {
                responseType: 3,
                message: 'Internal Server error!',
            })
        }
    },
}