* Update README.md

* Update README.md

* Fixed problem with docker volume mount location

* Updated docker compose with new volume mount location

* Fixed folder creation for db file

* Added support for cross-timezone clients

* Fixed database test

Co-authored-by: Noted <57927413+ItsNoted@users.noreply.github.com>
This commit is contained in:
Casvt
2023-01-24 15:33:16 +01:00
committed by GitHub
parent dfc949e766
commit d1d39a94ff
10 changed files with 45 additions and 28 deletions

View File

@@ -1,21 +1,21 @@
#!/usr/bin/env python3
#-*- coding: utf-8 -*-
from os import urandom
from os.path import dirname, join, abspath
from os import makedirs, urandom
from os.path import abspath, dirname, join
from sys import version_info
from flask import Flask, render_template, request
from waitress.server import create_server
from backend.db import close_db, setup_db, DBConnection
from backend.db import DBConnection, close_db, setup_db
from frontend.api import api, reminder_handler
from frontend.ui import ui
HOST = '0.0.0.0'
PORT = '8080'
THREADS = 10
DB_FILENAME = 'Noted.db'
DB_FILENAME = 'db', 'Noted.db'
def _folder_path(*folders) -> str:
"""Turn filepaths relative to the project folder into absolute paths
@@ -79,7 +79,9 @@ def Noted() -> None:
# Register web server
app = _create_app()
with app.app_context():
DBConnection.file = _folder_path(DB_FILENAME)
db_location = _folder_path(*DB_FILENAME)
makedirs(dirname(db_location), exist_ok=True)
DBConnection.file = db_location
setup_db()
reminder_handler._find_next_reminder()

View File

@@ -27,10 +27,9 @@ You can see our planned features in our [Project board](https://github.com/users
## Installation
Replace the timezone value (`TZ=`) to the [TZ database name](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) of your timezone!
```bash
docker volume create noted-db
docker run -d \
--name noted \
-v noted-db:/app \
-v noted-db:/app/db \
-e TZ=Europe/Amsterdam \
-p 8080:8080 \
mrcas/noted:latest

View File

@@ -1,12 +1,14 @@
#-*- coding: utf-8 -*-
from datetime import datetime
from sqlite3 import Connection, Row
from threading import current_thread
from time import time
from typing import Union
from flask import g
__DATABASE_VERSION__ = 1
__DATABASE_VERSION__ = 2
class Singleton(type):
_instances = {}
@@ -67,7 +69,18 @@ def migrate_db(current_db_version: int) -> None:
"""
print('Migrating database to newer version...')
cursor = get_db()
if current_db_version == 1:
# V1 -> V2
t = time()
utc_offset = datetime.fromtimestamp(t) - datetime.utcfromtimestamp(t)
reminders = cursor.execute("SELECT time, id FROM reminders;").fetchall()
new_reminders = []
new_reminders_append = new_reminders.append
for reminder in reminders:
new_reminders_append([round((datetime.fromtimestamp(reminder[0]) - utc_offset).timestamp()), reminder[1]])
cursor.executemany("UPDATE reminders SET time = ? WHERE id = ?;", new_reminders)
__DATABASE_VERSION__ = 2
return
def setup_db() -> None:

View File

