<!--views/front/signup.ejs-->
<link rel="stylesheet" href="/styles/front/signup.css" />

<section class="Signup">
    <div class="outer">
        <div class="title">ចុះ​ឈ្មោះ​ចុះ​ផ្សាយ​លក់​ផលិតផល</div>
        <form action="/signup" method="post">
            <a>ឈ្មោះ​អ្នក​ប្រើប្រាស់ៈ</a><input type="text" name="title" required  />
            <a>Email:</a><input type="email" name="email" required  />
            <a>ពាក្យ​សំងាត់ៈ</a><input type="password" name="password" minlength="8" required />
            <a>បញ្ជាក់​ពាក្យ​សំងាត់ៈ</a><input type="password" name="password1" minlength="8" required />
            <a>តំណរ​ភ្ជាប់​រូប​តំណាងៈ</a><input type="text" name="thumb" placeholder="មិន​ចាំបាច់" />
            <a></a><input type="submit" value="បញ្ជូន" />
            <a></a><div class="fb-login-button" data-width="100%" 
            data-size="large" data-button-type="continue_with" 
            data-layout="default" data-auto-logout-link="false" 
            data-use-continue-as="false" 
            onlogin="checkLoginState()"
            ></div>
            <a></a><div class="info"><%= data.message %></div>
        </form>
    </div>
</section>

<script>
    function checkLoginState() {
        FB.getLoginStatus(function(response) {
            if(response.authResponse.accessToken){
                FB.api('/me',function(user) {
                    const fbuser = {
                        id: user.id,
                        name: user.name, 
                    }
                
                    $.post('/signup/fbuser',fbuser,function(data, status){
                        alert(data.message)
                        window.location.href = data.redirect
                    })
                })
            }else{
                alert('​​​​​​​មានបញ្ហា​មិន​អាច​ចុះ​ឈ្មោះ​បាន')
            }
        })
    }

    window.fbAsyncInit = function() {
        FB.init({
            appId      : '3245867309046703',
            cookie     : true,
            xfbml      : true,
            version    : 'v14'
        })
        
        FB.AppEvents.logPageView(); 
    }
  
    (function(d, s, id){
       var js, fjs = d.getElementsByTagName(s)[0]
       if (d.getElementById(id)) {return;}
       js = d.createElement(s); js.id = id
       js.src = "https://connect.facebook.net/en_US/sdk.js"
       fjs.parentNode.insertBefore(js, fjs)
     }(document, 'script', 'facebook-jssdk'))
  </script>

 

// routes/front/signup.js
import express from 'express'
const signupRouter = express.Router()
import signup from '../../controllers/front/signup.js'

signupRouter.get('/',async (req,res)=>{
    signup.getItem(req,res)
})

signupRouter.post('/',async (req,res)=>{
    signup.registerItem(req,res)
})

signupRouter.get('/verify/:token',async (req,res)=>{
    signup.verifyToken(req,res)
})

signupRouter.post('/fbuser',async (req,res)=>{
    signup.postFBuser(req,res)
})

export default signupRouter

 

// controllers/front/signup.js
// npm install nodemailer
// npm install jsonwebtoken
import config from "../../config.js"
import userdb from '../../models/user.js'
import nodemailer from 'nodemailer'
import jwt from 'jsonwebtoken'
import dotenv from 'dotenv'
dotenv.config()

class Signup{
    async getItem(req,res){
        this.config = await config()
        this.config.pageTitle = 'ទំព័រ​ចុះ​ឈ្មោះ​'
        this.config.route = '/signup'

        res.render('base',{data:this.config})
    }

    async registerItem(req,res){
        this.config = await config()
        this.config.pageTitle = 'ទំព័រ​ចុះ​ឈ្មោះ​'
        this.config.route = '/signup'

        if(req.body.password === req.body.password1){
            if(await userdb.checkUser(req)){
                this.config.message = 'Email នេះ​មាន​គេ​ប្រើ​រួច​ហើយ ជ្រើសរើស​ Email ថ្មី​'
                res.render('base',{data:this.config})
            }else{
                this.config.message = `សារ​មួយ​ត្រូវ​បាន​ផ្ញើរ​ទៅ​ Email របស់​លោក​អ្នក សូម​ចុច​បញ្ជាក់​ពី​ការ​ចុះ​ឈ្មោះ​នេះ​`
                this.config.route = '/signup/confirm'
                const userid = await userdb.registerItem(req)
                await this.emailConfirm(req,userid)
                res.render('base',{data:this.config})
            }
        }else{
            this.config.message = 'ពាក្យ​សំងាត់​មិន​ដូច​គ្នា​ទេ សាកល្បង​ម្តង​ទៀត'
            res.render('base',{data:this.config})
        }
    }

    async emailConfirm(req,userid){
        let mailTransporter = nodemailer.createTransport({
            service: 'gmail',
            auth: {
                user: process.env.EMAIL_USER,
                pass: process.env.EMAIL_SECRET
            }
        })
         
        let mailDetails = {
            from: process.env.EMAIL_USER,
            to: req.body.email,
            subject: 'Signup Confirmation',
            text: `ចុច​តំណរភ្ជាប់​នេះ​ដើម្បី​សំរេច​​ចុះ​ឈ្មោះ ${await this.generateToken(req,userid)}`
        }
         
        mailTransporter.sendMail(mailDetails, function(err, data) {
            if(err) {
                console.log(err)
            } else {
                console.log('Email sent successfully')
            }
        })
    }

