nightly commit
This commit is contained in:
129
src/database.py
129
src/database.py
@@ -1,10 +1,40 @@
|
|||||||
import config
|
import config
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import json
|
import json
|
||||||
|
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
|
||||||
|
|
||||||
class CalendarDatabase(object):
|
class CalendarDatabase(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.db = None
|
self.db = None
|
||||||
|
self.cursor = None
|
||||||
|
self.mutex = threading.Lock()
|
||||||
|
|
||||||
def open(self):
|
def open(self):
|
||||||
if (self.is_database_valid()):
|
if (self.is_database_valid()):
|
||||||
@@ -21,15 +51,23 @@ class CalendarDatabase(object):
|
|||||||
if (self.is_database_valid()):
|
if (self.is_database_valid()):
|
||||||
raise Exception('Databade is opened')
|
raise Exception('Databade is opened')
|
||||||
|
|
||||||
|
# establish tables
|
||||||
self.open()
|
self.open()
|
||||||
|
cursor = self.db.cursor()
|
||||||
with open('sql/sqlite.sql', 'r', encoding='utf-8') as fsql:
|
with open('sql/sqlite.sql', 'r', encoding='utf-8') as fsql:
|
||||||
cursor = self.db.cursor()
|
|
||||||
cursor.executescript(fsql.read())
|
cursor.executescript(fsql.read())
|
||||||
cursor.close()
|
|
||||||
self.db.commit()
|
|
||||||
|
|
||||||
#todo: finish init
|
|
||||||
|
|
||||||
|
# finish init
|
||||||
|
cursor.execute('INSERT INTO user VALUES (?, ?, ?, ?, ?, ?);', (
|
||||||
|
username,
|
||||||
|
utils.ComputePasswordHash(password),
|
||||||
|
1,
|
||||||
|
utils.GenerateSalt(),
|
||||||
|
utils.GenerateToken(username),
|
||||||
|
0
|
||||||
|
))
|
||||||
|
cursor.close()
|
||||||
|
self.db.commit()
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self.check_database()
|
self.check_database()
|
||||||
@@ -43,9 +81,80 @@ class CalendarDatabase(object):
|
|||||||
def is_database_valid(self):
|
def is_database_valid(self):
|
||||||
return not (self.db == None)
|
return not (self.db == None)
|
||||||
|
|
||||||
# operation function
|
def get_username_from_token(self, token):
|
||||||
def login_step1(self, username):
|
self.cursor.execute('SELECT [ccn_name] FROM user WHERE [ccn_token] = ? AND [ccn_tokenExpireOn] > ?;',(
|
||||||
self.check_database()
|
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
|
||||||
|
|
||||||
|
|
||||||
def login_step2(self, username, password):
|
|
||||||
self.check_database()
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import database
|
|||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
render_static_resources = None
|
# render_static_resources = None
|
||||||
|
|
||||||
# =============================================database
|
# =============================================database
|
||||||
def get_database():
|
def get_database():
|
||||||
@@ -39,23 +39,28 @@ def nospecHandle():
|
|||||||
|
|
||||||
@app.route('/web/home', methods=['GET'])
|
@app.route('/web/home', methods=['GET'])
|
||||||
def web_homeHandle():
|
def web_homeHandle():
|
||||||
UpdateStaticResources()
|
# UpdateStaticResources()
|
||||||
return render_template("home.html", **render_static_resources)
|
return render_template("home.html")
|
||||||
|
|
||||||
@app.route('/web/calendar', methods=['GET'])
|
@app.route('/web/calendar', methods=['GET'])
|
||||||
def web_calendarHandle():
|
def web_calendarHandle():
|
||||||
UpdateStaticResources()
|
# UpdateStaticResources()
|
||||||
return render_template("calendar.html", **render_static_resources)
|
return render_template("calendar.html")
|
||||||
|
|
||||||
@app.route('/web/todo', methods=['GET'])
|
@app.route('/web/todo', methods=['GET'])
|
||||||
def web_todoHandle():
|
def web_todoHandle():
|
||||||
UpdateStaticResources()
|
# UpdateStaticResources()
|
||||||
return render_template("todo.html", **render_static_resources)
|
return render_template("todo.html")
|
||||||
|
|
||||||
@app.route('/web/admin', methods=['GET'])
|
@app.route('/web/admin', methods=['GET'])
|
||||||
def web_adminHandle():
|
def web_adminHandle():
|
||||||
UpdateStaticResources()
|
# UpdateStaticResources()
|
||||||
return render_template("admin.html", **render_static_resources)
|
return render_template("admin.html")
|
||||||
|
|
||||||
|
@app.route('/web/login', methods=['GET'])
|
||||||
|
def web_loginHandle():
|
||||||
|
# UpdateStaticResources()
|
||||||
|
return render_template("login.html")
|
||||||
|
|
||||||
# ============================================= query page route
|
# ============================================= query page route
|
||||||
|
|
||||||
@@ -194,6 +199,7 @@ def api_admin_deleteHandle():
|
|||||||
|
|
||||||
# =============================================main run
|
# =============================================main run
|
||||||
|
|
||||||
|
'''
|
||||||
def UpdateStaticResources():
|
def UpdateStaticResources():
|
||||||
global render_static_resources
|
global render_static_resources
|
||||||
if render_static_resources is not None:
|
if render_static_resources is not None:
|
||||||
@@ -209,6 +215,7 @@ def UpdateStaticResources():
|
|||||||
|
|
||||||
'url_js_pageHome': url_for('static', filename='js/page/home.js')
|
'url_js_pageHome': url_for('static', filename='js/page/home.js')
|
||||||
}
|
}
|
||||||
|
'''
|
||||||
|
|
||||||
def run():
|
def run():
|
||||||
app.run(port=config.CustomConfig['web']['port'])
|
app.run(port=config.CustomConfig['web']['port'])
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ CREATE TABLE calendar(
|
|||||||
|
|
||||||
[ccn_title] TEXT NOT NULL,
|
[ccn_title] TEXT NOT NULL,
|
||||||
[ccn_description] TEXT NOT NULL,
|
[ccn_description] TEXT NOT NULL,
|
||||||
[ccn_lastChange] BIGINT NOT NULL,
|
[ccn_lastChange] TEXT NOT NULL,
|
||||||
|
|
||||||
[ccn_eventDateTimeType] TINYINT NOT NULL,
|
[ccn_eventDateTimeType] TINYINT NOT NULL,
|
||||||
[ccn_eventDateTimeStart] BIGINT NOT NULL,
|
[ccn_eventDateTimeStart] BIGINT NOT NULL,
|
||||||
@@ -54,7 +54,7 @@ CREATE TABLE todo(
|
|||||||
[ccn_belongTo] TEXT NOT NULL,
|
[ccn_belongTo] TEXT NOT NULL,
|
||||||
|
|
||||||
[ccn_data] TEXT NOT NULL,
|
[ccn_data] TEXT NOT NULL,
|
||||||
[ccn_lastChange] BIGINT NOT NULL,
|
[ccn_lastChange] TEXT NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (ccn_uuid),
|
PRIMARY KEY (ccn_uuid),
|
||||||
FOREIGN KEY (ccn_belongTo) REFERENCES user(ccn_name) ON DELETE CASCADE
|
FOREIGN KEY (ccn_belongTo) REFERENCES user(ccn_name) ON DELETE CASCADE
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#calendar-body div:nth-child(n+2) div {
|
#ccn-calendar-calendarBbody div:nth-child(n+2) div {
|
||||||
border-top: 0 solid black;
|
border-top: 0 solid black;
|
||||||
border-left: 0 solid black;
|
border-left: 0 solid black;
|
||||||
border-right: 1px solid black;
|
border-right: 1px solid black;
|
||||||
@@ -13,15 +13,15 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#calendar-body div:nth-child(n+2) div:nth-child(1) {
|
#ccn-calendar-calendarBbody div:nth-child(n+2) div:nth-child(1) {
|
||||||
border-left: 1px solid black;
|
border-left: 1px solid black;
|
||||||
}
|
}
|
||||||
|
|
||||||
#calendar-body div:nth-child(2) div {
|
#ccn-calendar-calendarBbody div:nth-child(2) div {
|
||||||
border-top: 1px solid black;
|
border-top: 1px solid black;
|
||||||
}
|
}
|
||||||
|
|
||||||
#calendar-body div div {
|
#ccn-calendar-calendarBbody div div {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
flex-basis: 0;
|
flex-basis: 0;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#calendar-body div {
|
#ccn-calendar-calendarBbody div {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: row;
|
flex-flow: row;
|
||||||
}
|
}
|
||||||
|
|||||||
20
src/static/i18n/strings_en-US.properties
Normal file
20
src/static/i18n/strings_en-US.properties
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
ccn-pageName-home=coconut-leaf - A light, self-host calendar system.
|
||||||
|
ccn-pageName-calendar=coconut-leaf - Calendar
|
||||||
|
ccn-pageName-todo=coconut-leaf - Todo
|
||||||
|
ccn-pageName-admin=coconut-leaf - Admin
|
||||||
|
ccn-pageName-login=coconut-leaf - Login
|
||||||
|
|
||||||
|
ccn-header-nav-home=Home
|
||||||
|
ccn-header-nav-calendar=Calendar
|
||||||
|
ccn-header-nav-todo=Todo
|
||||||
|
ccn-header-nav-admin=Admin
|
||||||
|
ccn-header-user-login=Login
|
||||||
|
ccn-header-user-logout=Logout
|
||||||
|
ccn-header-language=Language
|
||||||
|
|
||||||
|
ccn-home-desc=<h1 class="title">coconut-leaf</h1><p>A light, self-host calendar system.</p><p>Originally, this app is served for yyc12345 personal use.</p><br /><p>Pull request / issue / translation are welcomed.</p><p>Submit them in our <a href="https://github.com/yyc12345/coconut-leaf">GitHub project</a>.</p><p>This project source code is licensed <a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL v3</a>.</p>
|
||||||
|
|
||||||
|
ccn-login-form-username=Username
|
||||||
|
ccn-login-form-password=Password
|
||||||
|
ccn-login-form-login=Login
|
||||||
|
|
||||||
21
src/static/i18n/strings_zh-CN.properties
Normal file
21
src/static/i18n/strings_zh-CN.properties
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
ccn-pageName-home=coconut-leaf - 一个轻量的自建日历系统
|
||||||
|
ccn-pageName-calendar=coconut-leaf - 日历
|
||||||
|
ccn-pageName-todo=coconut-leaf - 待办
|
||||||
|
ccn-pageName-admin=coconut-leaf - 管理
|
||||||
|
ccn-pageName-login=coconut-leaf - 登录
|
||||||
|
|
||||||
|
ccn-header-nav-home=主页
|
||||||
|
ccn-header-nav-calendar=日历
|
||||||
|
ccn-header-nav-todo=待办
|
||||||
|
ccn-header-nav-admin=管理
|
||||||
|
ccn-header-user-login=登录
|
||||||
|
ccn-header-user-logout=登出
|
||||||
|
ccn-header-language=语言
|
||||||
|
|
||||||
|
ccn-home-desc=<h1 class="title">coconut-leaf</h1><p>一个轻量的自建日历系统</p><p>原本是出于yyc12345的个人使用而制作的。</p><br /><p>欢迎提出Pull request / issue / 翻译</p><p>将他们提交到我们的<a href="https://github.com/yyc12345/coconut-leaf">GitHub项目</a>.</p><p>本工程代码使用<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL v3</a>授权。</p>
|
||||||
|
|
||||||
|
ccn-login-form-username=用户名
|
||||||
|
ccn-login-form-password=密码
|
||||||
|
ccn-login-form-login=登录
|
||||||
|
|
||||||
|
|
||||||
@@ -2,6 +2,7 @@ function cnn_headerNav_Insert() {
|
|||||||
$.ajax({
|
$.ajax({
|
||||||
url: $("#jsrender-tmpl-headerNav").attr('src'),
|
url: $("#jsrender-tmpl-headerNav").attr('src'),
|
||||||
type: "GET",
|
type: "GET",
|
||||||
|
async: false,
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
var tmpl = $.templates(data);
|
var tmpl = $.templates(data);
|
||||||
$('body').prepend(tmpl.render());
|
$('body').prepend(tmpl.render());
|
||||||
@@ -9,3 +10,49 @@ function cnn_headerNav_Insert() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cnn_headerNav_LoggedRefresh() {
|
||||||
|
if (cnn_api_tokenValid()) {
|
||||||
|
// logged, show all nav button and logout button
|
||||||
|
$("#cnn-header-nav-home").show();
|
||||||
|
$("#cnn-header-nav-calendar").show();
|
||||||
|
$("#cnn-header-nav-todo").show();
|
||||||
|
$("#cnn-header-nav-admin").show();
|
||||||
|
|
||||||
|
$("#cnn-header-user-login").hide();
|
||||||
|
$("#cnn-header-user-logout").show();
|
||||||
|
} else {
|
||||||
|
$("#cnn-header-nav-home").show();
|
||||||
|
$("#cnn-header-nav-calendar").hide();
|
||||||
|
$("#cnn-header-nav-todo").hide();
|
||||||
|
$("#cnn-header-nav-admin").hide();
|
||||||
|
|
||||||
|
$("#cnn-header-user-login").show();
|
||||||
|
$("#cnn-header-user-logout").hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// bind language process and internal process function such as logout and expand menu
|
||||||
|
function cnn_headerNav_BindEvents() {
|
||||||
|
// bind function
|
||||||
|
$("#cnn-header-language > *").each(function(){
|
||||||
|
$(this).click(function(){
|
||||||
|
ccn_i18n_ChangeLanguage($(this).attr("language"));
|
||||||
|
ccn_i18n_ApplyLanguage();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// todo: bind logout
|
||||||
|
|
||||||
|
|
||||||
|
// bind burger menu
|
||||||
|
// copy from bulma website
|
||||||
|
// Check for click events on the navbar burger icon
|
||||||
|
$(".navbar-burger").click(function() {
|
||||||
|
|
||||||
|
// Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
|
||||||
|
$(".navbar-burger").toggleClass("is-active");
|
||||||
|
$(".navbar-menu").toggleClass("is-active");
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
var ccn_i18n_i18nSupported = ['en-US', 'zh-CN'];
|
var ccn_i18n_i18nSupported = ['en-US', 'zh-CN'];
|
||||||
var ccn_i18n_currentLanguage = 'en-US';
|
var ccn_i18n_currentLanguage = 'en-US';
|
||||||
|
var ccn_pages_enumPages = {
|
||||||
|
home : 0,
|
||||||
|
calendar: 1,
|
||||||
|
todo: 2,
|
||||||
|
admin: 3,
|
||||||
|
login: 4
|
||||||
|
};
|
||||||
|
var ccn_pages_currentPage = ccn_pages_enumPages.home;
|
||||||
|
|
||||||
// judge current language
|
// judge current language
|
||||||
ccn_i18n_currentLanguage = ccn_localstorageAssist_Get('ccn-i18n', 'en-US');
|
ccn_i18n_currentLanguage = ccn_localstorageAssist_Get('ccn-i18n', 'en-US');
|
||||||
@@ -18,14 +26,17 @@ function ccn_i18n_ChangeLanguage(newLang) {
|
|||||||
function ccn_i18n_ApplyLanguage() {
|
function ccn_i18n_ApplyLanguage() {
|
||||||
$.i18n.properties({
|
$.i18n.properties({
|
||||||
name: 'strings_' + ccn_i18n_currentLanguage,
|
name: 'strings_' + ccn_i18n_currentLanguage,
|
||||||
path: 'i18n/',
|
path: '/static/i18n/',
|
||||||
|
encoding: 'utf-8',
|
||||||
mode: 'map',
|
mode: 'map',
|
||||||
|
async: true,
|
||||||
|
cache: false,
|
||||||
language: ccn_i18n_currentLanguage,
|
language: ccn_i18n_currentLanguage,
|
||||||
callback: function() {
|
callback: function() {
|
||||||
//set usual block
|
//set usual block
|
||||||
var cache = $(".ccn-i18n");
|
var cache = $(".ccn-i18n");
|
||||||
cache.each(function() {
|
cache.each(function() {
|
||||||
$(this).html($.i18n.prop($(this).attr('name')));
|
$(this).html($.i18n.prop($(this).attr('i18n-name')));
|
||||||
});
|
});
|
||||||
|
|
||||||
//set unusual block
|
//set unusual block
|
||||||
@@ -34,22 +45,19 @@ function ccn_i18n_ApplyLanguage() {
|
|||||||
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.user:
|
case ccn_pages_enumPages.calendar:
|
||||||
$('#ccn-pageName').html($.i18n.prop('ccn-pageName-user'))
|
$('#ccn-pageName').html($.i18n.prop('ccn-pageName-calendar'))
|
||||||
break;
|
break;
|
||||||
case ccn_pages_enumPages.userinfo:
|
case ccn_pages_enumPages.todo:
|
||||||
$('#ccn-pageName').html($.i18n.prop('ccn-pageName-userinfo'))
|
$('#ccn-pageName').html($.i18n.prop('ccn-pageName-todo'))
|
||||||
break;
|
break;
|
||||||
case ccn_pages_enumPages.map:
|
case ccn_pages_enumPages.admin:
|
||||||
$('#ccn-pageName').html($.i18n.prop('ccn-pageName-map'))
|
$('#ccn-pageName').html($.i18n.prop('ccn-pageName-admin'))
|
||||||
break;
|
break;
|
||||||
case ccn_pages_enumPages.mapinfo:
|
case ccn_pages_enumPages.login:
|
||||||
$('#ccn-pageName').html($.i18n.prop('ccn-pageName-mapinfo'))
|
$('#ccn-pageName').html($.i18n.prop('ccn-pageName-login'))
|
||||||
break;
|
|
||||||
case ccn_pages_enumPages.about:
|
|
||||||
$('#ccn-pageName').html($.i18n.prop('ccn-pageName-about'))
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
$(document).ready(function() {
|
||||||
|
// nav process
|
||||||
|
ccn_pages_currentPage = ccn_pages_enumPages.calendar;
|
||||||
|
cnn_headerNav_Insert();
|
||||||
|
cnn_headerNav_BindEvents();
|
||||||
|
cnn_headerNav_LoggedRefresh();
|
||||||
|
|
||||||
|
// process calendar it self
|
||||||
|
ccn_calendar_LoadCalendarBody();
|
||||||
|
|
||||||
|
// apply i18n
|
||||||
|
ccn_i18n_ApplyLanguage();
|
||||||
|
});
|
||||||
|
|
||||||
|
function ccn_calendar_LoadCalendarBody() {
|
||||||
|
$.ajax({
|
||||||
|
url: $("#jsrender-tmpl-calendarItem").attr('src'),
|
||||||
|
type: "GET",
|
||||||
|
async: false,
|
||||||
|
success: function (data) {
|
||||||
|
var tmpl = $.templates(data);
|
||||||
|
$('#ccn-calendar-calendarBbody').append(tmpl.render());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
// insert nav first
|
// nav process
|
||||||
|
ccn_pages_currentPage = ccn_pages_enumPages.home;
|
||||||
cnn_headerNav_Insert();
|
cnn_headerNav_Insert();
|
||||||
|
cnn_headerNav_BindEvents();
|
||||||
|
cnn_headerNav_LoggedRefresh();
|
||||||
|
|
||||||
|
// apply i18n
|
||||||
|
ccn_i18n_ApplyLanguage();
|
||||||
});
|
});
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
$(document).ready(function() {
|
||||||
|
// nav process
|
||||||
|
ccn_pages_currentPage = ccn_pages_enumPages.login;
|
||||||
|
cnn_headerNav_Insert();
|
||||||
|
cnn_headerNav_BindEvents();
|
||||||
|
cnn_headerNav_LoggedRefresh();
|
||||||
|
|
||||||
|
// apply i18n
|
||||||
|
ccn_i18n_ApplyLanguage();
|
||||||
|
});
|
||||||
11
src/static/tmpl/calendarItem.tmpl
Normal file
11
src/static/tmpl/calendarItem.tmpl
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{{for start=0 end=6 step=1 itemVar="~row"}}
|
||||||
|
<div>
|
||||||
|
{{for start=0 end=7 step=1 itemVar="~column"}}
|
||||||
|
<div id="ccn-calendar-calendarItem-{{:~row}}-{{:~column}}">
|
||||||
|
<p><b>1</b></p>
|
||||||
|
<p><small>春分</small></p>
|
||||||
|
<p><span class="icon is-small"><i class="fas fa-tasks"></i></span>114514</p>
|
||||||
|
</div>
|
||||||
|
{{/for}}
|
||||||
|
</div>
|
||||||
|
{{/for}}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<nav class="navbar has-shadow is-spaced bd-navbar" role="navigation" aria-label="main navigation">
|
<nav class="navbar has-shadow is-spaced bd-navbar" role="navigation" aria-label="main navigation">
|
||||||
<div class="navbar-brand">
|
<div class="navbar-brand">
|
||||||
<a class="navbar-item" href="home">
|
<a class="navbar-item" href="home">
|
||||||
<img src="icon.png"><b style="margin:0 0 0 14px;">coconut-leaf</b>
|
<img src="/static/image/icon.png"><b style="margin:0 0 0 14px;">coconut-leaf</b>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false"
|
<a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false"
|
||||||
@@ -14,26 +14,26 @@
|
|||||||
|
|
||||||
<div id="navbarBasicExample" class="navbar-menu">
|
<div id="navbarBasicExample" class="navbar-menu">
|
||||||
<div class="navbar-start">
|
<div class="navbar-start">
|
||||||
<a class="navbar-item" href="home">Home</a>
|
<a i18n-name="ccn-header-nav-home" id="cnn-header-nav-home" class="navbar-item ccn-i18n" href="/web/home"></a>
|
||||||
<a class="navbar-item" href="calendar">Calendar</a>
|
<a i18n-name="ccn-header-nav-calendar" id="cnn-header-nav-calendar" class="navbar-item ccn-i18n" href="/web/calendar"></a>
|
||||||
<a class="navbar-item" href="todo">Todo</a>
|
<a i18n-name="ccn-header-nav-todo" id="cnn-header-nav-todo" class="navbar-item ccn-i18n" href="/web/todo"></a>
|
||||||
<a class="navbar-item" href="admin">Admin</a>
|
<a i18n-name="ccn-header-nav-admin" id="cnn-header-nav-admin" class="navbar-item ccn-i18n" href="/web/admin"></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="navbar-end">
|
<div class="navbar-end">
|
||||||
<p class="control">
|
<p id="cnn-header-user-login" class="navbar-item">
|
||||||
<a class="button is-primary">Login</a>
|
<a class="button is-primary ccn-i18n" i18n-name="ccn-header-user-login" href="/web/login"></a>
|
||||||
</p>
|
</p>
|
||||||
<p class="control">
|
<p id="cnn-header-user-logout" class="navbar-item">
|
||||||
<a class="button is-primary">Logout</a>
|
<a class="button is-primary ccn-i18n" i18n-name="ccn-header-user-logout"></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="navbar-item has-dropdown is-hoverable">
|
<div class="navbar-item has-dropdown is-hoverable">
|
||||||
<a class="navbar-link">Language</a>
|
<a class="navbar-link ccn-i18n" i18n-name="ccn-header-language"></a>
|
||||||
|
|
||||||
<div class="navbar-dropdown">
|
<div id="cnn-header-language" class="navbar-dropdown">
|
||||||
<a class="navbar-item">English</a>
|
<a language="en-US" class="navbar-item">English</a>
|
||||||
<a class="navbar-item">简体中文</a>
|
<a language="zh-CN" class="navbar-item">简体中文</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
37
src/static/tmpl/scheduleItem.tmpl
Normal file
37
src/static/tmpl/scheduleItem.tmpl
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<div class="schedule-day container">
|
||||||
|
<div class="schedule-day-words">
|
||||||
|
<b>13</b>
|
||||||
|
<b>Friday</b>
|
||||||
|
</div>
|
||||||
|
<div class="schedule-event-list">
|
||||||
|
<div class="schedule-event card">
|
||||||
|
<div class="schedule-event-words">
|
||||||
|
<p class="level-item"><b>This is
|
||||||
|
titleewwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww</b>
|
||||||
|
</p>
|
||||||
|
<p class="level-item">this is
|
||||||
|
subtitleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="schedule-event-icon">
|
||||||
|
<span class="icon is-small"><i class="fas fa-lock"></i></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="schedule-event card">
|
||||||
|
<div class="schedule-event-words">
|
||||||
|
<p class="level-item"><b>This is
|
||||||
|
titleewwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww</b>
|
||||||
|
</p>
|
||||||
|
<p class="level-item">this is
|
||||||
|
subtitleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="schedule-event-icon">
|
||||||
|
<span class="icon is-small"><i class="fas fa-lock"></i></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
27
src/static/tmpl/todoItem.tmpl
Normal file
27
src/static/tmpl/todoItem.tmpl
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<div class="todo-item card">
|
||||||
|
<div class="todo-item-words">
|
||||||
|
<p>this is a
|
||||||
|
namewwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="todo-item-icon control">
|
||||||
|
<button class="button"><span class="icon is-small"><i class="fas fa-pen"></i></span></button>
|
||||||
|
</div>
|
||||||
|
<div class="todo-item-icon control">
|
||||||
|
<button class="button"><span class="icon is-small"><i class="fas fa-trash"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="todo-item card">
|
||||||
|
<div class="todo-item-words control">
|
||||||
|
<textarea class="textarea"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="todo-item-icon control">
|
||||||
|
<button class="button"><span class="icon is-small"><i class="fas fa-check"></i></span></button>
|
||||||
|
</div>
|
||||||
|
<div class="todo-item-icon control">
|
||||||
|
<button class="button"><span class="icon is-small"><i class="fas fa-times"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
27
src/static/tmpl/userItem.tmpl
Normal file
27
src/static/tmpl/userItem.tmpl
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<div class="user-item card">
|
||||||
|
<div class="user-item-words">
|
||||||
|
<p><b>this is a name</b></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="user-item-icon control">
|
||||||
|
<a class="button"><span class="icon is-small"><i class="fas fa-pen"></i></span></a>
|
||||||
|
</div>
|
||||||
|
<div class="user-item-icon control">
|
||||||
|
<a class="button"><span class="icon is-small"><i class="fas fa-trash"></i></span></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="user-item card">
|
||||||
|
<div class="user-item-words">
|
||||||
|
<p><b>this is a name</b></p>
|
||||||
|
<div class="control">
|
||||||
|
<input class="input" type="password" placeholder="New password"></input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="user-item-icon control">
|
||||||
|
<a class="button" href="javascript:void(0);"><span class="icon is-small"><i class="fas fa-check"></i></span></a>
|
||||||
|
</div>
|
||||||
|
<div class="user-item-icon control">
|
||||||
|
<a class="button" href="javascript:void(0);"><span class="icon is-small"><i class="fas fa-times"></i></span></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -3,54 +3,27 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>coconut-leaf Admin</title>
|
<title id="ccn-pageName"></title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css">
|
||||||
<script defer src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.1/js/all.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.1/js/all.min.js"></script>
|
||||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.js"></script>
|
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.js"></script>
|
||||||
|
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery-i18n-properties@1.2.7/jquery.i18n.properties.js"></script>
|
||||||
|
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jsrender@1.0.10/jsrender.min.js"></script>
|
||||||
|
|
||||||
<link rel="stylesheet" href="admin.css">
|
<script type="text/x-jsrender" id="jsrender-tmpl-headerNav" src="/static/tmpl/headerNav.tmpl"></script>
|
||||||
|
<script type="text/x-jsrender" id="jsrender-tmpl-userItem" src="/static/tmpl/userItem.tmpl"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="/static/js/localStorageAssist.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/js/i18n.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/js/api.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/js/headerNav.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="/static/js/page/login.js"></script>
|
||||||
|
<link rel="stylesheet" href="/static/css/admin.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar has-shadow is-spaced bd-navbar" role="navigation" aria-label="main navigation">
|
|
||||||
<div class="navbar-brand">
|
|
||||||
<a class="navbar-item" href="home">
|
|
||||||
<img src="icon.png"><b style="margin:0 0 0 14px;">coconut-leaf</b>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false"
|
|
||||||
data-target="navbarBasicExample">
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="navbarBasicExample" class="navbar-menu">
|
|
||||||
<div class="navbar-start">
|
|
||||||
<a class="navbar-item" href="home">Calendar</a>
|
|
||||||
<a class="navbar-item" href="home">Todo</a>
|
|
||||||
<a class="navbar-item" href="about">About</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="navbar-end">
|
|
||||||
<p class="control">
|
|
||||||
<a class="button is-primary" href="javascript:void(0);">Logout</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="navbar-item has-dropdown is-hoverable">
|
|
||||||
<a class="navbar-link">Language</a>
|
|
||||||
|
|
||||||
<div class="navbar-dropdown">
|
|
||||||
<a href="javascript:void(0);" class="navbar-item">English</a>
|
|
||||||
<a href="javascript:void(0);" class="navbar-item">简体中文</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div class="container" style="display: flex; flex-flow: column; margin-top: 1.25rem;">
|
<div class="container" style="display: flex; flex-flow: column; margin-top: 1.25rem;">
|
||||||
<h1 class="title">My account</h1>
|
<h1 class="title">My account</h1>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
|||||||
@@ -3,53 +3,28 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>coconut-leaf Calendar</title>
|
<title id="ccn-pageName"></title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css">
|
||||||
<script defer src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.1/js/all.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.1/js/all.min.js"></script>
|
||||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.js"></script>
|
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.js"></script>
|
||||||
|
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery-i18n-properties@1.2.7/jquery.i18n.properties.js"></script>
|
||||||
|
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jsrender@1.0.10/jsrender.min.js"></script>
|
||||||
|
|
||||||
<link rel="stylesheet" href="calendar.css">
|
<script type="text/x-jsrender" id="jsrender-tmpl-headerNav" src="/static/tmpl/headerNav.tmpl"></script>
|
||||||
|
<script type="text/x-jsrender" id="jsrender-tmpl-calendarItem" src="/static/tmpl/calendarItem.tmpl"></script>
|
||||||
|
<script type="text/x-jsrender" id="jsrender-tmpl-scheduleItem" src="/static/tmpl/scheduleItem.tmpl"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="/static/js/localStorageAssist.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/js/i18n.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/js/api.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/js/headerNav.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="/static/js/page/calendar.js"></script>
|
||||||
|
<link rel="stylesheet" href="/static/css/calendar.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar has-shadow is-spaced bd-navbar" role="navigation" aria-label="main navigation">
|
|
||||||
<div class="navbar-brand">
|
|
||||||
<a class="navbar-item" href="home">
|
|
||||||
<img src="icon.png"><b style="margin:0 0 0 14px;">coconut-leaf</b>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false"
|
|
||||||
data-target="navbarBasicExample">
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="navbarBasicExample" class="navbar-menu">
|
|
||||||
<div class="navbar-start">
|
|
||||||
<a class="navbar-item" href="home">Calendar</a>
|
|
||||||
<a class="navbar-item" href="home">Todo</a>
|
|
||||||
<a class="navbar-item" href="about">About</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="navbar-end">
|
|
||||||
<p class="control">
|
|
||||||
<a class="button is-primary" href="javascript:void(0);">Logout</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="navbar-item has-dropdown is-hoverable">
|
|
||||||
<a class="navbar-link">Language</a>
|
|
||||||
|
|
||||||
<div class="navbar-dropdown">
|
|
||||||
<a href="javascript:void(0);" class="navbar-item">English</a>
|
|
||||||
<a href="javascript:void(0);" class="navbar-item">简体中文</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div class="container" style="margin-top: 20px;">
|
<div class="container" style="margin-top: 20px;">
|
||||||
<div class="tabs">
|
<div class="tabs">
|
||||||
@@ -82,7 +57,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div id="calendar-body" class="card" style="padding: 1.25rem; display: flex; flex-flow: column;">
|
<div id="ccn-calendar-calendarBbody" class="card" style="padding: 1.25rem; display: flex; flex-flow: column;">
|
||||||
<div style="margin: 0 0 0.75em 0;">
|
<div style="margin: 0 0 0.75em 0;">
|
||||||
<div><b>Monday</b></div>
|
<div><b>Monday</b></div>
|
||||||
<div><b>Tuesday</b></div>
|
<div><b>Tuesday</b></div>
|
||||||
@@ -92,65 +67,6 @@
|
|||||||
<div><b style="color: red;">Saturday</b></div>
|
<div><b style="color: red;">Saturday</b></div>
|
||||||
<div><b style="color: red;">Sunday</b></div>
|
<div><b style="color: red;">Sunday</b></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<p><b>1</b></p>
|
|
||||||
<p><small>春分</small></p>
|
|
||||||
<p><span class="icon is-small"><i class="fas fa-tasks"></i></span>114514</p>
|
|
||||||
</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
<div>1</div>
|
|
||||||
</div>
|
|
||||||
</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;">
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>coconut-leaf Login</title>
|
<title id="ccn-pageName"></title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.1/js/all.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.1/js/all.min.js"></script>
|
||||||
@@ -11,26 +11,19 @@
|
|||||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery-i18n-properties@1.2.7/jquery.i18n.properties.js"></script>
|
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery-i18n-properties@1.2.7/jquery.i18n.properties.js"></script>
|
||||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jsrender@1.0.10/jsrender.min.js"></script>
|
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jsrender@1.0.10/jsrender.min.js"></script>
|
||||||
|
|
||||||
<script type="text/x-jsrender" id="jsrender-tmpl-headerNav" src="{{url_tmpl_headerNac}}"></script>
|
<script type="text/x-jsrender" id="jsrender-tmpl-headerNav" src="/static/tmpl/headerNav.tmpl"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="{{url_js_localStorageAssist}}"></script>
|
<script type="text/javascript" src="/static/js/localStorageAssist.js"></script>
|
||||||
<script type="text/javascript" src="{{url_js_i18n}}"></script>
|
<script type="text/javascript" src="/static/js/i18n.js"></script>
|
||||||
<script type="text/javascript" src="{{url_js_api}}"></script>
|
<script type="text/javascript" src="/static/js/api.js"></script>
|
||||||
<script type="text/javascript" src="{{url_js_headerNav}}"></script>
|
<script type="text/javascript" src="/static/js/headerNav.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="{{url_js_pageHome}}"></script>
|
<script type="text/javascript" src="/static/js/page/home.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="container" style="margin-top: 1.25rem;">
|
<div class="container" style="margin-top: 1.25rem;">
|
||||||
<article>
|
<article class="ccn-i18n" i18n-name="ccn-home-desc">
|
||||||
<h1 class="title">coconut-leaf</h1>
|
|
||||||
<p>A light, self-host calendar system.</p>
|
|
||||||
<p>Originally, this app is served for yyc12345's personal use.</p>
|
|
||||||
<br />
|
|
||||||
<p>Pull request / issue / translation are welcomed.</p>
|
|
||||||
<p>Submit them in our <a href="https://github.com/yyc12345/coconut-leaf">GitHub project</a>.</p>
|
|
||||||
|
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -3,53 +3,30 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>coconut-leaf Login</title>
|
<title id="ccn-pageName"></title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css">
|
||||||
<script defer src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.1/js/all.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.1/js/all.min.js"></script>
|
||||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.js"></script>
|
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.js"></script>
|
||||||
|
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery-i18n-properties@1.2.7/jquery.i18n.properties.js"></script>
|
||||||
|
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jsrender@1.0.10/jsrender.min.js"></script>
|
||||||
|
|
||||||
|
<script type="text/x-jsrender" id="jsrender-tmpl-headerNav" src="/static/tmpl/headerNav.tmpl"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="/static/js/localStorageAssist.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/js/i18n.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/js/api.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/js/headerNav.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="/static/js/page/login.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body style="height: 100%; display: flex; flex-flow: column;">
|
<body style="height: 100%; display: flex; flex-flow: column;">
|
||||||
|
|
||||||
<nav class="navbar has-shadow is-spaced bd-navbar" role="navigation" aria-label="main navigation">
|
|
||||||
<div class="navbar-brand">
|
|
||||||
<a class="navbar-item" href="home">
|
|
||||||
<img src="icon.png"><b style="margin:0 0 0 14px;">coconut-leaf</b>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false"
|
|
||||||
data-target="navbarBasicExample">
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="navbarBasicExample" class="navbar-menu">
|
|
||||||
<div class="navbar-start">
|
|
||||||
<a class="navbar-item" href="home">Home</a>
|
|
||||||
<a class="navbar-item" href="about">About</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="navbar-end">
|
|
||||||
<div class="navbar-item has-dropdown is-hoverable">
|
|
||||||
<a class="navbar-link">Language</a>
|
|
||||||
|
|
||||||
<div class="navbar-dropdown">
|
|
||||||
<a class="navbar-item">English</a>
|
|
||||||
<a class="navbar-item">简体中文</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div style="height: 100%; width: 100%; display: flex; justify-content: center; align-items: center;">
|
<div style="height: 100%; width: 100%; display: flex; justify-content: center; align-items: center;">
|
||||||
<div class="card" style="padding: 1.25rem;">
|
<div class="card" style="padding: 1.25rem;">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">Username</label>
|
<label class="label ccn-i18n" i18n-name="ccn-login-form-username"></label>
|
||||||
<div class="control has-icons-left has-icons-right">
|
<div class="control has-icons-left has-icons-right">
|
||||||
<input class="input" type="text">
|
<input class="input" type="text">
|
||||||
<span class="icon is-small is-left">
|
<span class="icon is-small is-left">
|
||||||
@@ -58,7 +35,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">Password</label>
|
<label class="label ccn-i18n" i18n-name="ccn-login-form-password"></label>
|
||||||
<p class="control has-icons-left">
|
<p class="control has-icons-left">
|
||||||
<input class="input" type="password">
|
<input class="input" type="password">
|
||||||
<span class="icon is-small is-left">
|
<span class="icon is-small is-left">
|
||||||
@@ -68,7 +45,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<button class="button is-primary">Login</button>
|
<button class="button is-primary ccn-i18n" i18n-name="ccn-login-form-login"></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,53 +3,27 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>coconut-leaf Calendar</title>
|
<title id="ccn-pageName"></title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css">
|
||||||
<script defer src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.1/js/all.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.1/js/all.min.js"></script>
|
||||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.js"></script>
|
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.js"></script>
|
||||||
|
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery-i18n-properties@1.2.7/jquery.i18n.properties.js"></script>
|
||||||
|
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jsrender@1.0.10/jsrender.min.js"></script>
|
||||||
|
|
||||||
<link rel="stylesheet" href="todo.css">
|
<script type="text/x-jsrender" id="jsrender-tmpl-headerNav" src="/static/tmpl/headerNav.tmpl"></script>
|
||||||
|
<script type="text/x-jsrender" id="jsrender-tmpl-todoItem" src="/static/tmpl/todoItem.tmpl"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="/static/js/localStorageAssist.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/js/i18n.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/js/api.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/js/headerNav.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="/static/js/page/login.js"></script>
|
||||||
|
<link rel="stylesheet" href="/static/css/todo.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar has-shadow is-spaced bd-navbar" role="navigation" aria-label="main navigation">
|
|
||||||
<div class="navbar-brand">
|
|
||||||
<a class="navbar-item" href="home">
|
|
||||||
<img src="icon.png"><b style="margin:0 0 0 14px;">coconut-leaf</b>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false"
|
|
||||||
data-target="navbarBasicExample">
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="navbarBasicExample" class="navbar-menu">
|
|
||||||
<div class="navbar-start">
|
|
||||||
<a class="navbar-item" href="home">Calendar</a>
|
|
||||||
<a class="navbar-item" href="home">Todo</a>
|
|
||||||
<a class="navbar-item" href="about">About</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="navbar-end">
|
|
||||||
<p class="control">
|
|
||||||
<a class="button is-primary" href="javascript:void(0);">Logout</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="navbar-item has-dropdown is-hoverable">
|
|
||||||
<a class="navbar-link">Language</a>
|
|
||||||
|
|
||||||
<div class="navbar-dropdown">
|
|
||||||
<a href="javascript:void(0);" class="navbar-item">English</a>
|
|
||||||
<a href="javascript:void(0);" class="navbar-item">简体中文</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div class="container" style="display: flex; flex-flow: column; margin-top: 1.25rem;">
|
<div class="container" style="display: flex; flex-flow: column; margin-top: 1.25rem;">
|
||||||
<h1 class="title">Todo list</h1>
|
<h1 class="title">Todo list</h1>
|
||||||
|
|||||||
12
src/utils.py
12
src/utils.py
@@ -1,6 +1,7 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
import random
|
import random
|
||||||
import uuid
|
import uuid
|
||||||
|
import time
|
||||||
|
|
||||||
ValidUsername = set(map(lambda x:chr(x), range(48, 58, 1))) | set(map(lambda x:chr(x), range(65, 91, 1))) | set(map(lambda x:chr(x), range(97, 123, 1)))
|
ValidUsername = set(map(lambda x:chr(x), range(48, 58, 1))) | set(map(lambda x:chr(x), range(65, 91, 1))) | set(map(lambda x:chr(x), range(97, 123, 1)))
|
||||||
ValidPassword = set(map(lambda x:chr(x), range(33, 127, 1)))
|
ValidPassword = set(map(lambda x:chr(x), range(33, 127, 1)))
|
||||||
@@ -13,7 +14,7 @@ def IsValidPassword(strl):
|
|||||||
|
|
||||||
def ComputePasswordHash(password):
|
def ComputePasswordHash(password):
|
||||||
s = hashlib.sha256()
|
s = hashlib.sha256()
|
||||||
s.update(password)
|
s.update(password.encode('utf-8'))
|
||||||
return s.hexdigest()
|
return s.hexdigest()
|
||||||
|
|
||||||
def GenerateUUID():
|
def GenerateUUID():
|
||||||
@@ -21,8 +22,8 @@ def GenerateUUID():
|
|||||||
|
|
||||||
def GenerateToken(username):
|
def GenerateToken(username):
|
||||||
s = hashlib.sha256()
|
s = hashlib.sha256()
|
||||||
s.update(username)
|
s.update(username.encode('utf-8'))
|
||||||
s.update(str(GenerateSalt()))
|
s.update((str(GenerateSalt())).encode('utf-8'))
|
||||||
return s.hexdigest()
|
return s.hexdigest()
|
||||||
|
|
||||||
def GenerateSalt():
|
def GenerateSalt():
|
||||||
@@ -30,5 +31,8 @@ def GenerateSalt():
|
|||||||
|
|
||||||
def ComputePasswordHashWithSalt(passwordHashed, salt):
|
def ComputePasswordHashWithSalt(passwordHashed, salt):
|
||||||
s = hashlib.sha256()
|
s = hashlib.sha256()
|
||||||
s.update(passwordHashed + str(salt))
|
s.update((passwordHashed + str(salt)).encode('utf-8'))
|
||||||
return s.hexdigest()
|
return s.hexdigest()
|
||||||
|
|
||||||
|
def GetCurrentTimestamp():
|
||||||
|
return int(time.time())
|
||||||
Reference in New Issue
Block a user