@@ -29,7 +29,7 @@ def _find_next_time(
) -> int:
td = relativedelta(**{repeat_quantity: repeat_interval})
new_time = datetime.fromtimestamp(original_time)
current_time = datetime.fromtimestamp(epoch_time())
current_time = datetime.fromtimestamp(datetime.utcnow().timestamp())
while new_time <= current_time:
new_time += td
return int(new_time.timestamp())
@@ -76,7 +76,7 @@ class ReminderHandler():
def _handle(self) -> None:
while not self.stop:
if self.next_reminder and self.next_reminder <= epoch_time():
if self.next_reminder and self.next_reminder <= datetime.utcnow().timestamp():
with self.context():
cursor = get_db(dict)
# Get all reminders for the timestamp
@@ -182,7 +182,7 @@ class Reminder:
Args:
title (str): The new title of the entry. Defaults to None.
time (int): The new epoch timestamp the the reminder should be send. Defaults to None.
time (int): The new UTC epoch timestamp the the reminder should be send. Defaults to None.
notification_service (int): The new id of the notification service to use to send the reminder. Defaults to None.
text (str, optional): The new body of the reminder. Defaults to None.
@@ -198,10 +198,11 @@ class Reminder:
raise InvalidKeyValue('repeat_interval', repeat_interval)
repeated_reminder = repeat_quantity is not None and repeat_interval is not None
if not repeated_reminder:
if time < epoch_time():
raise InvalidTime
time = round(time)
if time is not None:
if not repeated_reminder:
if time < datetime.utcnow().timestamp():
raise InvalidTime
time = round(time)
# Get current data and update it with new values
data = self.get()
@@ -355,7 +356,7 @@ class Reminders:
Args:
title (str): The title of the entry
time (int): The epoch timestamp the the reminder should be send.
time (int): The UTC epoch timestamp the the reminder should be send.
notification_service (int): The id of the notification service to use to send the reminder.
text (str, optional): The body of the reminder. Defaults to ''.
repeat_quantity (Literal["year", "month", "week", "day", "hours", "minutes"], optional): The quantity of the repeat specified for the reminder. Defaults to None.
@@ -364,7 +365,7 @@ class Reminders:
Returns:
dict: The info about the reminder
"""
if time < epoch_time():
if time < datetime.utcnow().timestamp():
raise InvalidTime
time = round(time)

View File

@@ -3,7 +3,7 @@ services:
noted:
container_name: noted
volumes:
- 'noted-db:/app'
- 'noted-db:/app/db'
environment:
- TZ=Europe/Amsterdam
ports:

View File

@@ -401,7 +401,7 @@ def api_reminders_list():
Description: Add a reminder
Parameters (body (content-type: application/json)):
title (required): the title of the reminder
time (required): the epoch timestamp that the reminder should be sent at
time (required): the UTC epoch timestamp that the reminder should be sent at
notification_service (required): the id of the notification service to use to send the notification
text: the body of the reminder
repeat_quantity ('year', 'month', 'week', 'day', 'hours', 'minutes'): The quantity of the repeat_interval
@@ -481,7 +481,7 @@ def api_get_reminder(r_id: int):
Description: Edit the reminder
Parameters (body (content-type: application/json)):
title: The new title of the entry.
time: The new epoch timestamp the the reminder should be send.
time: The new UTC epoch timestamp the the reminder should be send.
notification_service: The new id of the notification service to use to send the reminder.
text: The new body of the reminder.
repeat_quantity ('year', 'month', 'week', 'day', 'hours', 'minutes'): The quantity of the repeat_interval

View File

@@ -20,7 +20,7 @@ function addReminder() {
const data = {
'title': inputs.title.value,
'time': new Date(inputs.time.value).getTime() / 1000,
'time': (new Date(inputs.time.value) / 1000) + (new Date(inputs.time.value).getTimezoneOffset() * 60),
'notification_service': inputs.notification_service.value,
'text': inputs.text.value
};

View File

@@ -18,7 +18,7 @@ function editReminder() {
const id = document.getElementById('edit-form').dataset.id;
const data = {
'title': edit_inputs.title.value,
'time': new Date(edit_inputs.time.value).getTime() / 1000,
'time': (new Date(edit_inputs.time.value) / 1000) + (new Date(edit_inputs.time.value).getTimezoneOffset() * 60),
'notification_service': edit_inputs.notification_service.value,
'text': edit_inputs.text.value,
'repeat_quantity': null,
@@ -67,9 +67,10 @@ function showEdit(id) {
.then(json => {
edit_inputs.title.value = json.result.title;
edit_inputs.time.value = new Date(
var trigger_date = new Date(
(json.result.time + new Date(json.result.time * 1000).getTimezoneOffset() * -60) * 1000
).toISOString().slice(0, 16);
);
edit_inputs.time.value = trigger_date.toLocaleString('en-CA').slice(0,10) + 'T' + trigger_date.toTimeString().slice(0,5);
edit_inputs.notification_service.value = json.result.notification_service;
if (json.result['repeat_interval'] === null) {

View File

@@ -13,7 +13,8 @@ function fillTable(result) {
entry.appendChild(title);
const time = document.createElement('p');
var d = new Date(reminder.time * 1000);
var offset = new Date(reminder.time * 1000).getTimezoneOffset() * -60;
var d = new Date((reminder.time + offset) * 1000);
var formatted_date = d.toLocaleString('en-CA').slice(0,10) + ' ' + d.toTimeString().slice(0,5);
if (reminder.repeat_interval !== null) {
if (reminder.repeat_interval === 1) {

View File

@@ -1,11 +1,11 @@
import unittest
from backend.db import DBConnection
from Noted import DB_FILENAME
from Noted import DB_FILENAME, _folder_path
class Test_DB(unittest.TestCase):
def test_foreign_key(self):
DBConnection.file = DB_FILENAME
DBConnection.file = _folder_path(*DB_FILENAME)
instance = DBConnection(timeout=20.0)
self.assertEqual(instance.cursor().execute("PRAGMA foreign_keys;").fetchone()[0], 1)