mirror of
https://github.com/Casvt/MIND.git
synced 2026-02-19 11:54:46 -05:00
Fixes issue #28
This commit is contained in:
@@ -8,7 +8,7 @@ from typing import Union
|
||||
|
||||
from flask import g
|
||||
|
||||
__DATABASE_VERSION__ = 2
|
||||
__DATABASE_VERSION__ = 3
|
||||
|
||||
class Singleton(type):
|
||||
_instances = {}
|
||||
@@ -79,7 +79,17 @@ def migrate_db(current_db_version: int) -> None:
|
||||
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
|
||||
current_db_version = 2
|
||||
|
||||
if current_db_version == 2:
|
||||
# V2 -> V3
|
||||
cursor.executescript("""
|
||||
ALTER TABLE reminders
|
||||
ADD color VARCHAR(7);
|
||||
ALTER TABLE templates
|
||||
ADD color VARCHAR(7);
|
||||
""")
|
||||
current_db_version = 3
|
||||
|
||||
return
|
||||
|
||||
@@ -115,6 +125,8 @@ def setup_db() -> None:
|
||||
repeat_interval INTEGER,
|
||||
original_time INTEGER,
|
||||
|
||||
color VARCHAR(7),
|
||||
|
||||
FOREIGN KEY (user_id) REFERENCES users(id),
|
||||
FOREIGN KEY (notification_service) REFERENCES notification_services(id)
|
||||
);
|
||||
@@ -125,6 +137,8 @@ def setup_db() -> None:
|
||||
text TEXT,
|
||||
notification_service INTEGER NOT NULL,
|
||||
|
||||
color VARCHAR(7),
|
||||
|
||||
FOREIGN KEY (user_id) REFERENCES users(id),
|
||||
FOREIGN KEY (notification_service) REFERENCES notification_services(id)
|
||||
);
|
||||
|
||||
@@ -156,7 +156,8 @@ class Reminder:
|
||||
r.notification_service,
|
||||
ns.title AS notification_service_title,
|
||||
r.repeat_quantity,
|
||||
r.repeat_interval
|
||||
r.repeat_interval,
|
||||
r.color
|
||||
FROM
|
||||
reminders r
|
||||
INNER JOIN notification_services ns
|
||||
@@ -176,7 +177,8 @@ class Reminder:
|
||||
notification_service: int = None,
|
||||
text: str = None,
|
||||
repeat_quantity: Literal["year", "month", "week", "day", "hours", "minutes"] = None,
|
||||
repeat_interval: int = None
|
||||
repeat_interval: int = None,
|
||||
color: str = None
|
||||
) -> dict:
|
||||
"""Edit the reminder
|
||||
|
||||
@@ -185,6 +187,9 @@ class Reminder:
|
||||
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.
|
||||
repeat_quantity (Literal["year", "month", "week", "day", "hours", "minutes"], optional): The new quantity of the repeat specified for the reminder. Defaults to None.
|
||||
repeat_interval (int, optional): The new amount of repeat_quantity, like "5" (hours). Defaults to None.
|
||||
color (str, optional): The new hex code of the color of the reminder, which is shown in the web-ui. Defaults to None.
|
||||
|
||||
Returns:
|
||||
dict: The new reminder info
|
||||
@@ -212,10 +217,11 @@ class Reminder:
|
||||
'notification_service': notification_service,
|
||||
'text': text,
|
||||
'repeat_quantity': repeat_quantity,
|
||||
'repeat_interval': repeat_interval
|
||||
'repeat_interval': repeat_interval,
|
||||
'color': color
|
||||
}
|
||||
for k, v in new_values.items():
|
||||
if k in ('repeat_quantity', 'repeat_interval') or v is not None:
|
||||
if k in ('repeat_quantity', 'repeat_interval', 'color') or v is not None:
|
||||
data[k] = v
|
||||
|
||||
# Update database
|
||||
@@ -224,7 +230,7 @@ class Reminder:
|
||||
next_time = data["time"]
|
||||
cursor.execute("""
|
||||
UPDATE reminders
|
||||
SET title=?, text=?, time=?, notification_service=?, repeat_quantity=?, repeat_interval=?
|
||||
SET title=?, text=?, time=?, notification_service=?, repeat_quantity=?, repeat_interval=?, color=?
|
||||
WHERE id = ?;
|
||||
""", (
|
||||
data["title"],
|
||||
@@ -233,13 +239,14 @@ class Reminder:
|
||||
data["notification_service"],
|
||||
data["repeat_quantity"],
|
||||
data["repeat_interval"],
|
||||
data["color"],
|
||||
self.id
|
||||
))
|
||||
else:
|
||||
next_time = _find_next_time(data["time"], data["repeat_quantity"], data["repeat_interval"])
|
||||
cursor.execute("""
|
||||
UPDATE reminders
|
||||
SET title=?, text=?, time=?, notification_service=?, repeat_quantity=?, repeat_interval=?, original_time=?
|
||||
SET title=?, text=?, time=?, notification_service=?, repeat_quantity=?, repeat_interval=?, original_time=?, color=?
|
||||
WHERE id = ?;
|
||||
""", (
|
||||
data["title"],
|
||||
@@ -249,6 +256,7 @@ class Reminder:
|
||||
data["repeat_quantity"],
|
||||
data["repeat_interval"],
|
||||
data["time"],
|
||||
data["color"],
|
||||
self.id
|
||||
))
|
||||
except IntegrityError:
|
||||
@@ -284,7 +292,7 @@ class Reminders:
|
||||
sort_by (Literal["time", "time_reversed", "title", "title_reversed"], optional): How to sort the result. Defaults to "time".
|
||||
|
||||
Returns:
|
||||
List[dict]: The id, title, text, time, notification_service and notification_service_title of each reminder
|
||||
List[dict]: The id, title, text, time, notification_service, notification_service_title and color of each reminder
|
||||
"""
|
||||
sort_function = self.sort_functions.get(
|
||||
sort_by,
|
||||
@@ -300,7 +308,8 @@ class Reminders:
|
||||
r.notification_service,
|
||||
ns.title AS notification_service_title,
|
||||
r.repeat_quantity,
|
||||
r.repeat_interval
|
||||
r.repeat_interval,
|
||||
r.color
|
||||
FROM
|
||||
reminders r
|
||||
INNER JOIN notification_services ns
|
||||
@@ -350,7 +359,8 @@ class Reminders:
|
||||
notification_service: int,
|
||||
text: str = '',
|
||||
repeat_quantity: Literal["year", "month", "week", "day", "hours", "minutes"] = None,
|
||||
repeat_interval: int = None
|
||||
repeat_interval: int = None,
|
||||
color: str = None
|
||||
) -> Reminder:
|
||||
"""Add a reminder
|
||||
|
||||
@@ -361,6 +371,7 @@ class Reminders:
|
||||
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.
|
||||
repeat_interval (int, optional): The amount of repeat_quantity, like "5" (hours). Defaults to None.
|
||||
color (str, optional): The hex code of the color of the reminder, which is shown in the web-ui. Defaults to None.
|
||||
|
||||
Returns:
|
||||
dict: The info about the reminder
|
||||
@@ -377,15 +388,15 @@ class Reminders:
|
||||
try:
|
||||
if repeat_quantity is None and repeat_interval is None:
|
||||
id = get_db().execute("""
|
||||
INSERT INTO reminders(user_id, title, text, time, notification_service)
|
||||
VALUES (?,?,?,?,?);
|
||||
""", (self.user_id, title, text, time, notification_service)
|
||||
INSERT INTO reminders(user_id, title, text, time, notification_service, color)
|
||||
VALUES (?,?,?,?,?, ?);
|
||||
""", (self.user_id, title, text, time, notification_service, color)
|
||||
).lastrowid
|
||||
else:
|
||||
id = get_db().execute("""
|
||||
INSERT INTO reminders(user_id, title, text, time, notification_service, repeat_quantity, repeat_interval, original_time)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?);
|
||||
""", (self.user_id, title, text, time, notification_service, repeat_quantity, repeat_interval, time)
|
||||
INSERT INTO reminders(user_id, title, text, time, notification_service, repeat_quantity, repeat_interval, original_time, color)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||
""", (self.user_id, title, text, time, notification_service, repeat_quantity, repeat_interval, time, color)
|
||||
).lastrowid
|
||||
except IntegrityError:
|
||||
raise NotificationServiceNotFound
|
||||
|
||||
@@ -27,7 +27,8 @@ class Template:
|
||||
SELECT
|
||||
id,
|
||||
title, text,
|
||||
notification_service
|
||||
notification_service,
|
||||
color
|
||||
FROM templates
|
||||
WHERE id = ?;
|
||||
""",
|
||||
@@ -39,7 +40,8 @@ class Template:
|
||||
def update(self,
|
||||
title: str = None,
|
||||
notification_service: int = None,
|
||||
text: str = None
|
||||
text: str = None,
|
||||
color: str = None
|
||||
) -> dict:
|
||||
"""Edit the template
|
||||
|
||||
@@ -47,6 +49,7 @@ class Template:
|
||||
title (str): The new title of the entry. 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 template. Defaults to None.
|
||||
color (str, optional): The new hex code of the color of the template, which is shown in the web-ui. Defaults to None.
|
||||
|
||||
Returns:
|
||||
dict: The new template info
|
||||
@@ -57,21 +60,23 @@ class Template:
|
||||
new_values = {
|
||||
'title': title,
|
||||
'notification_service': notification_service,
|
||||
'text': text
|
||||
'text': text,
|
||||
'color': color
|
||||
}
|
||||
for k, v in new_values.items():
|
||||
if v is not None:
|
||||
if k in ('color',) or v is not None:
|
||||
data[k] = v
|
||||
|
||||
try:
|
||||
cursor.execute("""
|
||||
UPDATE templates
|
||||
SET title=?, notification_service=?, text=?
|
||||
SET title=?, notification_service=?, text=?, color=?
|
||||
WHERE id = ?;
|
||||
""", (
|
||||
data['title'],
|
||||
data['notification_service'],
|
||||
data['text'],
|
||||
data['color'],
|
||||
self.id
|
||||
))
|
||||
except IntegrityError:
|
||||
@@ -95,13 +100,14 @@ class Templates:
|
||||
"""Get all templates
|
||||
|
||||
Returns:
|
||||
List[dict]: The id, title, text and notification_service
|
||||
List[dict]: The id, title, text, notification_service and color
|
||||
"""
|
||||
templates: list = list(map(dict, get_db(dict).execute("""
|
||||
SELECT
|
||||
id,
|
||||
title, text,
|
||||
notification_service
|
||||
notification_service,
|
||||
color
|
||||
FROM templates
|
||||
WHERE user_id = ?
|
||||
ORDER BY title, id;
|
||||
@@ -126,7 +132,8 @@ class Templates:
|
||||
self,
|
||||
title: str,
|
||||
notification_service: int,
|
||||
text: str = ''
|
||||
text: str = '',
|
||||
color: str = None
|
||||
) -> Template:
|
||||
"""Add a template
|
||||
|
||||
@@ -134,16 +141,17 @@ class Templates:
|
||||
title (str): The title of the entry
|
||||
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 ''.
|
||||
color (str, optional): The hex code of the color of the template, which is shown in the web-ui. Defaults to None.
|
||||
|
||||
Returns:
|
||||
Template: The info about the template
|
||||
"""
|
||||
try:
|
||||
id = get_db().execute("""
|
||||
INSERT INTO templates(user_id, title, text, notification_service)
|
||||
VALUES (?,?,?,?);
|
||||
INSERT INTO templates(user_id, title, text, notification_service, color)
|
||||
VALUES (?,?,?,?,?);
|
||||
""",
|
||||
(self.user_id, title, text, notification_service)
|
||||
(self.user_id, title, text, notification_service, color)
|
||||
).lastrowid
|
||||
except IntegrityError:
|
||||
raise NotificationServiceNotFound
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
from os import urandom
|
||||
from time import time as epoch_time
|
||||
from typing import Any, Tuple
|
||||
from re import compile
|
||||
|
||||
from flask import Blueprint, g, request
|
||||
|
||||
@@ -20,6 +21,7 @@ from backend.users import User, register_user
|
||||
|
||||
api = Blueprint('api', __name__)
|
||||
api_key_map = {}
|
||||
color_regex = compile(r'#[0-9a-f]{6}')
|
||||
|
||||
"""
|
||||
AUTHENTICATION:
|
||||
@@ -104,6 +106,10 @@ def extract_key(values: dict, key: str, check_existence: bool=True) -> Any:
|
||||
'text', 'query'):
|
||||
if not isinstance(value, str):
|
||||
raise InvalidKeyValue(key, value)
|
||||
|
||||
elif key == 'color':
|
||||
if not color_regex.search(value):
|
||||
raise InvalidKeyValue(key, value)
|
||||
|
||||
else:
|
||||
if key == 'sort_by':
|
||||
@@ -127,7 +133,7 @@ def api_login():
|
||||
Requires being logged in: No
|
||||
Methods:
|
||||
POST:
|
||||
Parameters (body (content-type: application/json)):
|
||||
Parameters (body):
|
||||
username (required): the username of the user account
|
||||
password (required): the password of the user account
|
||||
Returns:
|
||||
@@ -216,7 +222,7 @@ def api_add_user():
|
||||
Requires being logged in: No
|
||||
Methods:
|
||||
POST:
|
||||
Parameters (body (content-type: application/json)):
|
||||
Parameters (body):
|
||||
username (required): the username of the new user account
|
||||
password (required): the password of the new user account
|
||||
Returns:
|
||||
@@ -248,7 +254,7 @@ def api_manage_user():
|
||||
Methods:
|
||||
PUT:
|
||||
Description: Change the password of the user account
|
||||
Parameters (body (content-type: application/json)):
|
||||
Parameters (body):
|
||||
new_password (required): the new password of the user account
|
||||
Returns:
|
||||
200:
|
||||
@@ -297,7 +303,7 @@ def api_notification_services_list():
|
||||
The id, title and url of every notification service
|
||||
POST:
|
||||
Description: Add a notification service
|
||||
Parameters (body (content-type: application/json)):
|
||||
Parameters (body):
|
||||
title (required): the title of the notification service
|
||||
url (required): the apprise url of the notification service
|
||||
Returns:
|
||||
@@ -340,7 +346,7 @@ def api_notification_service(n_id: int):
|
||||
No notification service found with the given id
|
||||
PUT:
|
||||
Description: Edit the notification service
|
||||
Parameters (body (content-type: application/json)):
|
||||
Parameters (body):
|
||||
title: The new title of the entry.
|
||||
url: The new apprise url of the entry.
|
||||
Returns:
|
||||
@@ -396,16 +402,17 @@ def api_reminders_list():
|
||||
sort_by: how to sort the result. Allowed values are 'title', 'title_reversed', 'time' and 'time_reversed'
|
||||
Returns:
|
||||
200:
|
||||
The id, title, text, time, notification_service, notification_service_title, repeat_quantity and repeat_interval of each reminder
|
||||
The id, title, text, time, notification_service, notification_service_title, repeat_quantity, repeat_interval and color of each reminder
|
||||
POST:
|
||||
Description: Add a reminder
|
||||
Parameters (body (content-type: application/json)):
|
||||
Parameters (body):
|
||||
title (required): the title of the reminder
|
||||
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
|
||||
repeat_interval: The number of the interval
|
||||
color: The hex code of the color of the reminder, which is shown in the web-ui
|
||||
Returns:
|
||||
200:
|
||||
The info about the new reminder entry
|
||||
@@ -427,13 +434,15 @@ def api_reminders_list():
|
||||
text = extract_key(data, 'text', check_existence=False)
|
||||
repeat_quantity = extract_key(data, 'repeat_quantity', check_existence=False)
|
||||
repeat_interval = extract_key(data, 'repeat_interval', check_existence=False)
|
||||
color = extract_key(data, 'color', check_existence=False)
|
||||
|
||||
result = reminders.add(title=title,
|
||||
time=time,
|
||||
notification_service=notification_service,
|
||||
text=text,
|
||||
repeat_quantity=repeat_quantity,
|
||||
repeat_interval=repeat_interval)
|
||||
repeat_interval=repeat_interval,
|
||||
color=color)
|
||||
return return_api(result.get(), code=201)
|
||||
|
||||
@api.route('/reminders/search', methods=['GET'])
|
||||
@@ -463,6 +472,24 @@ def api_reminders_query():
|
||||
@error_handler
|
||||
@auth
|
||||
def api_test_reminder():
|
||||
"""
|
||||
Endpoint: /reminders/test
|
||||
Description: Test send a reminder draft
|
||||
Requires being logged in: Yes
|
||||
Methods:
|
||||
GET:
|
||||
Parameters (body):
|
||||
title (required): The title of the entry.
|
||||
notification_service (required): The new id of the notification service to use to send the reminder.
|
||||
text: The body of the reminder.
|
||||
Returns:
|
||||
201:
|
||||
The reminder is sent (doesn't mean it works, just that it was sent)
|
||||
400:
|
||||
KeyNotFound: One of the required parameters was not given
|
||||
404:
|
||||
NotificationServiceNotFound: The notification service given was not found
|
||||
"""
|
||||
data = request.get_json()
|
||||
title = extract_key(data, 'title')
|
||||
notification_service = extract_key(data, 'notification_service')
|
||||
@@ -491,13 +518,14 @@ def api_get_reminder(r_id: int):
|
||||
No reminder found with the given id
|
||||
PUT:
|
||||
Description: Edit the reminder
|
||||
Parameters (body (content-type: application/json)):
|
||||
Parameters (body):
|
||||
title: The new title of the entry.
|
||||
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
|
||||
repeat_interval: The number of the interval
|
||||
repeat_quantity ('year', 'month', 'week', 'day', 'hours', 'minutes'): The new quantity of the repeat_interval.
|
||||
repeat_interval: The new number of the interval.
|
||||
color: The new hex code of the color of the reminder, which is shown in the web-ui.
|
||||
Returns:
|
||||
200:
|
||||
Reminder updated successfully
|
||||
@@ -524,14 +552,15 @@ def api_get_reminder(r_id: int):
|
||||
text = extract_key(data, 'text', check_existence=False)
|
||||
repeat_quantity = extract_key(data, 'repeat_quantity', check_existence=False)
|
||||
repeat_interval = extract_key(data, 'repeat_interval', check_existence=False)
|
||||
|
||||
color = extract_key(data, 'color', check_existence=False)
|
||||
|
||||
result = reminders.fetchone(r_id).update(title=title,
|
||||
time=time,
|
||||
notification_service=notification_service,
|
||||
text=text,
|
||||
repeat_quantity=repeat_quantity,
|
||||
repeat_interval=repeat_interval)
|
||||
repeat_interval=repeat_interval,
|
||||
color=color)
|
||||
return return_api(result)
|
||||
|
||||
elif request.method == 'DELETE':
|
||||
@@ -555,13 +584,14 @@ def api_get_templates():
|
||||
Description: Get a list of all templates
|
||||
Returns:
|
||||
200:
|
||||
The id, title, notification_service and text of every template
|
||||
The id, title, notification_service, text and color of every template
|
||||
POST:
|
||||
Description: Add a template
|
||||
Parameters (body (content-type: application/json)):
|
||||
Parameters (body):
|
||||
title (required): the title of the template
|
||||
notification_service (required): the id of the notification service to use to send the notification
|
||||
text: the body of the template
|
||||
color: the hex code of the color of the template, which is shown in the web-ui
|
||||
Returns:
|
||||
200:
|
||||
The info about the new template entry
|
||||
@@ -579,10 +609,12 @@ def api_get_templates():
|
||||
title = extract_key(data, 'title')
|
||||
notification_service = extract_key(data, 'notification_service')
|
||||
text = extract_key(data, 'text', check_existence=False)
|
||||
color = extract_key(data, 'color', check_existence=False)
|
||||
|
||||
result = templates.add(title=title,
|
||||
notification_service=notification_service,
|
||||
text=text)
|
||||
text=text,
|
||||
color=color)
|
||||
return return_api(result.get(), code=201)
|
||||
|
||||
@api.route('/templates/<int:t_id>', methods=['GET', 'PUT', 'DELETE'])
|
||||
@@ -605,10 +637,11 @@ def api_get_template(t_id: int):
|
||||
No template found with the given id
|
||||
PUT:
|
||||
Description: Edit the template
|
||||
Parameters (body (content-type: application/json)):
|
||||
Parameters (body):
|
||||
title: The new title of the entry.
|
||||
notification_service: The new id of the notification service to use to send the reminder.
|
||||
text: The new body of the template.
|
||||
color: The new hex code of the color of the template.
|
||||
Returns:
|
||||
200:
|
||||
Template updated successfully
|
||||
@@ -633,10 +666,12 @@ def api_get_template(t_id: int):
|
||||
title = extract_key(data, 'title', check_existence=False)
|
||||
notification_service = extract_key(data, 'notification_service', check_existence=False)
|
||||
text = extract_key(data, 'text', check_existence=False)
|
||||
color = extract_key(data, 'color', check_existence=False)
|
||||
|
||||
result = template.update(title=title,
|
||||
notification_service=notification_service,
|
||||
text=text)
|
||||
text=text,
|
||||
color=color)
|
||||
return return_api(result)
|
||||
|
||||
elif request.method == 'DELETE':
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
width: calc(50% - (var(--gap) / 2));
|
||||
}
|
||||
|
||||
.form-container > form > button,
|
||||
.sub-inputs > button {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@@ -54,6 +55,32 @@
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.color-list {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
|
||||
padding: 1rem;
|
||||
border: 2px solid var(--color-gray);
|
||||
border-radius: 4px;
|
||||
box-shadow: var(--default-shadow);
|
||||
}
|
||||
|
||||
.color-list > button {
|
||||
height: 1.5rem;
|
||||
width: 1.5rem;
|
||||
|
||||
padding: 1rem;
|
||||
border: 1px solid transparent;
|
||||
background-color: var(--color);
|
||||
}
|
||||
|
||||
.color-list > button[data-selected='true'] {
|
||||
border-color: var(--color-white);
|
||||
}
|
||||
|
||||
.repeat-bar,
|
||||
.repeat-edit-bar {
|
||||
display: flex;
|
||||
@@ -134,7 +161,8 @@ div.options > button {
|
||||
|
||||
@media (max-width: 460px) {
|
||||
.sub-inputs > input,
|
||||
.sub-inputs > select {
|
||||
.sub-inputs > select,
|
||||
.sub-inputs > button {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,8 @@
|
||||
--color-gray: #3c3c3c;
|
||||
--color-dark: #1b1b1b;
|
||||
|
||||
--color-error: rgb(219, 84, 97);
|
||||
--color-success: rgb(84, 219, 104);
|
||||
--color-error: #db5461;
|
||||
--color-success: #54db68;
|
||||
|
||||
--header-height: 4.5rem;
|
||||
--nav-width: 4rem;
|
||||
|
||||
@@ -84,6 +84,7 @@
|
||||
}
|
||||
|
||||
.entry {
|
||||
--color: var(--color-gray);
|
||||
width: var(--entry-width);
|
||||
height: 6rem;
|
||||
position: relative;
|
||||
@@ -95,7 +96,7 @@
|
||||
|
||||
border-radius: 4px;
|
||||
padding: .75rem;
|
||||
background-color: var(--color-gray);
|
||||
background-color: var(--color);
|
||||
}
|
||||
|
||||
button.entry.fit {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
const colors = ["#3c3c3c", "#49191e", "#171a42", "#083b06", "#3b3506", "#300e40"];
|
||||
const inputs = {
|
||||
'title': document.getElementById('title-input'),
|
||||
'time': document.getElementById('time-input'),
|
||||
'notification_service': document.getElementById('notification-service-input'),
|
||||
'text': document.getElementById('text-input')
|
||||
'text': document.getElementById('text-input'),
|
||||
'color': document.querySelector('#add .color-list')
|
||||
};
|
||||
|
||||
const type_buttons = {
|
||||
@@ -22,7 +24,11 @@ function addReminder() {
|
||||
'title': inputs.title.value,
|
||||
'time': (new Date(inputs.time.value) / 1000) + (new Date(inputs.time.value).getTimezoneOffset() * 60),
|
||||
'notification_service': inputs.notification_service.value,
|
||||
'text': inputs.text.value
|
||||
'text': inputs.text.value,
|
||||
'color': null
|
||||
};
|
||||
if (!inputs.color.classList.contains('hidden')) {
|
||||
data['color'] = inputs.color.querySelector('button[data-selected="true"]').dataset.color;
|
||||
};
|
||||
if (type_buttons['repeat-button'].dataset.selected === 'true') {
|
||||
data['repeat_quantity'] = type_buttons['repeat-quantity'].value;
|
||||
@@ -69,6 +75,9 @@ function closeAdd() {
|
||||
hideWindow();
|
||||
setTimeout(() => {
|
||||
document.getElementById('template-selection').value = document.querySelector('#template-selection option[selected]').value;
|
||||
if (!inputs.color.classList.contains('hidden')) {
|
||||
toggleColor(inputs.color);
|
||||
};
|
||||
inputs.title.value = '';
|
||||
inputs.time.value = '';
|
||||
inputs.notification_service.value = document.querySelector('#notification-service-input option[selected]').value;
|
||||
@@ -78,6 +87,31 @@ function closeAdd() {
|
||||
}, 500);
|
||||
};
|
||||
|
||||
function loadColor() {
|
||||
document.querySelectorAll('.color-list').forEach(list => {
|
||||
colors.forEach(color => {
|
||||
const entry = document.createElement('button');
|
||||
entry.dataset.color = color;
|
||||
entry.title = color;
|
||||
entry.type = 'button';
|
||||
entry.style.setProperty('--color', color);
|
||||
entry.addEventListener('click', e => selectColor(list, color))
|
||||
list.appendChild(entry);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function selectColor(list, color_code) {
|
||||
list.querySelector(`button[data-color="${color_code}"]`).dataset.selected = 'true';
|
||||
list.querySelectorAll(`button:not([data-color="${color_code}"])`).forEach(b => b.dataset.selected = 'false');
|
||||
return;
|
||||
}
|
||||
|
||||
function toggleColor(list) {
|
||||
selectColor(list, colors[0]);
|
||||
list.classList.toggle('hidden');
|
||||
}
|
||||
|
||||
function toggleNormal() {
|
||||
type_buttons['normal-button'].dataset.selected = 'true';
|
||||
type_buttons['repeat-button'].dataset.selected = 'false';
|
||||
@@ -133,7 +167,10 @@ function testReminder() {
|
||||
|
||||
document.getElementById('add-form').setAttribute('action', 'javascript:addReminder();');
|
||||
document.getElementById('template-selection').addEventListener('change', e => loadTemplate());
|
||||
document.getElementById('color-toggle').addEventListener('click', e => toggleColor(inputs.color));
|
||||
document.getElementById('normal-button').addEventListener('click', e => toggleNormal());
|
||||
document.getElementById('repeat-button').addEventListener('click', e => toggleRepeated());
|
||||
document.getElementById('close-add').addEventListener('click', e => closeAdd());
|
||||
document.getElementById('test-reminder').addEventListener('click', e => testReminder());
|
||||
|
||||
loadColor();
|
||||
|
||||
@@ -2,7 +2,8 @@ const edit_inputs = {
|
||||
'title': document.getElementById('title-edit-input'),
|
||||
'time': document.getElementById('time-edit-input'),
|
||||
'notification_service': document.getElementById('notification-service-edit-input'),
|
||||
'text': document.getElementById('text-edit-input')
|
||||
'text': document.getElementById('text-edit-input'),
|
||||
'color': document.querySelector('#edit .color-list')
|
||||
};
|
||||
|
||||
const edit_type_buttons = {
|
||||
@@ -22,7 +23,11 @@ function editReminder() {
|
||||
'notification_service': edit_inputs.notification_service.value,
|
||||
'text': edit_inputs.text.value,
|
||||
'repeat_quantity': null,
|
||||
'repeat_interval': null
|
||||
'repeat_interval': null,
|
||||
'color': null
|
||||
};
|
||||
if (!edit_inputs.color.classList.contains('hidden')) {
|
||||
data['color'] = edit_inputs.color.querySelector('button[data-selected="true"]').dataset.color;
|
||||
};
|
||||
if (edit_type_buttons['repeat-edit-button'].dataset.selected === 'true') {
|
||||
data['repeat_quantity'] = edit_type_buttons['repeat-edit-quantity'].value;
|
||||
@@ -65,6 +70,13 @@ function showEdit(id) {
|
||||
return response.json();
|
||||
})
|
||||
.then(json => {
|
||||
if (json.result['color'] !== null) {
|
||||
if (edit_inputs.color.classList.contains('hidden')) {
|
||||
toggleColor(edit_inputs.color);
|
||||
};
|
||||
selectColor(edit_inputs.color, json.result['color']);
|
||||
};
|
||||
|
||||
edit_inputs.title.value = json.result.title;
|
||||
|
||||
var trigger_date = new Date(
|
||||
@@ -142,6 +154,7 @@ function deleteReminder() {
|
||||
// code run on load
|
||||
|
||||
document.getElementById('edit-form').setAttribute('action', 'javascript:editReminder();');
|
||||
document.getElementById('color-edit-toggle').addEventListener('click', e => toggleColor(edit_inputs.color));
|
||||
document.getElementById('normal-edit-button').addEventListener('click', e => toggleEditNormal());
|
||||
document.getElementById('repeat-edit-button').addEventListener('click', e => toggleEditRepeated());
|
||||
document.getElementById('close-edit').addEventListener('click', e => hideWindow());
|
||||
|
||||
@@ -7,6 +7,9 @@ function fillTable(result) {
|
||||
entry.classList.add('entry');
|
||||
entry.dataset.id = reminder.id;
|
||||
entry.addEventListener('click', e => showEdit(reminder.id));
|
||||
if (reminder.color !== null) {
|
||||
entry.style.setProperty('--color', reminder.color);
|
||||
};
|
||||
|
||||
const title = document.createElement('h2');
|
||||
title.innerText = reminder.title;
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
const template_inputs = {
|
||||
'title': document.getElementById('title-template-input'),
|
||||
'notification-service': document.getElementById('notification-service-template-input'),
|
||||
'text': document.getElementById('text-template-input')
|
||||
'text': document.getElementById('text-template-input'),
|
||||
'color': document.querySelector('#add-template .color-list')
|
||||
};
|
||||
|
||||
const edit_template_inputs = {
|
||||
'title': document.getElementById('title-template-edit-input'),
|
||||
'notification-service': document.getElementById('notification-service-template-edit-input'),
|
||||
'text': document.getElementById('text-template-edit-input')
|
||||
'text': document.getElementById('text-template-edit-input'),
|
||||
'color': document.querySelector('#edit-template .color-list')
|
||||
};
|
||||
|
||||
function loadTemplates(force=true) {
|
||||
@@ -68,6 +70,9 @@ function loadTemplate() {
|
||||
inputs.title.value = '';
|
||||
inputs.notification_service.value = document.querySelector('#notification-service-input option[selected]').value;
|
||||
inputs.text.value = '';
|
||||
if (!inputs.color.classList.contains('hidden')) {
|
||||
toggleColor(inputs.color);
|
||||
};
|
||||
} else {
|
||||
fetch(`/api/templates/${id}?api_key=${api_key}`)
|
||||
.then(response => {
|
||||
@@ -81,6 +86,16 @@ function loadTemplate() {
|
||||
inputs.title.value = json.result.title;
|
||||
inputs.notification_service.value = json.result.notification_service;
|
||||
inputs.text.value = json.result.text;
|
||||
if (json.result.color !== null) {
|
||||
if (inputs.color.classList.contains('hidden')) {
|
||||
toggleColor(inputs.color);
|
||||
};
|
||||
selectColor(inputs.color, json.result.color);
|
||||
} else {
|
||||
if (!inputs.color.classList.contains('hidden')) {
|
||||
toggleColor(inputs.color);
|
||||
};
|
||||
};
|
||||
})
|
||||
.catch(e => {
|
||||
if (e === 401) {
|
||||
@@ -96,7 +111,11 @@ function addTemplate() {
|
||||
const data = {
|
||||
'title': template_inputs.title.value,
|
||||
'notification_service': template_inputs["notification-service"].value,
|
||||
'text': template_inputs.text.value
|
||||
'text': template_inputs.text.value,
|
||||
'color': null
|
||||
};
|
||||
if (!template_inputs.color.classList.contains('hidden')) {
|
||||
data['color'] = template_inputs.color.querySelector('button[data-selected="true"]').dataset.color;
|
||||
};
|
||||
fetch(`/api/templates?api_key=${api_key}`, {
|
||||
'method': 'POST',
|
||||
@@ -128,6 +147,9 @@ function closeAddTemplate() {
|
||||
template_inputs.title.value = '';
|
||||
template_inputs['notification-service'].value = document.querySelector('#notification-service-template-input option[selected]').value;
|
||||
template_inputs.text.value = '';
|
||||
if (!template_inputs.color.classList.contains('hidden')) {
|
||||
toggleColor(inputs.color);
|
||||
};
|
||||
}, 500);
|
||||
};
|
||||
|
||||
@@ -145,6 +167,12 @@ function showEditTemplate(id) {
|
||||
edit_template_inputs.title.value = json.result.title;
|
||||
edit_template_inputs['notification-service'].value = json.result.notification_service;
|
||||
edit_template_inputs.text.value = json.result.text;
|
||||
if (json.result.color !== null) {
|
||||
if (edit_template_inputs.color.classList.contains('hidden')) {
|
||||
toggleColor(edit_template_inputs.color);
|
||||
};
|
||||
selectColor(edit_template_inputs.color, json.result.color);
|
||||
};
|
||||
showWindow('edit-template');
|
||||
})
|
||||
.catch(e => {
|
||||
@@ -161,7 +189,11 @@ function saveTemplate() {
|
||||
const data = {
|
||||
'title': edit_template_inputs.title.value,
|
||||
'notification_service': edit_template_inputs['notification-service'].value,
|
||||
'text': edit_template_inputs.text.value
|
||||
'text': edit_template_inputs.text.value,
|
||||
'color': null
|
||||
};
|
||||
if (!edit_template_inputs.color.classList.contains('hidden')) {
|
||||
data['color'] = edit_template_inputs.color.querySelector('button[data-selected="true"]').dataset.color;
|
||||
};
|
||||
fetch(`/api/templates/${id}?api_key=${api_key}`, {
|
||||
'method': 'PUT',
|
||||
@@ -211,7 +243,9 @@ function deleteTemplate() {
|
||||
// code run on load
|
||||
|
||||
document.getElementById('template-form').setAttribute('action', 'javascript:addTemplate();');
|
||||
document.getElementById('color-template-toggle').addEventListener('click', e => toggleColor(template_inputs.color));
|
||||
document.getElementById('close-template').addEventListener('click', e => closeAddTemplate());
|
||||
document.getElementById('template-edit-form').setAttribute('action', 'javascript:saveTemplate()');
|
||||
document.getElementById('color-template-edit-toggle').addEventListener('click', e => toggleColor(edit_template_inputs.color));
|
||||
document.getElementById('close-edit-template').addEventListener('click', e => hideWindow());
|
||||
document.getElementById('delete-template').addEventListener('click', e => deleteTemplate());
|
||||
|
||||
@@ -137,9 +137,13 @@
|
||||
<h2>Add a reminder</h2>
|
||||
<div class="form-container">
|
||||
<form id="add-form">
|
||||
<select id="template-selection">
|
||||
<option value="0" selected>No template</option>
|
||||
</select>
|
||||
<div class="sub-inputs">
|
||||
<select id="template-selection">
|
||||
<option value="0" selected>No template</option>
|
||||
</select>
|
||||
<button type="button" id="color-toggle">Color</button>
|
||||
</div>
|
||||
<div class="color-list hidden"></div>
|
||||
<input type="text" id="title-input" placeholder="Title" required>
|
||||
<div class="sub-inputs">
|
||||
<input type="datetime-local" id="time-input" required>
|
||||
@@ -191,6 +195,8 @@
|
||||
<h2>Edit a reminder</h2>
|
||||
<div class="form-container">
|
||||
<form id="edit-form">
|
||||
<button type="button" id="color-edit-toggle">Color</button>
|
||||
<div class="color-list hidden"></div>
|
||||
<input type="text" id="title-edit-input" placeholder="Title" required>
|
||||
<div class="sub-inputs">
|
||||
<input type="datetime-local" id="time-edit-input" required>
|
||||
@@ -302,6 +308,8 @@
|
||||
<h2>Add a template</h2>
|
||||
<div class="form-container">
|
||||
<form id="template-form">
|
||||
<button type="button" id="color-template-toggle">Color</button>
|
||||
<div class="color-list hidden"></div>
|
||||
<input type="text" id="title-template-input" placeholder="Title" required>
|
||||
<select id="notification-service-template-input" required></select>
|
||||
<textarea id="text-template-input" cols="30" rows="10" placeholder="Text (optional)"></textarea>
|
||||
@@ -316,6 +324,8 @@
|
||||
<h2>Edit a template</h2>
|
||||
<div class="form-container">
|
||||
<form id="template-edit-form">
|
||||
<button type="button" id="color-template-edit-toggle">Color</button>
|
||||
<div class="color-list hidden"></div>
|
||||
<input type="text" id="title-template-edit-input" placeholder="Title" required>
|
||||
<select id="notification-service-template-edit-input" required></select>
|
||||
<textarea id="text-template-edit-input" cols="30" rows="10" placeholder="Text (optional)"></textarea>
|
||||
|
||||
Reference in New Issue
Block a user