    async generateToken(req,userid){
        const hostUrl = req.protocol + "://" + req.get('host')

        const date = (new Date()).toString()
        const mail = {
            id: userid,
            created: date
        }

        const token = jwt.sign(mail,process.env.SECRET_KEY,{expiresIn: '1d'})
        return (hostUrl + "/signup/verify/" + token)
    }

    async verifyToken(req,res){
        this.config = await config()
        const token = req.params.token
        if(token){
            try{
                jwt.verify(token,process.env.SECRET_KEY,(err,decoded)=>{
                    if(err){
                        console.log(err)
                        return res.sendStatus(403)
                    }else{
                        userdb.upgradeItem(req,decoded.id)
                        this.config.pageTitle = 'ផ្ទៀងផ្ទាត់​ពាក្យ​សំងាត់'
                        this.config.route = '/login'
                        this.config.message = 'អ្នក​អាច​​​​​​​​​​​​ចុះឈ្មោះចុះ​ផ្សាយ​លក់​ទំនិញ​បាន​ហើយ'

                        res.render('base',{data:this.config})
                    }
                })
            }catch(err){
                console.log(err)
                return res.sendStatus(403)
            }
        }else{
            return res.sendStatus(403)
        }
    }

    async postFBuser(req,res){
        const user = await userdb.editItem(req,req.body.id)
        if(user){
            res.json({message:'​​ឈ្មោះ​​​​​​​​​​​នេះត្រូវ​បាន​ចុះ​បញ្ជី​រួចម្តង​​ហើយ'})
        }else{
            await userdb.postFBuser(req)
            const redirectUrl = req.protocol + "://" + req.get('host') + '/login'
            res.json({message:'​​ឈ្មោះ​លោក​អ្នក​ត្រូវ​បាន​ចុះបញ្ជី​រួចរាល់​ហើយ',redirect:redirectUrl})
        }
    }
}

export default new Signup()

 

// models/user.js
// npm install bcryptjs
import bcrypt from 'bcryptjs'

class User{
    async checkUser(req){
        const query = {email:req.body.email}
        return await req.mydb.collection("users").findOne(query)
    }

    async count(req){
        return await req.mydb.collection('users').countDocuments()
    }

    async postItem(req){
        const id = Date.now() + Math.round(Math.random() * 1E9).toString()
        const hashPassword = bcrypt.hashSync(req.body.password, 12)

        let newUser = {
            id: id, 
            title: req.body.title,
            content: req.body.content,
            thumb: req.body.thumb,
            postdate: req.body.datetime,
            role: req.body.category,
            email: req.body.email,
            password: hashPassword,
        }
 
        await req.mydb.collection("users").insertOne(newUser)
    }

    async registerItem(req){
        const id = Date.now() + Math.round(Math.random() * 1E9).toString()
        const hashPassword = bcrypt.hashSync(req.body.password, 12)

        if(req.body.thumb){
            var thumb = req.body.thumb
        }else{
            var thumb = '/images/userthumb.png'
        }

        const now = new Date();
        const date = new Date(now.getTime() - now.getTimezoneOffset() * 60000).toISOString().substring(0, 16)

        let newUser = {
            id: id, 
            title: req.body.title,
            content: null,
            thumb: thumb,
            postdate: date,
            role: 'subscriber',
            email: req.body.email,
            password: hashPassword,
        }
 
        await req.mydb.collection("users").insertOne(newUser)
        return id
    }

    async upgradeItem(req,userid){
        await req.mydb.collection("users").updateOne({id:userid},{$set:{role:'Author'}})
    }

    async getItem(req,amount){
        return await req.mydb.collection("users").find().sort({date:-1,_id:-1}).limit(amount).toArray()
    }

    async editItem(req,userid){
        return await req.mydb.collection('users').findOne({id:userid})
    }

    async updateItem(req){
        let myquery = {id: req.params.id}

        const user = await req.mydb.collection('users').findOne({id:req.params.id})

        if(req.body.password === user.password){
            var hashPassword = req.body.password
        }else{
            var hashPassword = bcrypt.hashSync(req.body.password, 12)
        }

        let newvalue = {$set: {
            title: req.body.title,
            content: req.body.content,
            thumb: req.body.thumb,
            postdate: req.body.datetime,
            role: req.body.category,
            email: req.body.email,
            password: hashPassword
        }}
 
        await req.mydb.collection("users").updateOne(myquery,newvalue)
    }

    async updateAuthor(req){
        let myquery = {id: req.params.id}

        if(req.body.password === req.session.user.password){
            var hashPassword = req.body.password
        }else{
            var hashPassword = bcrypt.hashSync(req.body.password, 12)
        }

        let newvalue = {$set: {
            title: req.body.title,
            content: req.body.content,
            thumb: req.body.thumb,
            postdate: req.body.datetime,
            email: req.body.email,
            password: hashPassword
        }}
 
        await req.mydb.collection("users").updateOne(myquery,newvalue)
    }

    async deleteItem(req){
        await req.mydb.collection("users").deleteOne({id:req.params.id})
    }

    async paginateItem(req,amount){
        const page = req.body.page
        return await req.mydb.collection("users").find().skip(amount*page).sort({postdate:-1,_id:-1}).limit(amount).toArray()
    }

    async postFBuser(req){
        const now = new Date();
        const date = new Date(now.getTime() - now.getTimezoneOffset() * 60000).toISOString().substring(0, 16)

        let newUser = {
            id: req.body.id, 
            title: req.body.name,
            content: null,
            thumb: '/images/userthumb.png',
            postdate: date,
            role: 'Author',
            email: null,
            password: null,
        }
 
        await req.mydb.collection("users").insertOne(newUser)
    }
}

export default new User()

 

Heroku: https://khmerweb-sale.herokuapp.com