mirror of
https://github.com/Casvt/MIND.git
synced 2026-02-19 11:54:46 -05:00
V1.0.1 (#30)
* 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:
12
Noted.py
12
Noted.py
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ services:
|
||||
noted:
|
||||
container_name: noted
|
||||
volumes:
|
||||
- 'noted-db:/app'
|
||||
- 'noted-db:/app/db'
|
||||
environment:
|
||||
- TZ=Europe/Amsterdam
|
||||
ports:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user