diff --git a/TODO b/TODO index b02a72897..7bfd60e5a 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,8 @@ -- conflict detection - - note title and content changes are not in audit_log table - deleting cloned nodes ends with 500 (probably only on folders) - what links here - recent changes - link to note should lead to the revision - db upgrade / migration -- dates should be stored in UTC to work correctly with time zones \ No newline at end of file +- dates should be stored in UTC to work correctly with time zones + - we should also record timezone info so that we display the date correctly with respect to the local date at the time of recording it +- modularize frontend + - unify handling of global variables \ No newline at end of file diff --git a/src/notes_api.py b/src/notes_api.py index 21cc89707..4aa4f147b 100644 --- a/src/notes_api.py +++ b/src/notes_api.py @@ -12,6 +12,7 @@ from sql import delete from sql import execute, insert, commit from sql import getResults, getSingleResult, getOption, addAudit, deleteRecentAudits +import utils import audit_category notes_api = Blueprint('notes_api', __name__) @@ -44,7 +45,7 @@ def updateNote(note_id): note = request.get_json(force=True) - now = math.floor(time.time()) + now = utils.nowTimestamp() history_snapshot_time_interval = float(getOption('history_snapshot_time_interval')) @@ -154,7 +155,7 @@ def createChild(parent_note_id): addAudit(audit_category.CREATE_NOTE, request, noteId) - now = math.floor(time.time()) + now = utils.nowTimestamp() insert("notes", { 'note_id': noteId, diff --git a/src/sql.py b/src/sql.py index c891e7a36..c067f5e35 100644 --- a/src/sql.py +++ b/src/sql.py @@ -4,6 +4,8 @@ import sqlite3 import math import time +import utils + conn = None def dict_factory(cursor, row): @@ -36,7 +38,7 @@ def getOption(name): return getSingleResult("SELECT opt_value FROM options WHERE opt_name = ?", [name])['opt_value'] def addAudit(category, request = None, note_id = None, change_from = None, change_to = None, comment = None): - now = math.floor(time.time()) + now = utils.nowTimestamp() browser_id = None @@ -49,7 +51,7 @@ def addAudit(category, request = None, note_id = None, change_from = None, chang def deleteRecentAudits(category, request, note_id): browser_id = request.headers['x-browser-id'] - delete_cutoff = math.floor(time.time()) - 10 * 60; + delete_cutoff = utils.nowTimestamp() - 10 * 60; execute("DELETE FROM audit_log WHERE category = ? AND browser_id = ? AND note_id = ? AND date_modified > ?", [category, browser_id, note_id, delete_cutoff]) diff --git a/src/tree_api.py b/src/tree_api.py index 675e5449f..44509c37a 100644 --- a/src/tree_api.py +++ b/src/tree_api.py @@ -7,6 +7,7 @@ from flask import Blueprint, jsonify from flask_login import login_required from sql import getResults, getSingleResult, getOption +import utils tree_api = Blueprint('tree_api', __name__) @@ -50,6 +51,6 @@ def getTree(): retObject['encrypted_data_key'] = getOption('encrypted_data_key') retObject['encryption_session_timeout'] = getOption('encryption_session_timeout') retObject['browser_id'] = base64.b64encode(os.urandom(8)) - retObject['full_load_time'] = math.floor(time.time()) + retObject['full_load_time'] = utils.nowTimestamp() return jsonify(retObject) \ No newline at end of file diff --git a/src/utils.py b/src/utils.py new file mode 100644 index 000000000..3bbdf40e1 --- /dev/null +++ b/src/utils.py @@ -0,0 +1,5 @@ +from datetime import datetime +import time + +def nowTimestamp(): + return time.mktime(datetime.utcnow().timetuple()) diff --git a/static/js/init.js b/static/js/init.js index 6056f660a..22bea3c75 100644 --- a/static/js/init.js +++ b/static/js/init.js @@ -15,6 +15,16 @@ $(document).bind('keydown', 'alt+s', function() { $("input[name=search]").focus(); }); +function getDateFromTS(timestamp) { + // Date accepts number of milliseconds since epoch so UTC timestamp works without any extra handling + // see https://stackoverflow.com/questions/4631928/convert-utc-epoch-to-local-date-with-javascript + const utcDate = new Date(timestamp * 1000); + + const localDate = new Date(utcDate.getTime() - utcDate.getTimezoneOffset() * 60 * 1000); + + return localDate; +} + function formatTime(date) { return (date.getHours() <= 9 ? "0" : "") + date.getHours() + ":" + (date.getMinutes() <= 9 ? "0" : "") + date.getMinutes(); } diff --git a/static/js/note_history.js b/static/js/note_history.js index 089599804..69cc05cc7 100644 --- a/static/js/note_history.js +++ b/static/js/note_history.js @@ -17,7 +17,7 @@ $(document).bind('keydown', 'alt+h', function() { globalHistoryItems = result; for (const row of result) { - const dateModified = new Date(row.date_modified * 1000); + const dateModified = getDateFromTS(row.date_modified); $("#noteHistoryList").append($('