feat: update database fields
This commit is contained in:
3
assets/migration/README.md
Normal file
3
assets/migration/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Migration
|
||||
|
||||
This directory contains the migration scripts for the database.
|
||||
49
assets/migration/v1_to_v2.sqlite.sql
Normal file
49
assets/migration/v1_to_v2.sqlite.sql
Normal file
@@ -0,0 +1,49 @@
|
||||
-- Migration script for coconut-leaf database v1 to v2
|
||||
-- This script updates field names by:
|
||||
-- 1. Removing 'ccn_' prefix from all fields
|
||||
-- 2. Converting camelCase to snake_case
|
||||
|
||||
-- Step 1: Rename user table columns
|
||||
ALTER TABLE user RENAME COLUMN ccn_name TO name;
|
||||
ALTER TABLE user RENAME COLUMN ccn_password TO password;
|
||||
ALTER TABLE user RENAME COLUMN ccn_isAdmin TO is_admin;
|
||||
ALTER TABLE user RENAME COLUMN ccn_salt TO salt;
|
||||
|
||||
-- Step 2: Rename token table columns
|
||||
ALTER TABLE token RENAME COLUMN ccn_user TO user;
|
||||
ALTER TABLE token RENAME COLUMN ccn_token TO token;
|
||||
ALTER TABLE token RENAME COLUMN ccn_tokenExpireOn TO token_expire_on;
|
||||
ALTER TABLE token RENAME COLUMN ccn_ua TO ua;
|
||||
ALTER TABLE token RENAME COLUMN ccn_ip TO ip;
|
||||
|
||||
-- Step 3: Rename collection table columns
|
||||
ALTER TABLE collection RENAME COLUMN ccn_uuid TO uuid;
|
||||
ALTER TABLE collection RENAME COLUMN ccn_name TO name;
|
||||
ALTER TABLE collection RENAME COLUMN ccn_user TO user;
|
||||
ALTER TABLE collection RENAME COLUMN ccn_lastChange TO last_change;
|
||||
|
||||
-- Step 4: Rename share table columns
|
||||
ALTER TABLE share RENAME COLUMN ccn_uuid TO uuid;
|
||||
ALTER TABLE share RENAME COLUMN ccn_target TO target;
|
||||
|
||||
-- Step 5: Rename calendar table columns
|
||||
ALTER TABLE calendar RENAME COLUMN ccn_uuid TO uuid;
|
||||
ALTER TABLE calendar RENAME COLUMN ccn_belongTo TO belong_to;
|
||||
ALTER TABLE calendar RENAME COLUMN ccn_title TO title;
|
||||
ALTER TABLE calendar RENAME COLUMN ccn_description TO description;
|
||||
ALTER TABLE calendar RENAME COLUMN ccn_lastChange TO last_change;
|
||||
ALTER TABLE calendar RENAME COLUMN ccn_eventDateTimeStart TO event_date_time_start;
|
||||
ALTER TABLE calendar RENAME COLUMN ccn_eventDateTimeEnd TO event_date_time_end;
|
||||
ALTER TABLE calendar RENAME COLUMN ccn_timezoneOffset TO timezone_offset;
|
||||
ALTER TABLE calendar RENAME COLUMN ccn_loopRules TO loop_rules;
|
||||
ALTER TABLE calendar RENAME COLUMN ccn_loopDateTimeStart TO loop_date_time_start;
|
||||
ALTER TABLE calendar RENAME COLUMN ccn_loopDateTimeEnd TO loop_date_time_end;
|
||||
|
||||
-- Step 6: Rename todo table columns
|
||||
ALTER TABLE todo RENAME COLUMN ccn_uuid TO uuid;
|
||||
ALTER TABLE todo RENAME COLUMN ccn_belongTo TO belong_to;
|
||||
ALTER TABLE todo RENAME COLUMN ccn_data TO data;
|
||||
ALTER TABLE todo RENAME COLUMN ccn_lastChange TO last_change;
|
||||
|
||||
-- Note: Foreign key constraints will be automatically updated by SQLite when renaming columns
|
||||
-- No additional steps needed for foreign keys
|
||||
@@ -119,10 +119,10 @@ class CalendarDatabase:
|
||||
# ======================= token related internal operation
|
||||
def tokenOper_clean(self):
|
||||
# remove outdated token
|
||||
self.cursor.execute('DELETE FROM token WHERE [ccn_tokenExpireOn] <= ?',(utils.GetCurrentTimestamp(), ))
|
||||
self.cursor.execute('DELETE FROM token WHERE [token_expire_on] <= ?',(utils.GetCurrentTimestamp(), ))
|
||||
|
||||
def tokenOper_postpone_expireOn(self, token):
|
||||
self.cursor.execute('UPDATE token SET [ccn_tokenExpireOn] = ? WHERE [ccn_token] = ?;', (
|
||||
self.cursor.execute('UPDATE token SET [token_expire_on] = ? WHERE [token] = ?;', (
|
||||
utils.GetTokenExpireOn(),
|
||||
token
|
||||
))
|
||||
@@ -131,12 +131,12 @@ class CalendarDatabase:
|
||||
self.tokenOper_get_username(token)
|
||||
|
||||
def tokenOper_is_admin(self, username):
|
||||
self.cursor.execute('SELECT [ccn_isAdmin] FROM user WHERE [ccn_name] = ?;',(username, ))
|
||||
self.cursor.execute('SELECT [is_admin] FROM user WHERE [name] = ?;',(username, ))
|
||||
cache = self.cursor.fetchone()[0]
|
||||
return cache == 1
|
||||
|
||||
def tokenOper_get_username(self, token):
|
||||
self.cursor.execute('SELECT [ccn_user] FROM token WHERE [ccn_token] = ? AND [ccn_tokenExpireOn] > ?;',(
|
||||
self.cursor.execute('SELECT [user] FROM token WHERE [token] = ? AND [token_expire_on] > ?;',(
|
||||
token,
|
||||
utils.GetCurrentTimestamp()
|
||||
))
|
||||
@@ -151,7 +151,7 @@ class CalendarDatabase:
|
||||
@SafeDatabaseOperation
|
||||
def common_salt(self, username):
|
||||
salt = utils.GenerateSalt()
|
||||
self.cursor.execute('UPDATE user SET [ccn_salt] = ? WHERE [ccn_name] = ?;', (
|
||||
self.cursor.execute('UPDATE user SET [salt] = ? WHERE [name] = ?;', (
|
||||
salt,
|
||||
username
|
||||
))
|
||||
@@ -159,12 +159,12 @@ class CalendarDatabase:
|
||||
|
||||
@SafeDatabaseOperation
|
||||
def common_login(self, username, password, clientUa, clientIp):
|
||||
self.cursor.execute('SELECT [ccn_password], [ccn_salt] FROM user WHERE [ccn_name] = ?;', (username, ))
|
||||
self.cursor.execute('SELECT [password], [salt] FROM user WHERE [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_salt] = ? WHERE [ccn_name] = ?;', (
|
||||
self.cursor.execute('UPDATE user SET [salt] = ? WHERE [name] = ?;', (
|
||||
utils.GenerateSalt(), # regenerate a new slat to prevent re-login try
|
||||
username
|
||||
))
|
||||
@@ -182,7 +182,7 @@ class CalendarDatabase:
|
||||
|
||||
@SafeDatabaseOperation
|
||||
def common_webLogin(self, username, password, clientUa, clientIp):
|
||||
self.cursor.execute('SELECT [ccn_name] FROM user WHERE [ccn_name] = ? AND [ccn_password] = ?;', (username, utils.ComputePasswordHash(password)))
|
||||
self.cursor.execute('SELECT [name] FROM user WHERE [name] = ? AND [password] = ?;', (username, utils.ComputePasswordHash(password)))
|
||||
|
||||
if len(self.cursor.fetchall()) != 0:
|
||||
token = utils.GenerateToken(username)
|
||||
@@ -201,7 +201,7 @@ class CalendarDatabase:
|
||||
@SafeDatabaseOperation
|
||||
def common_logout(self, token):
|
||||
self.tokenOper_check_valid(token)
|
||||
self.cursor.execute('DELETE FROM token WHERE [ccn_token] = ?;', (token, ))
|
||||
self.cursor.execute('DELETE FROM token WHERE [token] = ?;', (token, ))
|
||||
return True
|
||||
|
||||
@SafeDatabaseOperation
|
||||
@@ -214,24 +214,24 @@ class CalendarDatabase:
|
||||
def calendar_getFull(self, token, startDateTime, endDateTime):
|
||||
username = self.tokenOper_get_username(token)
|
||||
self.cursor.execute('SELECT calendar.* FROM calendar INNER JOIN collection \
|
||||
ON collection.ccn_uuid = calendar.ccn_belongTo \
|
||||
WHERE (collection.ccn_user = ? AND calendar.ccn_loopDateTimeEnd >= ? AND calendar.ccn_loopDateTimeStart - (calendar.ccn_eventDateTimeEnd - calendar.ccn_eventDateTimeStart) <= ?);',
|
||||
ON collection.uuid = calendar.belong_to \
|
||||
WHERE (collection.user = ? AND calendar.loop_date_time_end >= ? AND calendar.loop_date_time_start - (calendar.event_date_time_end - calendar.event_date_time_start) <= ?);',
|
||||
(username, startDateTime, endDateTime))
|
||||
return self.cursor.fetchall()
|
||||
|
||||
@SafeDatabaseOperation
|
||||
def calendar_getList(self, token, startDateTime, endDateTime):
|
||||
username = self.tokenOper_get_username(token)
|
||||
self.cursor.execute('SELECT calendar.ccn_uuid FROM calendar INNER JOIN collection \
|
||||
ON collection.ccn_uuid = calendar.ccn_belongTo \
|
||||
WHERE (collection.ccn_user = ? AND calendar.ccn_loopDateTimeEnd >= ? AND calendar.ccn_loopDateTimeStart - (calendar.ccn_eventDateTimeEnd - calendar.ccn_eventDateTimeStart) <= ?);',
|
||||
self.cursor.execute('SELECT calendar.uuid FROM calendar INNER JOIN collection \
|
||||
ON collection.uuid = calendar.belong_to \
|
||||
WHERE (collection.user = ? AND calendar.loop_date_time_end >= ? AND calendar.loop_date_time_start - (calendar.event_date_time_end - calendar.event_date_time_start) <= ?);',
|
||||
(username, startDateTime, endDateTime))
|
||||
return tuple(map(lambda x: x[0], self.cursor.fetchall()))
|
||||
|
||||
@SafeDatabaseOperation
|
||||
def calendar_getDetail(self, token, uuid):
|
||||
self.tokenOper_check_valid(token)
|
||||
self.cursor.execute('SELECT * FROM calendar WHERE [ccn_uuid] = ?;', (uuid, ))
|
||||
self.cursor.execute('SELECT * FROM calendar WHERE [uuid] = ?;', (uuid, ))
|
||||
return self.cursor.fetchone()
|
||||
|
||||
@SafeDatabaseOperation
|
||||
@@ -239,13 +239,13 @@ class CalendarDatabase:
|
||||
self.tokenOper_check_valid(token)
|
||||
|
||||
# get prev data
|
||||
self.cursor.execute('SELECT * FROM calendar WHERE [ccn_uuid] = ? AND [ccn_lastChange] = ?;', (uuid, lastChange))
|
||||
self.cursor.execute('SELECT * FROM calendar WHERE [uuid] = ? AND [last_change] = ?;', (uuid, lastChange))
|
||||
analyseData = list(self.cursor.fetchone())
|
||||
|
||||
# construct update data
|
||||
lastupdate = utils.GenerateUUID()
|
||||
sqlList = [
|
||||
'[ccn_lastChange] = ?',
|
||||
'[last_change] = ?',
|
||||
]
|
||||
argumentsList = [
|
||||
lastupdate,
|
||||
@@ -256,44 +256,44 @@ class CalendarDatabase:
|
||||
|
||||
cache = optArgs.get('belongTo', None)
|
||||
if cache is not None:
|
||||
sqlList.append('[ccn_belongTo] = ?')
|
||||
sqlList.append('[belong_to] = ?')
|
||||
argumentsList.append(cache)
|
||||
cache = optArgs.get('title', None)
|
||||
if cache is not None:
|
||||
sqlList.append('[ccn_title] = ?')
|
||||
sqlList.append('[title] = ?')
|
||||
argumentsList.append(cache)
|
||||
cache = optArgs.get('description', None)
|
||||
if cache is not None:
|
||||
sqlList.append('[ccn_description] = ?')
|
||||
sqlList.append('[description] = ?')
|
||||
argumentsList.append(cache)
|
||||
cache = optArgs.get('eventDateTimeStart', None)
|
||||
if cache is not None:
|
||||
sqlList.append('[ccn_eventDateTimeStart] = ?')
|
||||
sqlList.append('[event_date_time_start] = ?')
|
||||
argumentsList.append(cache)
|
||||
reAnalyseLoop = True
|
||||
analyseData[5] = cache
|
||||
cache = optArgs.get('eventDateTimeEnd', None)
|
||||
if cache is not None:
|
||||
sqlList.append('[ccn_eventDateTimeEnd] = ?')
|
||||
sqlList.append('[event_date_time_end] = ?')
|
||||
argumentsList.append(cache)
|
||||
cache = optArgs.get('loopRules', None)
|
||||
if cache is not None:
|
||||
sqlList.append('[ccn_loopRules] = ?')
|
||||
sqlList.append('[loop_rules] = ?')
|
||||
argumentsList.append(cache)
|
||||
reAnalyseLoop = True
|
||||
analyseData[8] = cache
|
||||
cache = optArgs.get('timezoneOffset', None)
|
||||
if cache is not None:
|
||||
sqlList.append('[ccn_timezoneOffset] = ?')
|
||||
sqlList.append('[timezone_offset] = ?')
|
||||
argumentsList.append(cache)
|
||||
reAnalyseLoop = True
|
||||
analyseData[7] = cache
|
||||
|
||||
if reAnalyseLoop:
|
||||
# re-compute loop data and upload it into list
|
||||
sqlList.append('[ccn_loopDateTimeStart] = ?')
|
||||
sqlList.append('[loop_date_time_start] = ?')
|
||||
argumentsList.append(analyseData[5])
|
||||
sqlList.append('[ccn_loopDateTimeEnd] = ?')
|
||||
sqlList.append('[loop_date_time_end] = ?')
|
||||
argumentsList.append(str(dt.ResolveLoopStr(
|
||||
analyseData[8],
|
||||
analyseData[5],
|
||||
@@ -302,7 +302,7 @@ class CalendarDatabase:
|
||||
|
||||
# execute
|
||||
argumentsList.append(uuid)
|
||||
self.cursor.execute('UPDATE calendar SET {} WHERE [ccn_uuid] = ?;'.format(', '.join(sqlList)),
|
||||
self.cursor.execute('UPDATE calendar SET {} WHERE [uuid] = ?;'.format(', '.join(sqlList)),
|
||||
tuple(argumentsList))
|
||||
if self.cursor.rowcount != 1:
|
||||
raise Exception('Fail to update due to no matched rows or too much rows.')
|
||||
@@ -336,7 +336,7 @@ class CalendarDatabase:
|
||||
@SafeDatabaseOperation
|
||||
def calendar_delete(self, token, uuid, lastChange):
|
||||
self.tokenOper_check_valid(token)
|
||||
self.cursor.execute('DELETE FROM calendar WHERE [ccn_uuid] = ? AND [ccn_lastChange] = ?;', (uuid, lastChange))
|
||||
self.cursor.execute('DELETE FROM calendar WHERE [uuid] = ? AND [last_change] = ?;', (uuid, lastChange))
|
||||
if self.cursor.rowcount != 1:
|
||||
raise Exception('Fail to delete due to no matched rows or too much rows.')
|
||||
return True
|
||||
@@ -345,19 +345,19 @@ class CalendarDatabase:
|
||||
@SafeDatabaseOperation
|
||||
def collection_getFullOwn(self, token):
|
||||
username = self.tokenOper_get_username(token)
|
||||
self.cursor.execute('SELECT [ccn_uuid], [ccn_name], [ccn_lastChange] FROM collection WHERE [ccn_user] = ?;', (username, ))
|
||||
self.cursor.execute('SELECT [uuid], [name], [last_change] FROM collection WHERE [user] = ?;', (username, ))
|
||||
return self.cursor.fetchall()
|
||||
|
||||
@SafeDatabaseOperation
|
||||
def collection_getListOwn(self, token):
|
||||
username = self.tokenOper_get_username(token)
|
||||
self.cursor.execute('SELECT [ccn_uuid] FROM collection WHERE [ccn_user] = ?;', (username, ))
|
||||
self.cursor.execute('SELECT [uuid] FROM collection WHERE [user] = ?;', (username, ))
|
||||
return tuple(map(lambda x: x[0], self.cursor.fetchall()))
|
||||
|
||||
@SafeDatabaseOperation
|
||||
def collection_getDetailOwn(self, token, uuid):
|
||||
username = self.tokenOper_get_username(token)
|
||||
self.cursor.execute('SELECT [ccn_uuid], [ccn_name], [ccn_lastChange] FROM collection WHERE [ccn_user] = ? AND [ccn_uuid] = ?;', (username, uuid))
|
||||
self.cursor.execute('SELECT [uuid], [name], [last_change] FROM collection WHERE [user] = ? AND [uuid] = ?;', (username, uuid))
|
||||
return self.cursor.fetchone()
|
||||
|
||||
@SafeDatabaseOperation
|
||||
@@ -374,7 +374,7 @@ class CalendarDatabase:
|
||||
self.tokenOper_check_valid(token)
|
||||
|
||||
lastupdate = utils.GenerateUUID()
|
||||
self.cursor.execute('UPDATE collection SET [ccn_name] = ?, [ccn_lastChange] = ? WHERE [ccn_uuid] = ? AND [ccn_lastChange] = ?;', (
|
||||
self.cursor.execute('UPDATE collection SET [name] = ?, [last_change] = ? WHERE [uuid] = ? AND [last_change] = ?;', (
|
||||
newname,
|
||||
lastupdate,
|
||||
uuid,
|
||||
@@ -388,7 +388,7 @@ class CalendarDatabase:
|
||||
def collection_deleteOwn(self, token, uuid, lastChange):
|
||||
self.tokenOper_check_valid(token)
|
||||
|
||||
self.cursor.execute('DELETE FROM collection WHERE [ccn_uuid] = ? AND [ccn_lastChange] = ?;', (
|
||||
self.cursor.execute('DELETE FROM collection WHERE [uuid] = ? AND [last_change] = ?;', (
|
||||
uuid,
|
||||
lastChange
|
||||
))
|
||||
@@ -399,7 +399,7 @@ class CalendarDatabase:
|
||||
@SafeDatabaseOperation
|
||||
def collection_getSharing(self, token, uuid):
|
||||
self.tokenOper_check_valid(token)
|
||||
self.cursor.execute('SELECT [ccn_target] FROM share WHERE [ccn_uuid] = ?;', (uuid, ))
|
||||
self.cursor.execute('SELECT [target] FROM share WHERE [uuid] = ?;', (uuid, ))
|
||||
return tuple(map(lambda x: x[0], self.cursor.fetchall()))
|
||||
|
||||
@SafeDatabaseOperation
|
||||
@@ -407,11 +407,11 @@ class CalendarDatabase:
|
||||
self.tokenOper_check_valid(token)
|
||||
|
||||
lastupdate = utils.GenerateUUID()
|
||||
self.cursor.execute('UPDATE collection SET [ccn_lastChange] = ?, WHERE [ccn_uuid] = ? AND [ccn_lastChange] = ?;', (lastupdate, uuid, lastChange))
|
||||
self.cursor.execute('UPDATE collection SET [last_change] = ?, WHERE [uuid] = ? AND [last_change] = ?;', (lastupdate, uuid, lastChange))
|
||||
if self.cursor.rowcount != 1:
|
||||
raise Exception('Fail to delete due to no matched rows or too much rows.')
|
||||
|
||||
self.cursor.execute('DELETE FROM share WHERE [ccn_uuid] = ? AND [ccn_target] = ?;', (uuid, target))
|
||||
self.cursor.execute('DELETE FROM share WHERE [uuid] = ? AND [target] = ?;', (uuid, target))
|
||||
if self.cursor.rowcount != 1:
|
||||
raise Exception('Fail to delete due to no matched rows or too much rows.')
|
||||
|
||||
@@ -422,11 +422,11 @@ class CalendarDatabase:
|
||||
self.tokenOper_check_valid(token)
|
||||
|
||||
lastupdate = utils.GenerateUUID()
|
||||
self.cursor.execute('UPDATE collection SET [ccn_lastChange] = ? WHERE [ccn_uuid] = ? AND [ccn_lastChange] = ?;', (lastupdate, uuid, lastChange))
|
||||
self.cursor.execute('UPDATE collection SET [last_change] = ? WHERE [uuid] = ? AND [last_change] = ?;', (lastupdate, uuid, lastChange))
|
||||
if self.cursor.rowcount != 1:
|
||||
raise Exception('Fail to delete due to no matched rows or too much rows.')
|
||||
|
||||
self.cursor.execute('SELECT * FROM share WHERE [ccn_uuid] = ? AND [ccn_target] = ?;', (uuid, target))
|
||||
self.cursor.execute('SELECT * FROM share WHERE [uuid] = ? AND [target] = ?;', (uuid, target))
|
||||
if len(self.cursor.fetchall()) != 0:
|
||||
raise Exception('Fail to insert duplicated item.')
|
||||
self.cursor.execute('INSERT INTO share VALUES (?, ?);', (uuid, target))
|
||||
@@ -436,29 +436,29 @@ class CalendarDatabase:
|
||||
@SafeDatabaseOperation
|
||||
def collection_getShared(self, token):
|
||||
username = self.tokenOper_get_username(token)
|
||||
self.cursor.execute('SELECT collection.ccn_uuid, collection.ccn_name, collection.ccn_user \
|
||||
self.cursor.execute('SELECT collection.uuid, collection.name, collection.user \
|
||||
FROM share INNER JOIN collection \
|
||||
ON share.ccn_uuid = collection.ccn_uuid \
|
||||
WHERE share.ccn_target = ?;', (username, ))
|
||||
ON share.uuid = collection.uuid \
|
||||
WHERE share.target = ?;', (username, ))
|
||||
return self.cursor.fetchall()
|
||||
|
||||
# =============================== todo
|
||||
@SafeDatabaseOperation
|
||||
def todo_getFull(self, token):
|
||||
username = self.tokenOper_get_username(token)
|
||||
self.cursor.execute('SELECT * FROM todo WHERE [ccn_belongTo] = ?;', (username, ))
|
||||
self.cursor.execute('SELECT * FROM todo WHERE [belong_to] = ?;', (username, ))
|
||||
return self.cursor.fetchall()
|
||||
|
||||
@SafeDatabaseOperation
|
||||
def todo_getList(self, token):
|
||||
username = self.tokenOper_get_username(token)
|
||||
self.cursor.execute('SELECT [ccn_uuid] FROM todo WHERE [ccn_belongTo] = ?;', (username, ))
|
||||
self.cursor.execute('SELECT [uuid] FROM todo WHERE [belong_to] = ?;', (username, ))
|
||||
return tuple(map(lambda x: x[0], self.cursor.fetchall()))
|
||||
|
||||
@SafeDatabaseOperation
|
||||
def todo_getDetail(self, token, uuid):
|
||||
username = self.tokenOper_get_username(token)
|
||||
self.cursor.execute('SELECT * FROM todo WHERE [ccn_belongTo] = ? AND [ccn_uuid] = ?;', (username, uuid))
|
||||
self.cursor.execute('SELECT * FROM todo WHERE [belong_to] = ? AND [uuid] = ?;', (username, uuid))
|
||||
return self.cursor.fetchone()
|
||||
|
||||
@SafeDatabaseOperation
|
||||
@@ -482,7 +482,7 @@ class CalendarDatabase:
|
||||
|
||||
# update
|
||||
newLastChange = utils.GenerateUUID()
|
||||
self.cursor.execute('UPDATE todo SET [ccn_data] = ?, [ccn_lastChange] = ? WHERE [ccn_uuid] = ? AND [ccn_lastChange] = ?;', (
|
||||
self.cursor.execute('UPDATE todo SET [data] = ?, [last_change] = ? WHERE [uuid] = ? AND [last_change] = ?;', (
|
||||
data,
|
||||
newLastChange,
|
||||
uuid,
|
||||
@@ -498,7 +498,7 @@ class CalendarDatabase:
|
||||
self.tokenOper_check_valid(token)
|
||||
|
||||
# delete
|
||||
self.cursor.execute('DELETE FROM todo WHERE [ccn_uuid] = ? AND [ccn_lastChange] = ?;', (uuid, lastChange))
|
||||
self.cursor.execute('DELETE FROM todo WHERE [uuid] = ? AND [last_change] = ?;', (uuid, lastChange))
|
||||
if self.cursor.rowcount != 1:
|
||||
raise Exception('Fail to delete due to no matched rows or too much rows.')
|
||||
return True
|
||||
@@ -511,7 +511,7 @@ class CalendarDatabase:
|
||||
if not self.tokenOper_is_admin(username):
|
||||
raise Exception('Permission denied.')
|
||||
|
||||
self.cursor.execute('SELECT [ccn_name], [ccn_isAdmin] FROM user;')
|
||||
self.cursor.execute('SELECT [name], [is_admin] FROM user;')
|
||||
return tuple(map(lambda x: (x[0], x[1] == 1), self.cursor.fetchall()))
|
||||
|
||||
@SafeDatabaseOperation
|
||||
@@ -542,16 +542,16 @@ class CalendarDatabase:
|
||||
# analyse opt arg
|
||||
cache = optArgs.get('password', None)
|
||||
if cache is not None:
|
||||
sqlList.append('[ccn_password] = ?')
|
||||
sqlList.append('[password] = ?')
|
||||
argumentsList.append(utils.ComputePasswordHash(cache))
|
||||
cache = optArgs.get('isAdmin', None)
|
||||
if cache is not None:
|
||||
sqlList.append('[ccn_isAdmin] = ?')
|
||||
sqlList.append('[is_admin] = ?')
|
||||
argumentsList.append(1 if cache else 0)
|
||||
|
||||
# execute
|
||||
argumentsList.append(_username)
|
||||
self.cursor.execute('UPDATE user SET {} WHERE [ccn_name] = ?;'.format(', '.join(sqlList)),
|
||||
self.cursor.execute('UPDATE user SET {} WHERE [name] = ?;'.format(', '.join(sqlList)),
|
||||
tuple(argumentsList))
|
||||
logging.debug(cache)
|
||||
logging.debug(tuple(argumentsList))
|
||||
@@ -566,7 +566,7 @@ class CalendarDatabase:
|
||||
raise Exception('Permission denied.')
|
||||
|
||||
# delete
|
||||
self.cursor.execute('DELETE FROM user WHERE [ccn_name] = ?;', (username, ))
|
||||
self.cursor.execute('DELETE FROM user WHERE [name] = ?;', (username, ))
|
||||
if self.cursor.rowcount != 1:
|
||||
raise Exception('Fail to delete due to no matched rows or too much rows.')
|
||||
return True
|
||||
@@ -580,7 +580,7 @@ class CalendarDatabase:
|
||||
@SafeDatabaseOperation
|
||||
def profile_changePassword(self, token, newpassword):
|
||||
username = self.tokenOper_get_username(token)
|
||||
self.cursor.execute('UPDATE user SET [ccn_password] = ? WHERE [ccn_name] = ?;', (
|
||||
self.cursor.execute('UPDATE user SET [password] = ? WHERE [name] = ?;', (
|
||||
utils.ComputePasswordHash(newpassword),
|
||||
username
|
||||
))
|
||||
@@ -590,7 +590,7 @@ class CalendarDatabase:
|
||||
def profile_getToken(self, token):
|
||||
username = self.tokenOper_get_username(token)
|
||||
|
||||
self.cursor.execute('SELECT * FROM token WHERE [ccn_user] = ?;', (
|
||||
self.cursor.execute('SELECT * FROM token WHERE [user] = ?;', (
|
||||
username,
|
||||
))
|
||||
return self.cursor.fetchall()
|
||||
@@ -600,7 +600,7 @@ class CalendarDatabase:
|
||||
_username = self.tokenOper_get_username(token)
|
||||
|
||||
# delete
|
||||
self.cursor.execute('DELETE FROM token WHERE [ccn_user] = ? AND [ccn_token] = ?;', (
|
||||
self.cursor.execute('DELETE FROM token WHERE [user] = ? AND [token] = ?;', (
|
||||
_username,
|
||||
deleteToken
|
||||
))
|
||||
|
||||
@@ -1,67 +1,67 @@
|
||||
CREATE TABLE user(
|
||||
[ccn_name] TEXT NOT NULL,
|
||||
[ccn_password] TEXT NOT NULL,
|
||||
[ccn_isAdmin] TINYINT NOT NULL CHECK(ccn_isAdmin = 1 OR ccn_isAdmin = 0),
|
||||
[ccn_salt] INTEGER NOT NULL,
|
||||
[name] TEXT NOT NULL,
|
||||
[password] TEXT NOT NULL,
|
||||
[is_admin] TINYINT NOT NULL CHECK(is_admin = 1 OR is_admin = 0),
|
||||
[salt] INTEGER NOT NULL,
|
||||
|
||||
PRIMARY KEY (ccn_name)
|
||||
PRIMARY KEY (name)
|
||||
);
|
||||
|
||||
CREATE TABLE token(
|
||||
[ccn_user] TEXT NOT NULL,
|
||||
[ccn_token] TEXT UNIQUE NOT NULL,
|
||||
[ccn_tokenExpireOn] BIGINT NOT NULL,
|
||||
[ccn_ua] TEXT NOT NULL,
|
||||
[ccn_ip] TEXT NOT NULL,
|
||||
[user] TEXT NOT NULL,
|
||||
[token] TEXT UNIQUE NOT NULL,
|
||||
[token_expire_on] BIGINT NOT NULL,
|
||||
[ua] TEXT NOT NULL,
|
||||
[ip] TEXT NOT NULL,
|
||||
|
||||
FOREIGN KEY (ccn_user) REFERENCES user(ccn_name) ON DELETE CASCADE
|
||||
FOREIGN KEY (user) REFERENCES user(name) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE collection(
|
||||
[ccn_uuid] TEXT NOT NULL,
|
||||
[ccn_name] TEXT NOT NULL,
|
||||
[ccn_user] TEXT NOT NULL,
|
||||
[ccn_lastChange] TEXT NOT NULL,
|
||||
[uuid] TEXT NOT NULL,
|
||||
[name] TEXT NOT NULL,
|
||||
[user] TEXT NOT NULL,
|
||||
[last_change] TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY (ccn_uuid),
|
||||
FOREIGN KEY (ccn_user) REFERENCES user(ccn_name) ON DELETE CASCADE
|
||||
PRIMARY KEY (uuid),
|
||||
FOREIGN KEY (user) REFERENCES user(name) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE share(
|
||||
[ccn_uuid] TEXT NOT NULL,
|
||||
[ccn_target] TEXT NOT NULL,
|
||||
[uuid] TEXT NOT NULL,
|
||||
[target] TEXT NOT NULL,
|
||||
|
||||
FOREIGN KEY (ccn_uuid) REFERENCES collection(ccn_uuid) ON DELETE CASCADE
|
||||
FOREIGN KEY (ccn_target) REFERENCES user(ccn_name) ON DELETE CASCADE
|
||||
FOREIGN KEY (uuid) REFERENCES collection(uuid) ON DELETE CASCADE
|
||||
FOREIGN KEY (target) REFERENCES user(name) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE calendar(
|
||||
[ccn_uuid] TEXT NOT NULL,
|
||||
[ccn_belongTo] TEXT NOT NULL,
|
||||
[uuid] TEXT NOT NULL,
|
||||
[belong_to] TEXT NOT NULL,
|
||||
|
||||
[ccn_title] TEXT NOT NULL,
|
||||
[ccn_description] TEXT NOT NULL,
|
||||
[ccn_lastChange] TEXT NOT NULL,
|
||||
[title] TEXT NOT NULL,
|
||||
[description] TEXT NOT NULL,
|
||||
[last_change] TEXT NOT NULL,
|
||||
|
||||
[ccn_eventDateTimeStart] BIGINT NOT NULL,
|
||||
[ccn_eventDateTimeEnd] BIGINT NOT NULL,
|
||||
[ccn_timezoneOffset] INT NOT NULL,
|
||||
[event_date_time_start] BIGINT NOT NULL,
|
||||
[event_date_time_end] BIGINT NOT NULL,
|
||||
[timezone_offset] INT NOT NULL,
|
||||
|
||||
[ccn_loopRules] TEXT NOT NULL,
|
||||
[ccn_loopDateTimeStart] BIGINT NOT NULL,
|
||||
[ccn_loopDateTimeEnd] BIGINT NOT NULL,
|
||||
[loop_rules] TEXT NOT NULL,
|
||||
[loop_date_time_start] BIGINT NOT NULL,
|
||||
[loop_date_time_end] BIGINT NOT NULL,
|
||||
|
||||
PRIMARY KEY (ccn_uuid),
|
||||
FOREIGN KEY (ccn_belongTo) REFERENCES collection(ccn_uuid) ON DELETE CASCADE
|
||||
PRIMARY KEY (uuid),
|
||||
FOREIGN KEY (belong_to) REFERENCES collection(uuid) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE todo(
|
||||
[ccn_uuid] TEXT NOT NULL,
|
||||
[ccn_belongTo] TEXT NOT NULL,
|
||||
[uuid] TEXT NOT NULL,
|
||||
[belong_to] TEXT NOT NULL,
|
||||
|
||||
[ccn_data] TEXT NOT NULL,
|
||||
[ccn_lastChange] TEXT NOT NULL,
|
||||
[data] TEXT NOT NULL,
|
||||
[last_change] TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY (ccn_uuid),
|
||||
FOREIGN KEY (ccn_belongTo) REFERENCES user(ccn_name) ON DELETE CASCADE
|
||||
PRIMARY KEY (uuid),
|
||||
FOREIGN KEY (belong_to) REFERENCES user(name) ON DELETE CASCADE
|
||||
);
|
||||
@@ -1,61 +0,0 @@
|
||||
# ============================
|
||||
# 路由 1: /web -> 静态文件
|
||||
# ============================
|
||||
location /web {
|
||||
# 使用 alias 精确映射
|
||||
# 请求 /web/index.html -> /var/www/static/index.html
|
||||
alias /var/www/static;
|
||||
|
||||
# 静态文件优化
|
||||
expires 7d;
|
||||
add_header Cache-Control "public, max-age=604800";
|
||||
|
||||
# 尝试返回文件,不存在则返回404(避免落入其他location)
|
||||
try_files $uri $uri/ =404;
|
||||
|
||||
# 可选:启用 gzip 压缩
|
||||
gzip_static on;
|
||||
}
|
||||
|
||||
# ============================
|
||||
# 路由 2: /api -> Go 程序 (8848端口)
|
||||
# ============================
|
||||
location /api {
|
||||
# 反向代理到本地 Go 服务
|
||||
proxy_pass http://127.0.0.1:8848;
|
||||
|
||||
# 重要:保留原始请求头
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# WebSocket 支持(如果 Go 程序需要)
|
||||
# proxy_http_version 1.1;
|
||||
# proxy_set_header Upgrade $http_upgrade;
|
||||
# proxy_set_header Connection "upgrade";
|
||||
|
||||
# 超时设置(根据业务调整)
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
|
||||
# 缓冲设置(可选,大文件上传时注意调整)
|
||||
proxy_buffering on;
|
||||
proxy_buffer_size 4k;
|
||||
proxy_buffers 8 4k;
|
||||
}
|
||||
|
||||
# ============================
|
||||
# 可选:根路径处理
|
||||
# ============================
|
||||
location = / {
|
||||
# 重定向到 /web
|
||||
return 302 /web/;
|
||||
}
|
||||
|
||||
# 禁止访问隐藏文件
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
return 404;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import math
|
||||
|
||||
print('Dial Plate Generator')
|
||||
plateSize = float(input('Plate size: '))
|
||||
hourInnerRadius = float(input('Hour inner radius percent (float): '))
|
||||
hourOutterRadius = float(input('Hour outter radius percent (float): '))
|
||||
minuteRadius = float(input('Minute radius percent (float): '))
|
||||
|
||||
halfPlateSize = plateSize / 2
|
||||
for i in range(24):
|
||||
rad = math.radians(90 - i * 30)
|
||||
x = math.cos(rad)
|
||||
y = math.sin(rad)
|
||||
radius = halfPlateSize * (hourOutterRadius if i < 12 else hourInnerRadius)
|
||||
x = x * radius + halfPlateSize
|
||||
y = (-y * radius) + halfPlateSize
|
||||
print('<text x="{:.6f}" y="{:.6f}">{}</text>'.format(x, y, i))
|
||||
|
||||
print('')
|
||||
|
||||
for i in range(12):
|
||||
rad = math.radians(90 - i * 30)
|
||||
x = math.cos(rad)
|
||||
y = math.sin(rad)
|
||||
radius = minuteRadius * halfPlateSize
|
||||
x = x * radius + halfPlateSize
|
||||
y = (-y * radius) + halfPlateSize
|
||||
print('<text x="{:.6f}" y="{:.6f}">{}</text>'.format(x, y, i * 5))
|
||||
|
||||
Reference in New Issue
Block a user