Adding Deleting User Functionality
#controllers/index.py
import config
from copy import deepcopy
from bottle import Bottle, template, static_file, request
from models import lesson, userdb

class Index(Bottle):
    def __init__(self):
        super().__init__()
        self.route('/static/images/<filename>', callback=self.loadImage)
        self.route('/static/styles/<filename>', callback=self.loadStyle)
        self.route('/static/scripts/<filename>', callback=self.loadScript)
        self.route('/static/fonts/<filename>', callback=self.loadFont)
        self.route('/static/sounds/<filename>', callback=self.loadSound)

        self.route('/', callback=self.index)
        self.route('/lesson/<id:int>', callback=self.lesson)
        self.route('/practice/<id:int>', callback=self.practice)

        self.userdb = userdb.Userdb()

    def loadImage(self, filename):
        return static_file(filename, root='./public/images')

    def loadStyle(self, filename):
        return static_file(filename, root='./public/css')

    def loadScript(self, filename):
        return static_file(filename, root='./public/js')

    def loadFont(self, filename):
        return static_file(filename, root='./public/fonts')

    def loadSound(self, filename):
        return static_file(filename, root='./public/sounds')

    def checkLoggedIn(self, kdict):
        username = request.get_cookie('logged-in', secret=kdict['secretKey'])
        if username:
            result = self.userdb.checkUsername(username)
            kdict['user'] = result

    def index(self):
        kdict = deepcopy(config.kdict)
        kdict['blogTitle'] = "រៀន​វាយ​អក្សរ​ខ្មែរ"
        self.checkLoggedIn(kdict)
        return template('index', data=kdict)

    def lesson(self, id):
        kdict = deepcopy(config.kdict)
        kdict['blogTitle'] = 'មេរៀន​ទី '+kdict['KhmerNumber'][id]
        self.checkLoggedIn(kdict)
        kdict['lesson'] = lesson.__dict__['lesson'+str(id)]
        return template('lesson', data=kdict)

    def practice(self, id):
        kdict = deepcopy(config.kdict)
        kdict['blogTitle'] = 'លំហាត់ទី '+kdict['KhmerNumber'][id]
        self.checkLoggedIn(kdict)
        practice = []
        for v in range(id):
            practice += lesson.__dict__['lesson'+str(v+1)]

        kdict['lesson'] = practice
        return template('practice', data=kdict)
#controllers/login.py
import config
from copy import deepcopy
from bottle import Bottle, template, request, response, redirect
from verify_email import verify_email
from models import 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)

    self.userdb = userdb.Userdb()
    
  def index(self):
    kdict = deepcopy(config.kdict)
    kdict['blogTitle'] = "ចុះឈ្មោះ"
    return template('login', data=kdict)

  def postUser(self):
    kdict = deepcopy(config.kdict)
    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 = self.userdb.checkUser(username, password, email)
      if result:
        response.set_cookie('logged-in', result[0], path='/', secret=kdict['secretKey'])
        redirect('/')
      else:
        result = self.userdb.checkUsername(username)
        if not result:
          response.set_cookie('logged-in', username, path='/', secret=kdict['secretKey'])
          self.userdb.insert(username, password, email, 1, False)
          redirect('/')
        else:
          kdict['message'] = 'ឈ្មោះ​អ្នក​ប្រើប្រាស់​នេះ​ត្រូវ​បាន​គេប្រើ​រួច​ហើយ​។'
          return template('login', data=kdict)
    else:
      if not checkEmail:
        kdict['message'] = 'Email របស់​លោក​អ្នក​មិនត្រឹមត្រូវ​ទេ។'
        return template('login', data=kdict)
      elif not (username or password):
        kdict['message'] = 'ត្រូវ​មាន​ឈ្មោះ​អ្នក​ប្រើប្រាស់​និង​ពាក្យ​សំងាត់​។'
        return template('login', data=kdict)

  def getUser(self):
    return 'get user'

  def logout(self):
    kdict = deepcopy(config.kdict)
    username = request.get_cookie('logged-in', secret=kdict['secretKey'])
    if username:
      self.userdb.deleteUser(username)
      
    response.delete_cookie('logged-in', path='/', secret=kdict['secretKey'])
    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, PASSWORD, GRADE FROM TYPERS WHERE USERNAME = %s LIMIT 1"
    self.cursor.execute(SQL, (username,))
    result = self.cursor.fetchone()
    
    self.conn.close()

    return result

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

    self.cursor.execute("DELETE FROM TYPERS WHERE USERNAME = '" + username + "'")

    self.conn.commit()
    self.conn.close()

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