1
0

nightly commit

This commit is contained in:
2021-01-24 14:38:08 +08:00
parent e4bc3f686f
commit b83b19364c
21 changed files with 223 additions and 107 deletions

View File

@@ -3,6 +3,7 @@ import sqlite3
import json import json
import utils import utils
import threading import threading
import logging
def SafeDatabaseOperation(func): def SafeDatabaseOperation(func):
def wrapper(self, *args, **kwargs): def wrapper(self, *args, **kwargs):
@@ -11,22 +12,31 @@ def SafeDatabaseOperation(func):
try: try:
self.check_database() self.check_database()
self.cursor = self.db.cursor() self.cursor = self.db.cursor()
except: except Exception as e:
self.cursor = None self.cursor = None
return (False, None) if config.CustomConfig['debug']:
logging.exception(e)
return (False, str(e), None)
# do real data work # do real data work
try: try:
result = (True, func(self, *args, **kwargs)) if self.isFirstRun:
self.isFirstRun = False
print('Cleaning outdated token...')
self.tokenOper_clean()
result = (True, '', func(self, *args, **kwargs))
self.cursor.close() self.cursor.close()
self.cursor = None self.cursor = None
self.db.commit() self.db.commit()
return result return result
except: except Exception as e:
self.cursor.close() self.cursor.close()
self.cursor = None self.cursor = None
self.db.rollback() self.db.rollback()
return (False, None) if config.CustomConfig['debug']:
logging.exception(e)
return (False, str(e), None)
return wrapper return wrapper
@@ -35,6 +45,7 @@ class CalendarDatabase(object):
self.db = None self.db = None
self.cursor = None self.cursor = None
self.mutex = threading.Lock() self.mutex = threading.Lock()
self.isFirstRun = True
def open(self): def open(self):
if (self.is_database_valid()): if (self.is_database_valid()):
@@ -49,7 +60,7 @@ class CalendarDatabase(object):
def init(self, username, password): def init(self, username, password):
if (self.is_database_valid()): if (self.is_database_valid()):
raise Exception('Databade is opened') raise Exception('Database is opened')
# establish tables # establish tables
self.open() self.open()
@@ -58,13 +69,11 @@ class CalendarDatabase(object):
cursor.executescript(fsql.read()) cursor.executescript(fsql.read())
# finish init # finish init
cursor.execute('INSERT INTO user VALUES (?, ?, ?, ?, ?, ?);', ( cursor.execute('INSERT INTO user VALUES (?, ?, ?, ?);', (
username, username,
utils.ComputePasswordHash(password), utils.ComputePasswordHash(password),
1, 1,
utils.GenerateSalt(), utils.GenerateSalt()
utils.GenerateToken(username),
0
)) ))
cursor.close() cursor.close()
self.db.commit() self.db.commit()
@@ -81,8 +90,27 @@ class CalendarDatabase(object):
def is_database_valid(self): def is_database_valid(self):
return not (self.db == None) return not (self.db == None)
def get_username_from_token(self, token): # ======================= token related internal operation
self.cursor.execute('SELECT [ccn_name] FROM user WHERE [ccn_token] = ? AND [ccn_tokenExpireOn] > ?;',( def tokenOper_clean(self):
# remove outdated token
self.cursor.execute('DELETE FROM token WHERE [ccn_tokenExpireOn] <= ?',(utils.GetCurrentTimestamp(), ))
def tokenOper_postpone_expireOn(self, token):
self.cursor.execute('UPDATE token SET [ccn_tokenExpireOn] = ? WHERE [ccn_token] = ?;', (
utils.GetTokenExpireOn(),
token
))
def tokenOper_check_valid(self, token):
self.tokenOper_get_username(token)
def tokenOper_is_admin(self, username):
self.cursor.execute('SELECT [ccn_isAdmin] FROM user WHERE [ccn_name] = ?;',(username, ))
cache = self.cursor.fetchone()[0]
return True if cache == 1 else False
def tokenOper_get_username(self, token):
self.cursor.execute('SELECT [ccn_user] FROM token WHERE [ccn_token] = ? AND [ccn_tokenExpireOn] > ?;',(
token, token,
utils.GetCurrentTimestamp() utils.GetCurrentTimestamp()
)) ))
@@ -106,16 +134,19 @@ class CalendarDatabase(object):
if password == utils.ComputePasswordHashWithSalt(gotten_password, gotten_salt): if password == utils.ComputePasswordHashWithSalt(gotten_password, gotten_salt):
token = utils.GenerateToken(username) token = utils.GenerateToken(username)
self.cursor.execute('UPDATE user SET [ccn_token] = ?, [ccn_tokenExpireOn] = ?, [ccn_salt] = ? WHERE [ccn_name] = ?;', ( self.cursor.execute('UPDATE user SET [ccn_salt] = ? WHERE [ccn_name] = ?;', (
token,
utils.GetCurrentTimestamp() + 60 * 60 * 24 * 2, # add 2 day from now
utils.GenerateSalt(), # regenerate a new slat to prevent re-login try utils.GenerateSalt(), # regenerate a new slat to prevent re-login try
username username
)) ))
self.cursor.execute('INSERT INTO token VALUES (?, ?, ?);', (
username,
token,
utils.GetTokenExpireOn(), # add 2 day from now
))
return token return token
else: else:
# throw a exception to indicate fail to login # throw a exception to indicate fail to login
raise Exception() raise Exception('Login authentication failed')
@SafeDatabaseOperation @SafeDatabaseOperation
def common_webLogin(self, username, password): def common_webLogin(self, username, password):
@@ -123,38 +154,35 @@ class CalendarDatabase(object):
if len(self.cursor.fetchall()) != 0: if len(self.cursor.fetchall()) != 0:
token = utils.GenerateToken(username) token = utils.GenerateToken(username)
self.cursor.execute('UPDATE user SET [ccn_token] = ?, [ccn_tokenExpireOn] = ? WHERE [ccn_name] = ?;', ( self.cursor.execute('INSERT INTO token VALUES (?, ?, ?);', (
username,
token, token,
utils.GetCurrentTimestamp() + 60 * 60 * 24 * 2, # add 2 day from now utils.GetTokenExpireOn(), # add 2 day from now
username
)) ))
return token return token
else: else:
# throw a exception to indicate fail to login # throw a exception to indicate fail to login
raise Exception() raise Exception('Login authentication failed')
@SafeDatabaseOperation @SafeDatabaseOperation
def common_logout(self, token): def common_logout(self, token):
username = self.get_username_from_token(token) self.tokenOper_check_valid(token)
self.cursor.execute('UPDATE user SET [ccn_tokenExpireOn] = 0 WHERE [ccn_name] = ?;', (username, )) self.cursor.execute('DELETE FROM token WHERE [ccn_token] = ?;', (token, ))
return None return None
@SafeDatabaseOperation @SafeDatabaseOperation
def common_tokenValid(self, token): def common_tokenValid(self, token):
# get user name have check the validation, don't do anything more. self.tokenOper_check_valid(token)
self.get_username_from_token(token)
return None return None
@SafeDatabaseOperation @SafeDatabaseOperation
def common_isAdmin(self, token): def common_isAdmin(self, token):
username = self.get_username_from_token(token) username = self.tokenOper_get_username(token)
self.cursor.execute('SELECT [ccn_isAdmin] FROM user WHERE [ccn_name] = ?;', (username, )) return self.tokenOper_is_admin(username)
result = self.cursor.fetchone()[0] == 1
return result
@SafeDatabaseOperation @SafeDatabaseOperation
def common_changePassword(self, token, newpassword): def common_changePassword(self, token, newpassword):
username = self.get_username_from_token(token) username = self.tokenOper_get_username(token)
self.cursor.execute('UPDATE user SET [ccn_password] = ? WHERE [ccn_name] = ?;', ( self.cursor.execute('UPDATE user SET [ccn_password] = ? WHERE [ccn_name] = ?;', (
newpassword, newpassword,
username username
@@ -170,25 +198,25 @@ class CalendarDatabase(object):
# =============================== todo # =============================== todo
@SafeDatabaseOperation @SafeDatabaseOperation
def todo_getFull(self, token): def todo_getFull(self, token):
username = self.get_username_from_token(token) username = self.tokenOper_get_username(token)
self.cursor.execute('SELECT * FROM todo WHERE [ccn_belongTo] = ?;', (username, )) self.cursor.execute('SELECT * FROM todo WHERE [ccn_belongTo] = ?;', (username, ))
return self.cursor.fetchall() return self.cursor.fetchall()
@SafeDatabaseOperation @SafeDatabaseOperation
def todo_getList(self, token): def todo_getList(self, token):
username = self.get_username_from_token(token) username = self.tokenOper_get_username(token)
self.cursor.execute('SELECT [ccn_uuid] FROM todo WHERE [ccn_belongTo] = ?;', (username, )) self.cursor.execute('SELECT [ccn_uuid] FROM todo WHERE [ccn_belongTo] = ?;', (username, ))
return tuple(map(lambda x: x[0], self.cursor.fetchall())) return tuple(map(lambda x: x[0], self.cursor.fetchall()))
@SafeDatabaseOperation @SafeDatabaseOperation
def todo_getDetail(self, token, uuid): def todo_getDetail(self, token, uuid):
username = self.get_username_from_token(token) 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 [ccn_belongTo] = ? AND [ccn_uuid] = ?;', (username, uuid))
return self.cursor.fetchone() return self.cursor.fetchone()
@SafeDatabaseOperation @SafeDatabaseOperation
def todo_add(self, token): def todo_add(self, token):
username = self.get_username_from_token(token) username = self.tokenOper_get_username(token)
newuuid = utils.GenerateUUID() newuuid = utils.GenerateUUID()
lastupdate = utils.GenerateUUID() lastupdate = utils.GenerateUUID()
returnedData = ( returnedData = (
@@ -203,7 +231,7 @@ class CalendarDatabase(object):
@SafeDatabaseOperation @SafeDatabaseOperation
def todo_update(self, token, uuid, data, lastChange): def todo_update(self, token, uuid, data, lastChange):
# check valid token # check valid token
self.get_username_from_token(token) self.tokenOper_check_valid(token)
# check sync conflict # check sync conflict
self.cursor.execute('SELECT [ccn_uuid] FROM todo WHERE [ccn_uuid] = ? AND [ccn_lastChange] = ?;', ( self.cursor.execute('SELECT [ccn_uuid] FROM todo WHERE [ccn_uuid] = ? AND [ccn_lastChange] = ?;', (
uuid, uuid,
@@ -224,7 +252,7 @@ class CalendarDatabase(object):
@SafeDatabaseOperation @SafeDatabaseOperation
def todo_delete(self, token, uuid, lastChange): def todo_delete(self, token, uuid, lastChange):
# check valid token # check valid token
self.get_username_from_token(token) self.tokenOper_check_valid(token)
# check sync conflict # check sync conflict
self.cursor.execute('SELECT [ccn_uuid] FROM todo WHERE [ccn_uuid] = ? AND [ccn_lastChange] = ?;', ( self.cursor.execute('SELECT [ccn_uuid] FROM todo WHERE [ccn_uuid] = ? AND [ccn_lastChange] = ?;', (
uuid, uuid,

View File

@@ -302,8 +302,8 @@ def CheckParameter(paramList):
def ConstructResponseBody(returnedTuple): def ConstructResponseBody(returnedTuple):
return { return {
'success': returnedTuple[0], 'success': returnedTuple[0],
'error': '', 'error': returnedTuple[1],
'data': returnedTuple[1] 'data': returnedTuple[2]
} }
def run(): def run():

View File

@@ -6,10 +6,16 @@ CREATE TABLE user(
[ccn_password] TEXT NOT NULL, [ccn_password] TEXT NOT NULL,
[ccn_isAdmin] TINYINT NOT NULL CHECK(ccn_isAdmin = 1 OR ccn_isAdmin = 0), [ccn_isAdmin] TINYINT NOT NULL CHECK(ccn_isAdmin = 1 OR ccn_isAdmin = 0),
[ccn_salt] INTEGER NOT NULL, [ccn_salt] INTEGER NOT NULL,
PRIMARY KEY (ccn_name)
);
CREATE TABLE token(
[ccn_user] TEXT NOT NULL,
[ccn_token] TEXT UNIQUE NOT NULL, [ccn_token] TEXT UNIQUE NOT NULL,
[ccn_tokenExpireOn] BIGINT NOT NULL, [ccn_tokenExpireOn] BIGINT NOT NULL,
PRIMARY KEY (ccn_name) FOREIGN KEY (ccn_user) REFERENCES user(ccn_name) ON DELETE CASCADE
); );
CREATE TABLE collection( CREATE TABLE collection(

View File

@@ -24,10 +24,10 @@ ccn-login-form-login=Login
ccn-todo-todoList=Todo list ccn-todo-todoList=Todo list
ccn-calendar-jump=Jump ccn-calendar-calendar-jump=Jump
ccn-calendar-today=Today ccn-calendar-calendar-today=Today
ccn-calendar-add=Add... ccn-calendar-calendar-add=Add...
ccn-calendar-scheduleList=Schedule ccn-calendar-calendar-scheduleList=Schedule
ccn-calendar-tabcontrol-tabCalendar=Calendar ccn-calendar-tabcontrol-tabCalendar=Calendar
ccn-calendar-tabcontrol-tabShared=Shared ccn-calendar-tabcontrol-tabShared=Shared
ccn-calendar-tabcontrol-tabSharing=Sharing ccn-calendar-tabcontrol-tabSharing=Sharing
@@ -38,3 +38,7 @@ ccn-calendar-week-thursday=Thursday
ccn-calendar-week-friday=Friday ccn-calendar-week-friday=Friday
ccn-calendar-week-saturday=Saturday ccn-calendar-week-saturday=Saturday
ccn-calendar-week-sunday=Sunday ccn-calendar-week-sunday=Sunday
ccn-calendar-shared-list=Shared
ccn-calendar-sharing-ownedList=Owned
ccn-calendar-sharing-sharingTargetList=Sharing target
ccn-calendar-sharing-sharingTargetEditing=Editing:

View File

@@ -24,10 +24,10 @@ ccn-login-form-login=登录
ccn-todo-todoList=待办列表 ccn-todo-todoList=待办列表
ccn-calendar-jump=转到 ccn-calendar-calendar-jump=转到
ccn-calendar-today=今天 ccn-calendar-calendar-today=今天
ccn-calendar-add=添加... ccn-calendar-calendar-add=添加...
ccn-calendar-scheduleList=日程安排 ccn-calendar-calendar-scheduleList=日程安排
ccn-calendar-tabcontrol-tabCalendar=日历 ccn-calendar-tabcontrol-tabCalendar=日历
ccn-calendar-tabcontrol-tabShared=被共享的 ccn-calendar-tabcontrol-tabShared=被共享的
ccn-calendar-tabcontrol-tabSharing=共享给其他人 ccn-calendar-tabcontrol-tabSharing=共享给其他人
@@ -38,3 +38,7 @@ ccn-calendar-week-thursday=星期四
ccn-calendar-week-friday=星期五 ccn-calendar-week-friday=星期五
ccn-calendar-week-saturday=星期六 ccn-calendar-week-saturday=星期六
ccn-calendar-week-sunday=星期日 ccn-calendar-week-sunday=星期日
ccn-calendar-shared-list=被共享的集合
ccn-calendar-sharing-ownedList=我的集合
ccn-calendar-sharing-sharingTargetList=分享目标
ccn-calendar-sharing-sharingTargetEditing=正在编辑集合:

View File

@@ -1,13 +1,5 @@
function cnn_headerNav_Insert() { function cnn_headerNav_Insert() {
$.ajax({ $('body').prepend(ccn_template_headerNav.render());
url: $("#jsrender-tmpl-headerNav").attr('src'),
type: "GET",
async: false,
success: function (data) {
var tmpl = $.templates(data);
$('body').prepend(tmpl.render());
}
});
} }
function cnn_headerNav_LoggedRefresh() { function cnn_headerNav_LoggedRefresh() {
@@ -57,10 +49,10 @@ function cnn_headerNav_BindEvents() {
// Check for click events on the navbar burger icon // Check for click events on the navbar burger icon
$(".navbar-burger").click(function() { $(".navbar-burger").click(function() {
// Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu" // Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
$(".navbar-burger").toggleClass("is-active"); $(".navbar-burger").toggleClass("is-active");
$(".navbar-menu").toggleClass("is-active"); $(".navbar-menu").toggleClass("is-active");
}); });
} }

View File

@@ -43,19 +43,19 @@ function ccn_i18n_ApplyLanguage() {
//set title //set title
switch(ccn_pages_currentPage) { switch(ccn_pages_currentPage) {
case ccn_pages_enumPages.home: case ccn_pages_enumPages.home:
$('#ccn-pageName').html($.i18n.prop('ccn-pageName-home')) $('#ccn-pageName').html($.i18n.prop('ccn-pageName-home'));
break; break;
case ccn_pages_enumPages.calendar: case ccn_pages_enumPages.calendar:
$('#ccn-pageName').html($.i18n.prop('ccn-pageName-calendar')) $('#ccn-pageName').html($.i18n.prop('ccn-pageName-calendar'));
break; break;
case ccn_pages_enumPages.todo: case ccn_pages_enumPages.todo:
$('#ccn-pageName').html($.i18n.prop('ccn-pageName-todo')) $('#ccn-pageName').html($.i18n.prop('ccn-pageName-todo'));
break; break;
case ccn_pages_enumPages.admin: case ccn_pages_enumPages.admin:
$('#ccn-pageName').html($.i18n.prop('ccn-pageName-admin')) $('#ccn-pageName').html($.i18n.prop('ccn-pageName-admin'));
break; break;
case ccn_pages_enumPages.login: case ccn_pages_enumPages.login:
$('#ccn-pageName').html($.i18n.prop('ccn-pageName-login')) $('#ccn-pageName').html($.i18n.prop('ccn-pageName-login'));
break; break;
} }
} }

View File

@@ -0,0 +1,14 @@
$(document).ready(function() {
ccn_pages_currentPage = ccn_pages_enumPages.admin;
// template process
ccn_template_Load();
// nav process
cnn_headerNav_Insert();
cnn_headerNav_BindEvents();
cnn_headerNav_LoggedRefresh();
// apply i18n
ccn_i18n_ApplyLanguage();
});

View File

@@ -1,6 +1,10 @@
$(document).ready(function() { $(document).ready(function() {
// nav process
ccn_pages_currentPage = ccn_pages_enumPages.calendar; ccn_pages_currentPage = ccn_pages_enumPages.calendar;
// template process
ccn_template_Load();
// nav process
cnn_headerNav_Insert(); cnn_headerNav_Insert();
cnn_headerNav_BindEvents(); cnn_headerNav_BindEvents();
cnn_headerNav_LoggedRefresh(); cnn_headerNav_LoggedRefresh();

View File

@@ -1,6 +1,10 @@
$(document).ready(function() { $(document).ready(function() {
// nav process
ccn_pages_currentPage = ccn_pages_enumPages.home; ccn_pages_currentPage = ccn_pages_enumPages.home;
// template process
ccn_template_Load();
// nav process
cnn_headerNav_Insert(); cnn_headerNav_Insert();
cnn_headerNav_BindEvents(); cnn_headerNav_BindEvents();
cnn_headerNav_LoggedRefresh(); cnn_headerNav_LoggedRefresh();

View File

@@ -1,6 +1,10 @@
$(document).ready(function() { $(document).ready(function() {
// nav process
ccn_pages_currentPage = ccn_pages_enumPages.login; ccn_pages_currentPage = ccn_pages_enumPages.login;
// template process
ccn_template_Load();
// nav process
cnn_headerNav_Insert(); cnn_headerNav_Insert();
cnn_headerNav_BindEvents(); cnn_headerNav_BindEvents();
cnn_headerNav_LoggedRefresh(); cnn_headerNav_LoggedRefresh();

View File

@@ -1,8 +1,12 @@
var ccn_todo_todoListCache = []; var ccn_todo_todoListCache = [];
$(document).ready(function() { $(document).ready(function() {
ccn_pages_currentPage = ccn_pages_enumPages.todo;
// template process
ccn_template_Load();
// nav process // nav process
ccn_pages_currentPage = ccn_pages_enumPages.login;
cnn_headerNav_Insert(); cnn_headerNav_Insert();
cnn_headerNav_BindEvents(); cnn_headerNav_BindEvents();
cnn_headerNav_LoggedRefresh(); cnn_headerNav_LoggedRefresh();
@@ -40,25 +44,15 @@ function ccn_todo_RenderCacheList() {
data: undefined data: undefined
}; };
var templates = undefined;
$.ajax({
url: $("#jsrender-tmpl-todoItem").attr('src'),
type: "GET",
async: false,
success: function (data) {
templates = $.templates(data);
}
});
var listDOM = $("#ccn-todo-todoList"); var listDOM = $("#ccn-todo-todoList");
for(var index in ccn_todo_todoListCache) { for(var index in ccn_todo_todoListCache) {
// update render data // update render data
var item = ccn_todo_todoListCache[index]; var item = ccn_todo_todoListCache[index];
renderdata.uuid = item[0]; renderdata.uuid = item[0];
renderdata.data = item[2]; renderdata.data = LineBreaker2Br(item[2]);
// render // render
listDOM.append(templates.render(renderdata)); listDOM.append(ccn_template_todoItem.render(renderdata));
// set mode // set mode
var uuid = renderdata.uuid; var uuid = renderdata.uuid;
@@ -110,22 +104,11 @@ function ccn_todo_Add() {
// add into cache // add into cache
ccn_todo_todoListCache[result[0]] = result; ccn_todo_todoListCache[result[0]] = result;
// render
var templates = undefined;
$.ajax({
url: $("#jsrender-tmpl-todoItem").attr('src'),
type: "GET",
async: false,
success: function (data) {
templates = $.templates(data);
}
});
// render // render
var listDOM = $("#ccn-todo-todoList"); var listDOM = $("#ccn-todo-todoList");
listDOM.append(templates.render({ listDOM.append(ccn_template_todoItem.render({
uuid: result[0], uuid: result[0],
data: result[2] data: LineBreaker2Br(result[2])
})); }));
// set mode // set mode
@@ -145,7 +128,7 @@ function ccn_todo_ItemEdit() {
// copy current data to textarea // copy current data to textarea
$("#ccn-todo-todoItem-textarea-" + uuid).val( $("#ccn-todo-todoItem-textarea-" + uuid).val(
$("#ccn-todo-todoItem-p-" + uuid).text() ccn_todo_todoListCache[uuid][2]
); );
// switch to edit mode // switch to edit mode
@@ -186,7 +169,7 @@ function ccn_todo_ItemUpdate() {
// safely update data & lastChanged and control // safely update data & lastChanged and control
ccn_todo_todoListCache[uuid][2] = newData; ccn_todo_todoListCache[uuid][2] = newData;
ccn_todo_todoListCache[uuid][3] = result; ccn_todo_todoListCache[uuid][3] = result;
$("#ccn-todo-todoItem-p-" + uuid).text(newData); $("#ccn-todo-todoItem-p-" + uuid).html(LineBreaker2Br(newData));
// switch to normal mode // switch to normal mode
ccn_todo_ChangeDisplayMode(uuid, false); ccn_todo_ChangeDisplayMode(uuid, false);

61
src/static/js/template.js Normal file
View File

@@ -0,0 +1,61 @@
var ccn_template_headerNav = undefined;
var ccn_template_calendarItem = undefined;
var ccn_template_scheduleItem = undefined;
var ccn_template_userItem = undefined;
var ccn_template_todoItem = undefined;
function ccn_template_Load() {
$.ajax({
url: $("#jsrender-tmpl-headerNav").attr('src'),
type: "GET",
async: false,
success: function (data) {
ccn_template_headerNav = $.templates(data);
}
});
switch(ccn_pages_currentPage) {
case ccn_pages_enumPages.home:
break;
case ccn_pages_enumPages.calendar:
$.ajax({
url: $("#jsrender-tmpl-calendarItem").attr('src'),
type: "GET",
async: false,
success: function (data) {
ccn_template_calendarItem = $.templates(data);
}
});
$.ajax({
url: $("#jsrender-tmpl-scheduleItem").attr('src'),
type: "GET",
async: false,
success: function (data) {
ccn_template_scheduleItem = $.templates(data);
}
});
break;
case ccn_pages_enumPages.todo:
$.ajax({
url: $("#jsrender-tmpl-todoItem").attr('src'),
type: "GET",
async: false,
success: function (data) {
ccn_template_todoItem = $.templates(data);
}
});
break;
case ccn_pages_enumPages.admin:
$.ajax({
url: $("#jsrender-tmpl-userItem").attr('src'),
type: "GET",
async: false,
success: function (data) {
ccn_template_userItem = $.templates(data);
}
});
break;
case ccn_pages_enumPages.login:
break;
}
}

View File

@@ -36,3 +36,7 @@ function GetApiToken() {
function SetApiToken(value) { function SetApiToken(value) {
ccn_localstorageAssist_Set('ccn-token', value); ccn_localstorageAssist_Set('ccn-token', value);
} }
function LineBreaker2Br(strl) {
return $('<div>').text(strl).html().replace(/\n/g,'<br />');
}

View File

@@ -1,6 +1,6 @@
<div id="ccn-todo-todoItem-{{:uuid}}" class="todo-item card"> <div id="ccn-todo-todoItem-{{:uuid}}" class="todo-item card">
<div class="todo-item-words"> <div class="todo-item-words">
<p id="ccn-todo-todoItem-p-{{:uuid}}">{{>data}}</p> <p id="ccn-todo-todoItem-p-{{:uuid}}">{{:data}}</p>
<textarea id="ccn-todo-todoItem-textarea-{{:uuid}}" class="textarea"></textarea> <textarea id="ccn-todo-todoItem-textarea-{{:uuid}}" class="textarea"></textarea>
</div> </div>

View File

@@ -18,6 +18,7 @@
<script type="text/javascript" src="/static/js/i18n.js"></script> <script type="text/javascript" src="/static/js/i18n.js"></script>
<script type="text/javascript" src="/static/js/utils.js"></script> <script type="text/javascript" src="/static/js/utils.js"></script>
<script type="text/javascript" src="/static/js/api.js"></script> <script type="text/javascript" src="/static/js/api.js"></script>
<script type="text/javascript" src="/static/js/template.js"></script>
<script type="text/javascript" src="/static/js/headerNav.js"></script> <script type="text/javascript" src="/static/js/headerNav.js"></script>
<script type="text/javascript" src="/static/js/page/admin.js"></script> <script type="text/javascript" src="/static/js/page/admin.js"></script>

View File

@@ -19,6 +19,7 @@
<script type="text/javascript" src="/static/js/i18n.js"></script> <script type="text/javascript" src="/static/js/i18n.js"></script>
<script type="text/javascript" src="/static/js/utils.js"></script> <script type="text/javascript" src="/static/js/utils.js"></script>
<script type="text/javascript" src="/static/js/api.js"></script> <script type="text/javascript" src="/static/js/api.js"></script>
<script type="text/javascript" src="/static/js/template.js"></script>
<script type="text/javascript" src="/static/js/headerNav.js"></script> <script type="text/javascript" src="/static/js/headerNav.js"></script>
<script type="text/javascript" src="/static/js/tabcontrol.js"></script> <script type="text/javascript" src="/static/js/tabcontrol.js"></script>
@@ -46,16 +47,16 @@
<input class="input" type="date"> <input class="input" type="date">
</div> </div>
<div class="control"> <div class="control">
<button i18n-name="ccn-calendar-jump" class="button is-info"></button> <button i18n-name="ccn-calendar-calendar-jump" class="button is-info"></button>
</div> </div>
</div> </div>
</div> </div>
<div class="level-item control"> <div class="level-item control">
<a i18n-name="ccn-calendar-today" class="button is-info"></a> <a i18n-name="ccn-calendar-calendar-today" class="button is-info"></a>
</div> </div>
<div class="level-item control"> <div class="level-item control">
<a i18n-name="ccn-calendar-add" class="button is-primary"></a> <a i18n-name="ccn-calendar-calendar-add" class="button is-primary"></a>
</div> </div>
</nav> </nav>
@@ -72,7 +73,7 @@
</div> </div>
<div class="container" style="padding: 1.25rem; display: flex; flex-flow: column; margin-top: 1.25rem;"> <div class="container" style="padding: 1.25rem; display: flex; flex-flow: column; margin-top: 1.25rem;">
<h1 i18n-name="ccn-calendar-scheduleList" class="title"></h1> <h1 i18n-name="ccn-calendar-calendar-scheduleList" class="title"></h1>
<div id="schedule-list"> <div id="schedule-list">
<div class="schedule-day container"> <div class="schedule-day container">
@@ -174,7 +175,7 @@
<div id="tabcontrol-panel-1-2" class="container tabcontrol-panel-1" style="margin-top: 20px;"> <div id="tabcontrol-panel-1-2" class="container tabcontrol-panel-1" style="margin-top: 20px;">
<div class="container" style="display: flex; flex-flow: column;"> <div class="container" style="display: flex; flex-flow: column;">
<h1 class="title">Shared</h1> <h1 i18n-name="ccn-calendar-shared-list" class="title"></h1>
<div class="field"> <div class="field">
<div class="control"> <div class="control">
<a class="button is-primary"> <a class="button is-primary">
@@ -215,7 +216,7 @@
<div id="tabcontrol-panel-1-3" class="container tabcontrol-panel-1" style="margin-top: 20px;"> <div id="tabcontrol-panel-1-3" class="container tabcontrol-panel-1" style="margin-top: 20px;">
<div class="container" style="display: flex; flex-flow: column;"> <div class="container" style="display: flex; flex-flow: column;">
<h1 class="title">Owned</h1> <h1 i18n-name="ccn-calendar-sharing-ownedList" class="title"></h1>
<div class="control-list"> <div class="control-list">
<div class="field has-addons"> <div class="field has-addons">
<div class="control"> <div class="control">
@@ -272,8 +273,8 @@
</div> </div>
<div class="container" style="display: flex; flex-flow: column;"> <div class="container" style="display: flex; flex-flow: column;">
<h1 class="title">Sharing target</h1> <h1 i18n-name="ccn-calendar-sharing-sharingTargetList" class="title"></h1>
<label class="label"><span>Editing: </span><span>xxx</span></label> <label class="label"><span i18n-name="ccn-calendar-sharing-sharingTargetEditing"></span><span>xxx</span></label>
<div class="control-list"> <div class="control-list">
<div class="field has-addons"> <div class="field has-addons">

View File

@@ -17,6 +17,7 @@
<script type="text/javascript" src="/static/js/i18n.js"></script> <script type="text/javascript" src="/static/js/i18n.js"></script>
<script type="text/javascript" src="/static/js/utils.js"></script> <script type="text/javascript" src="/static/js/utils.js"></script>
<script type="text/javascript" src="/static/js/api.js"></script> <script type="text/javascript" src="/static/js/api.js"></script>
<script type="text/javascript" src="/static/js/template.js"></script>
<script type="text/javascript" src="/static/js/headerNav.js"></script> <script type="text/javascript" src="/static/js/headerNav.js"></script>
<script type="text/javascript" src="/static/js/page/home.js"></script> <script type="text/javascript" src="/static/js/page/home.js"></script>

View File

@@ -17,6 +17,7 @@
<script type="text/javascript" src="/static/js/i18n.js"></script> <script type="text/javascript" src="/static/js/i18n.js"></script>
<script type="text/javascript" src="/static/js/utils.js"></script> <script type="text/javascript" src="/static/js/utils.js"></script>
<script type="text/javascript" src="/static/js/api.js"></script> <script type="text/javascript" src="/static/js/api.js"></script>
<script type="text/javascript" src="/static/js/template.js"></script>
<script type="text/javascript" src="/static/js/headerNav.js"></script> <script type="text/javascript" src="/static/js/headerNav.js"></script>
<script type="text/javascript" src="/static/js/page/login.js"></script> <script type="text/javascript" src="/static/js/page/login.js"></script>

View File

@@ -18,6 +18,7 @@
<script type="text/javascript" src="/static/js/i18n.js"></script> <script type="text/javascript" src="/static/js/i18n.js"></script>
<script type="text/javascript" src="/static/js/utils.js"></script> <script type="text/javascript" src="/static/js/utils.js"></script>
<script type="text/javascript" src="/static/js/api.js"></script> <script type="text/javascript" src="/static/js/api.js"></script>
<script type="text/javascript" src="/static/js/template.js"></script>
<script type="text/javascript" src="/static/js/headerNav.js"></script> <script type="text/javascript" src="/static/js/headerNav.js"></script>
<script type="text/javascript" src="/static/js/page/todo.js"></script> <script type="text/javascript" src="/static/js/page/todo.js"></script>

View File

@@ -23,7 +23,7 @@ def GenerateUUID():
def GenerateToken(username): def GenerateToken(username):
s = hashlib.sha256() s = hashlib.sha256()
s.update(username.encode('utf-8')) s.update(username.encode('utf-8'))
s.update((str(GenerateSalt())).encode('utf-8')) s.update(GenerateUUID().encode('utf-8'))
return s.hexdigest() return s.hexdigest()
def GenerateSalt(): def GenerateSalt():
@@ -36,3 +36,6 @@ def ComputePasswordHashWithSalt(passwordHashed, salt):
def GetCurrentTimestamp(): def GetCurrentTimestamp():
return int(time.time()) return int(time.time())
def GetTokenExpireOn():
return GetCurrentTimestamp() + 60 * 60 * 24 * 2 # add 2 day from now