Adding Signup/Login Functionalities
#controllers/login.py
import config
from bottle import Bottle, template, request, response, redirect
from verify_email import verify_email
from models.userdb import Userdb

userdb = Userdb()

class Login(Bottle):
  def __init__(self):
    super().__init__()
    self.get('/', callback=self.index)
    self.get('/user', callback=self.getUser)
    self.post('/user', callback=self.postUser)
    self.get('/logout', callback=self.logout)
    
  def index(self):
    config.kdict['blogTitle'] = "ចុះឈ្មោះ"
    return template('login', data=config.kdict)

  def postUser(self):
    username = request.forms.getunicode('fusername')
    password = request.forms.getunicode('fpassword')
    email = request.forms.getunicode('femail')

    checkEmail = verify_email(email)

    if checkEmail and username and password:
      result = userdb.checkUser(username, password, email)
      if result:
        config.kdict['user'] = result
        redirect('/')
      else:
        result = userdb.checkUsername(username)
        if not result:
          userdb.insert(username, password, email, 1, False)
          result = userdb.checkUser(username, password, email)
          config.kdict['user'] = result
          redirect('/')
        else:
          config.kdict['message'] = 'ឈ្មោះ​អ្នក​ប្រើប្រាស់​នេះ​ត្រូវ​បាន​គេប្រើ​រួច​ហើយ​។'
          redirect('/login')
    else:
      if not checkEmail:
        config.kdict['message'] = 'Email របស់​លោក​អ្នក​មិនត្រឹមត្រូវ​ទេ។'
        redirect('/login')
      elif not (username or password):
        config.kdict['message'] = 'ត្រូវ​មាន​ឈ្មោះ​អ្នក​ប្រើប្រាស់​និង​ពាក្យ​សំងាត់​។'
        redirect('/login')

  def getUser(self):
    return 'get user'

  def logout(self):
    config.kdict['user'] = ('ភ្ញៀវ', 'អត់មាន', 1)
    redirect('/')
#models/userdb.py
import os, psycopg2

class Userdb():
  def __init__(self):
    self.createTable()

  def setConection(self):
    if 'DYNO' in os.environ:
      DATABASE_URL = os.environ['DATABASE_URL']
      self.conn = psycopg2.connect(DATABASE_URL, sslmode='require')
      self.cursor = self.conn.cursor()
    else: 
      self.conn = psycopg2.connect(
        database="postgres", 
        user="postgres", 
        password="sokhavuth", 
        host="localhost", 
        port="5432"
      )

      self.cursor = self.conn.cursor()
  
  def createTable(self):
    self.setConection()
    
    SQL = '''CREATE TABLE IF NOT EXISTS TYPERS(
      ID SERIAL PRIMARY KEY,
      USERNAME TEXT,
      PASSWORD VARCHAR(320),
      EMAIL VARCHAR(320),
      GRADE INT,
      GRADUATED BOOLEAN NOT NULL
    )'''

    self.cursor.execute(SQL)
  
    self.conn.close()

  def insert(self, *user):
    self.setConection()

    self.cursor.execute("INSERT INTO TYPERS (USERNAME, PASSWORD, EMAIL, GRADE, GRADUATED) VALUES %s ", (user,))
  
    self.conn.commit()
    self.conn.close()

  def checkUser(self, *user):
    self.setConection()

    SQL = "SELECT USERNAME, PASSWORD, GRADE FROM TYPERS WHERE USERNAME = %s AND PASSWORD = %s AND EMAIL = %s LIMIT 1"
    self.cursor.execute(SQL, user)
    result = self.cursor.fetchone()
    
    self.conn.close()

    return result

  def checkUsername(self, username):
    self.setConection()

    SQL = "SELECT USERNAME FROM TYPERS WHERE USERNAME = %s LIMIT 1"
    self.cursor.execute(SQL, (username,))
    result = self.cursor.fetchone()
    
    self.conn.close()

    return result

<!--views/login.tpl-->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>{{data['blogTitle']}}</title>
    <script src="/static/scripts/jQuery.js"></script>
    <script src="/static/scripts/login.js"></script>
    <link href="/static/styles/login.css" rel="stylesheet"></link>
    <link href="/static/images/site_logo.png" rel="icon" ></link>
    <link href="/static/fonts/setup.css" rel="stylesheet"></link>
  </head>
  <body>
    <div id="site">
      <form id="login" action='/login/user' method='post'>
        <div  id='info'>ទំរង់បែបបទ​ចុះ​ឈ្មោះ</div>
        <div class="wrapper">
          <a></a><div style='text-align:center;'><dv class='message'>{{data['message']}}</dv></div>
          %data['message'] = ''
          <a>អ្នក​ប្រើប្រាស់ៈ</a><input class='username' type='text' name='fusername' required />
          <a>ពាក្យ​សំងាត់ៈ</a><input class='password' type='password' name='fpassword' required />
          <a>Email:​</a><input type="email" name="femail" pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$" required />
          <a></a><input type='submit' value='បញ្ជូន' />
        </div>
      </form>
    </div><!--sites-->
  </body>
</html>

GitHub: https://khmerweb-typing.herokuapp.com
Heroku: https://khmerweb-typing.herokuapp.com/