2021-01-16 22:15:10 +08:00
|
|
|
import config
|
|
|
|
|
import sqlite3
|
|
|
|
|
import json
|
2021-01-19 22:20:11 +08:00
|
|
|
import utils
|
|
|
|
|
import threading
|
|
|
|
|
|
|
|
|
|
def SafeDatabaseOperation(func):
|
|
|
|
|
def wrapper(self, *args, **kwargs):
|
|
|
|
|
with self.mutex:
|
|
|
|
|
# check database and acquire cursor
|
|
|
|
|
try:
|
|
|
|
|
self.check_database()
|
|
|
|
|
self.cursor = self.db.cursor()
|
|
|
|
|
except:
|
|
|
|
|
self.cursor = None
|
|
|
|
|
return (False, None)
|
|
|
|
|
|
|
|
|
|
# do real data work
|
|
|
|
|
try:
|
|
|
|
|
result = (True, func(self, *args, **kwargs))
|
|
|
|
|
self.cursor.close()
|
|
|
|
|
self.cursor = None
|
|
|
|
|
self.db.commit()
|
|
|
|
|
return result
|
|
|
|
|
except:
|
|
|
|
|
self.cursor.close()
|
|
|
|
|
self.cursor = None
|
|
|
|
|
self.db.rollback()
|
|
|
|
|
return (False, None)
|
|
|
|
|
|
|
|
|
|
return wrapper
|
2021-01-16 22:15:10 +08:00
|
|
|
|
|
|
|
|
class CalendarDatabase(object):
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.db = None
|
2021-01-19 22:20:11 +08:00
|
|
|
self.cursor = None
|
|
|
|
|
self.mutex = threading.Lock()
|
2021-01-16 22:15:10 +08:00
|
|
|
|
|
|
|
|
def open(self):
|
|
|
|
|
if (self.is_database_valid()):
|
|
|
|
|
raise Exception('Databade is opened')
|
|
|
|
|
|
|
|
|
|
if config.CustomConfig['database-type'] == 'sqlite':
|
|
|
|
|
self.db = sqlite3.connect(config.CustomConfig['database-config']['url'])
|
|
|
|
|
elif config.CustomConfig['database-type'] == 'mysql':
|
|
|
|
|
raise Exception('Not implemented database')
|
|
|
|
|
else:
|
|
|
|
|
raise Exception('Unknow database type')
|
|
|
|
|
|
|
|
|
|
def init(self, username, password):
|
|
|
|
|
if (self.is_database_valid()):
|
|
|
|
|
raise Exception('Databade is opened')
|
|
|
|
|
|
2021-01-19 22:20:11 +08:00
|
|
|
# establish tables
|
2021-01-16 22:15:10 +08:00
|
|
|
self.open()
|
2021-01-19 22:20:11 +08:00
|
|
|
cursor = self.db.cursor()
|
2021-01-16 22:15:10 +08:00
|
|
|
with open('sql/sqlite.sql', 'r', encoding='utf-8') as fsql:
|
|
|
|
|
cursor.executescript(fsql.read())
|
|
|
|
|
|
2021-01-19 22:20:11 +08:00
|
|
|
# finish init
|
|
|
|
|
cursor.execute('INSERT INTO user VALUES (?, ?, ?, ?, ?, ?);', (
|
|
|
|
|
username,
|
|
|
|
|
utils.ComputePasswordHash(password),
|
|
|
|
|
1,
|
|
|
|
|
utils.GenerateSalt(),
|
|
|
|
|
utils.GenerateToken(username),
|
|
|
|
|
0
|
|
|
|
|
))
|
|
|
|
|
cursor.close()
|
|
|
|
|
self.db.commit()
|
2021-01-16 22:15:10 +08:00
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
|
self.check_database()
|
|
|
|
|
self.db.close()
|
|
|
|
|
self.db = None
|
|
|
|
|
|
|
|
|
|
def check_database(self):
|
|
|
|
|
if (not self.is_database_valid()):
|
|
|
|
|
raise Exception('Databade is None')
|
|
|
|
|
|
|
|
|
|
def is_database_valid(self):
|
|
|
|
|
return not (self.db == None)
|
|
|
|
|
|
2021-01-19 22:20:11 +08:00
|
|
|
def get_username_from_token(self, token):
|
|
|
|
|
self.cursor.execute('SELECT [ccn_name] FROM user WHERE [ccn_token] = ? AND [ccn_tokenExpireOn] > ?;',(
|
|
|
|
|
token,
|
|
|
|
|
utils.GetCurrentTimestamp()
|
|
|
|
|
))
|
|
|
|
|
return self.cursor.fetchone()[0]
|
|
|
|
|
|
|
|
|
|
# =============================== # =============================== operation function
|
|
|
|
|
# =============================== common
|
|
|
|
|
@SafeDatabaseOperation
|
|
|
|
|
def common_salt(self, username):
|
|
|
|
|
salt = utils.GenerateSalt()
|
|
|
|
|
self.cursor.execute('UPDATE user SET [ccn_salt] = ? WHERE [ccn_name] = ?;', (
|
|
|
|
|
salt,
|
|
|
|
|
username
|
|
|
|
|
))
|
|
|
|
|
return salt
|
|
|
|
|
|
|
|
|
|
@SafeDatabaseOperation
|
|
|
|
|
def common_login(self, username, password):
|
|
|
|
|
self.cursor.execute('SELECT [ccn_password], [ccn_salt] FROM user WHERE [ccn_name] = ?;', (username, ))
|
|
|
|
|
(gotten_salt, gotten_password) = self.cursor.fetchone()
|
|
|
|
|
|
|
|
|
|
if password == utils.ComputePasswordHashWithSalt(gotten_password, gotten_salt):
|
|
|
|
|
token = utils.GenerateToken(username)
|
|
|
|
|
self.cursor.execute('UPDATE user SET [ccn_token] = ?, [ccn_tokenExpireOn] = ? WHERE [ccn_name] = ?;', (
|
|
|
|
|
token,
|
|
|
|
|
utils.GetCurrentTimestamp() + 60 * 60 * 24 * 2, # add 2 day from now
|
|
|
|
|
username
|
|
|
|
|
))
|
|
|
|
|
return token
|
|
|
|
|
else:
|
|
|
|
|
# return empty string to indicate fail to login
|
|
|
|
|
return ''
|
|
|
|
|
|
|
|
|
|
@SafeDatabaseOperation
|
|
|
|
|
def common_logout(self, token):
|
|
|
|
|
username = self.get_username_from_token(cur, token)
|
|
|
|
|
self.cursor.execute('UPDATE user SET [ccn_tokenExpireOn] = 0 WHERE [ccn_name] = ?;', (username, ))
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
@SafeDatabaseOperation
|
|
|
|
|
def common_tokenValid(self, token):
|
|
|
|
|
# get user name have check the validation, don't do anything more.
|
|
|
|
|
self.get_username_from_token(token)
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
@SafeDatabaseOperation
|
|
|
|
|
def common_isAdmin(self, token):
|
|
|
|
|
username = self.get_username_from_token(token)
|
|
|
|
|
self.cursor.execute('SELECT [ccn_isAdmin] FROM user WHERE [ccn_name] = ?;', (username, ))
|
|
|
|
|
result = self.cursor.fetchone()[0] == 1
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
@SafeDatabaseOperation
|
|
|
|
|
def common_changePassword(self, token, newpassword):
|
|
|
|
|
username = self.get_username_from_token(token)
|
|
|
|
|
self.cursor.execute('UPDATE user SET [ccn_password] = ? WHERE [ccn_name] = ?;', (
|
|
|
|
|
newpassword,
|
|
|
|
|
username
|
|
|
|
|
))
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
# =============================== calendar
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# =============================== collection
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# =============================== todo
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# =============================== admin
|
|
|
|
|
|
2021-01-16 22:15:10 +08:00
|
|
|
|