mirror of
https://github.com/Casvt/MIND.git
synced 2026-02-19 11:54:46 -05:00
22
MIND.py
22
MIND.py
@@ -1,13 +1,15 @@
|
||||
#!/usr/bin/env python3
|
||||
#-*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
from os import makedirs, urandom
|
||||
from os.path import abspath, dirname, join, isfile
|
||||
from os.path import abspath, dirname, isfile, join
|
||||
from shutil import move
|
||||
from sys import version_info
|
||||
|
||||
from flask import Flask, render_template, request
|
||||
from flask import Flask
|
||||
from waitress.server import create_server
|
||||
from werkzeug.middleware.dispatcher import DispatcherMiddleware
|
||||
|
||||
from backend.db import DBConnection, close_db, setup_db
|
||||
from frontend.api import api, reminder_handler
|
||||
@@ -15,6 +17,7 @@ from frontend.ui import ui
|
||||
|
||||
HOST = '0.0.0.0'
|
||||
PORT = '8080'
|
||||
URL_PREFIX = '' # Must start with '/' e.g. '/mind'
|
||||
THREADS = 10
|
||||
DB_FILENAME = 'db', 'MIND.db'
|
||||
|
||||
@@ -39,15 +42,10 @@ def _create_app() -> Flask:
|
||||
app.config['SECRET_KEY'] = urandom(32)
|
||||
app.config['JSONIFY_PRETTYPRINT_REGULAR'] = True
|
||||
app.config['JSON_SORT_KEYS'] = False
|
||||
app.config['APPLICATION_ROOT'] = URL_PREFIX
|
||||
app.wsgi_app = DispatcherMiddleware(Flask(__name__), {URL_PREFIX: app.wsgi_app})
|
||||
|
||||
# Add error handlers
|
||||
@app.errorhandler(404)
|
||||
def not_found(e):
|
||||
if request.path.startswith('/api'):
|
||||
return {'error': 'Not Found', 'result': {}}, 404
|
||||
else:
|
||||
return render_template('page_not_found.html')
|
||||
|
||||
@app.errorhandler(400)
|
||||
def bad_request(e):
|
||||
return {'error': 'Bad request', 'result': {}}, 400
|
||||
@@ -78,6 +76,10 @@ def MIND() -> None:
|
||||
print('Error: the minimum python version required is python3.7 (currently ' + version_info.major + '.' + version_info.minor + '.' + version_info.micro + ')')
|
||||
|
||||
# Register web server
|
||||
# We need to get the value to ui.py but MIND.py imports from ui.py so we get an import loop.
|
||||
# To go around this, we abuse the fact that the logging module is a singleton.
|
||||
# We add an attribute to the logging module and in ui.py get the value this way.
|
||||
logging.URL_PREFIX = URL_PREFIX
|
||||
app = _create_app()
|
||||
with app.app_context():
|
||||
if isfile(_folder_path('db', 'Noted.db')):
|
||||
@@ -93,7 +95,7 @@ def MIND() -> None:
|
||||
|
||||
# Create waitress server and run
|
||||
server = create_server(app, host=HOST, port=PORT, threads=THREADS)
|
||||
print(f'MIND running on http://{HOST}:{PORT}/')
|
||||
print(f'MIND running on http://{HOST}:{PORT}{URL_PREFIX}')
|
||||
server.run()
|
||||
print(f'\nShutting down MIND...')
|
||||
|
||||
|
||||
@@ -120,6 +120,10 @@ def extract_key(values: dict, key: str, check_existence: bool=True) -> Any:
|
||||
|
||||
return value
|
||||
|
||||
@api.errorhandler(404)
|
||||
def not_found(e):
|
||||
return return_api({}, 'Not Found', 404)
|
||||
|
||||
#===================
|
||||
# Authentication endpoints
|
||||
#===================
|
||||
|
||||
@@ -35,7 +35,7 @@ function addReminder() {
|
||||
data['repeat_interval'] = type_buttons['repeat-interval'].value
|
||||
};
|
||||
|
||||
fetch(`/api/reminders?api_key=${api_key}`, {
|
||||
fetch(`${url_prefix}/api/reminders?api_key=${api_key}`, {
|
||||
'method': 'POST',
|
||||
'headers': {'Content-Type': 'application/json'},
|
||||
'body': JSON.stringify(data)
|
||||
@@ -52,7 +52,7 @@ function addReminder() {
|
||||
})
|
||||
.catch(e => {
|
||||
if (e === 401) {
|
||||
window.location.href = '/';
|
||||
window.location.href = url_prefix;
|
||||
} else if (e === 400) {
|
||||
inputs.time.classList.add('error-input');
|
||||
inputs.time.title = 'Time is in the past';
|
||||
@@ -144,7 +144,7 @@ function testReminder() {
|
||||
'notification_service': inputs.notification_service.value,
|
||||
'text': inputs.text.value
|
||||
};
|
||||
fetch(`/api/reminders/test?api_key=${api_key}`, {
|
||||
fetch(`${url_prefix}/api/reminders/test?api_key=${api_key}`, {
|
||||
'method': 'POST',
|
||||
'headers': {'Content-Type': 'application/json'},
|
||||
'body': JSON.stringify(data)
|
||||
@@ -158,7 +158,7 @@ function testReminder() {
|
||||
})
|
||||
.catch(e => {
|
||||
if (e === 401) {
|
||||
window.location.href = '/';
|
||||
window.location.href = url_prefix;
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
@@ -34,7 +34,7 @@ function editReminder() {
|
||||
data['repeat_interval'] = edit_type_buttons['repeat-edit-interval'].value;
|
||||
};
|
||||
|
||||
fetch(`/api/reminders/${id}?api_key=${api_key}`, {
|
||||
fetch(`${url_prefix}/api/reminders/${id}?api_key=${api_key}`, {
|
||||
'method': 'PUT',
|
||||
'headers': {'Content-Type': 'application/json'},
|
||||
'body': JSON.stringify(data)
|
||||
@@ -51,7 +51,7 @@ function editReminder() {
|
||||
})
|
||||
.catch(e => {
|
||||
if (e === 401) {
|
||||
window.location.href = '/';
|
||||
window.location.href = url_prefix;
|
||||
} else {
|
||||
console.log(e);
|
||||
};
|
||||
@@ -60,7 +60,7 @@ function editReminder() {
|
||||
|
||||
function showEdit(id) {
|
||||
document.getElementById('edit-form').dataset.id = id;
|
||||
fetch(`/api/reminders/${id}?api_key=${api_key}`)
|
||||
fetch(`${url_prefix}/api/reminders/${id}?api_key=${api_key}`)
|
||||
.then(response => {
|
||||
// catch errors
|
||||
if (!response.ok) {
|
||||
@@ -99,7 +99,7 @@ function showEdit(id) {
|
||||
})
|
||||
.catch(e => {
|
||||
if (e === 401) {
|
||||
window.location.href = '/';
|
||||
window.location.href = url_prefix;
|
||||
} else if (e === 404) {
|
||||
fillList();
|
||||
} else {
|
||||
@@ -127,7 +127,7 @@ function toggleEditRepeated() {
|
||||
|
||||
function deleteReminder() {
|
||||
const id = document.getElementById('edit-form').dataset.id;
|
||||
fetch(`/api/reminders/${id}?api_key=${api_key}`, {
|
||||
fetch(`${url_prefix}/api/reminders/${id}?api_key=${api_key}`, {
|
||||
'method': 'DELETE'
|
||||
})
|
||||
.then(response => {
|
||||
@@ -142,7 +142,7 @@ function deleteReminder() {
|
||||
})
|
||||
.catch(e => {
|
||||
if (e === 401) {
|
||||
window.location.href = '/';
|
||||
window.location.href = url_prefix;
|
||||
} else if (e === 404) {
|
||||
fillList();
|
||||
} else {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
function logout() {
|
||||
fetch(`/api/auth/logout?api_key=${api_key}`, {
|
||||
fetch(`${url_prefix}/api/auth/logout?api_key=${api_key}`, {
|
||||
'method': 'POST'
|
||||
})
|
||||
.then(response => {
|
||||
sessionStorage.removeItem('api_key');
|
||||
window.location.href = '/';
|
||||
window.location.href = url_prefix;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -49,9 +49,10 @@ function showTab(tab_id, button_id, load_function=null) {
|
||||
|
||||
// code run on load
|
||||
|
||||
const url_prefix = document.getElementById('url_prefix').dataset.value;
|
||||
const api_key = sessionStorage.getItem('api_key');
|
||||
if (api_key === null) {
|
||||
window.location.href = '/';
|
||||
window.location.href = url_prefix;
|
||||
};
|
||||
|
||||
document.getElementById('toggle-nav').addEventListener('click', e => toggleNav());
|
||||
|
||||
@@ -10,7 +10,7 @@ function login(data=null) {
|
||||
'password': document.getElementById('password-input').value
|
||||
};
|
||||
};
|
||||
fetch(`/api/auth/login`, {
|
||||
fetch(`${url_prefix}/api/auth/login`, {
|
||||
'method': 'POST',
|
||||
'headers': {'Content-Type': 'application/json'},
|
||||
'body': JSON.stringify(data)
|
||||
@@ -25,7 +25,7 @@ function login(data=null) {
|
||||
})
|
||||
.then(json => {
|
||||
sessionStorage.setItem('api_key', json.result.api_key);
|
||||
window.location.href = '/reminders';
|
||||
window.location.href = `${url_prefix}/reminders`;
|
||||
})
|
||||
.catch(e => {
|
||||
if (e === 401) {
|
||||
@@ -49,7 +49,7 @@ function create() {
|
||||
'username': document.getElementById('new-username-input').value,
|
||||
'password': document.getElementById('new-password-input').value
|
||||
};
|
||||
fetch(`/api/user/add`, {
|
||||
fetch(`${url_prefix}/api/user/add`, {
|
||||
'method': 'POST',
|
||||
'headers': {'Content-Type': 'application/json'},
|
||||
'body': JSON.stringify(data)
|
||||
@@ -81,6 +81,8 @@ function toggleWindow() {
|
||||
|
||||
// code run on load
|
||||
|
||||
const url_prefix = document.getElementById('url_prefix').dataset.value;
|
||||
|
||||
document.getElementById('login-form').setAttribute('action', 'javascript:login();');
|
||||
document.getElementById('create-form').setAttribute('action', 'javascript:create();');
|
||||
document.querySelectorAll('.switch-button').forEach(e => e.addEventListener('click', e => toggleWindow()));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
function fillNotificationSelection() {
|
||||
fetch(`/api/notificationservices?api_key=${api_key}`)
|
||||
fetch(`${url_prefix}/api/notificationservices?api_key=${api_key}`)
|
||||
.then(response => {
|
||||
// catch errors
|
||||
if (!response.ok) {
|
||||
@@ -87,7 +87,7 @@ function fillNotificationSelection() {
|
||||
})
|
||||
.catch(e => {
|
||||
if (e === 401) {
|
||||
window.location.href = '/';
|
||||
window.location.href = url_prefix;
|
||||
} else {
|
||||
console.log(e);
|
||||
};
|
||||
@@ -96,7 +96,7 @@ function fillNotificationSelection() {
|
||||
|
||||
function deleteService(id) {
|
||||
const row = document.querySelector(`tr[data-id="${id}"]`);
|
||||
fetch(`/api/notificationservices/${id}?api_key=${api_key}`, {
|
||||
fetch(`${url_prefix}/api/notificationservices/${id}?api_key=${api_key}`, {
|
||||
'method': 'DELETE'
|
||||
})
|
||||
.then(response => response.json())
|
||||
@@ -113,7 +113,7 @@ function deleteService(id) {
|
||||
})
|
||||
.catch(e => {
|
||||
if (e.error === 'ApiKeyExpired' || e.error === 'ApiKeyInvalid') {
|
||||
window.location.href = '/';
|
||||
window.location.href = url_prefix;
|
||||
} else if (e.error === 'NotificationServiceInUse') {
|
||||
const delete_button = row.querySelector('button[title="Delete"]');
|
||||
delete_button.classList.add('error-icon');
|
||||
@@ -136,7 +136,7 @@ function saveService(id) {
|
||||
'title': row.querySelector(`td.title-column > input`).value,
|
||||
'url': row.querySelector(`td.url-column > input`).value
|
||||
};
|
||||
fetch(`/api/notificationservices/${id}?api_key=${api_key}`, {
|
||||
fetch(`${url_prefix}/api/notificationservices/${id}?api_key=${api_key}`, {
|
||||
'method': 'PUT',
|
||||
'headers': {'Content-Type': 'application/json'},
|
||||
'body': JSON.stringify(data)
|
||||
@@ -151,7 +151,7 @@ function saveService(id) {
|
||||
})
|
||||
.catch(e => {
|
||||
if (e === 401) {
|
||||
window.location.href = '/';
|
||||
window.location.href = url_prefix;
|
||||
} else if (e === 400) {
|
||||
save_button.classList.add('error-icon');
|
||||
save_button.title = 'Invalid Apprise URL';
|
||||
@@ -176,7 +176,7 @@ function addService() {
|
||||
'title': inputs_buttons.title.value,
|
||||
'url': inputs_buttons.url.value
|
||||
};
|
||||
fetch(`/api/notificationservices?api_key=${api_key}`, {
|
||||
fetch(`${url_prefix}/api/notificationservices?api_key=${api_key}`, {
|
||||
'method': 'POST',
|
||||
'headers': {'Content-Type': 'application/json'},
|
||||
'body': JSON.stringify(data)
|
||||
@@ -199,7 +199,7 @@ function addService() {
|
||||
})
|
||||
.catch(e => {
|
||||
if (e === 401) {
|
||||
window.location.href = '/';
|
||||
window.location.href = url_prefix;
|
||||
} else if (e === 400) {
|
||||
inputs_buttons.save_button.classList.add('error-icon');
|
||||
inputs_buttons.save_button.title = 'Invalid Apprise URL';
|
||||
|
||||
@@ -42,7 +42,7 @@ function fillTable(result) {
|
||||
};
|
||||
|
||||
function fillList() {
|
||||
fetch(`/api/reminders?api_key=${api_key}`)
|
||||
fetch(`${url_prefix}/api/reminders?api_key=${api_key}`)
|
||||
.then(response => {
|
||||
// catch errors
|
||||
if (!response.ok) {
|
||||
@@ -55,7 +55,7 @@ function fillList() {
|
||||
})
|
||||
.catch(e => {
|
||||
if (e === 401) {
|
||||
window.location.href = '/';
|
||||
window.location.href = url_prefix;
|
||||
} else {
|
||||
console.log(e);
|
||||
};
|
||||
@@ -64,7 +64,7 @@ function fillList() {
|
||||
|
||||
function search() {
|
||||
const query = document.getElementById('search-input').value;
|
||||
fetch(`/api/reminders/search?api_key=${api_key}&query=${query}`)
|
||||
fetch(`${url_prefix}/api/reminders/search?api_key=${api_key}&query=${query}`)
|
||||
.then(response => {
|
||||
// catch errors
|
||||
if (!response.ok) {
|
||||
@@ -77,7 +77,7 @@ function search() {
|
||||
})
|
||||
.catch(e => {
|
||||
if (e === 401) {
|
||||
window.location.href = '/';
|
||||
window.location.href = url_prefix;
|
||||
} else {
|
||||
console.log(e);
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ function changePassword() {
|
||||
const data = {
|
||||
'new_password': document.getElementById('password-input').value
|
||||
};
|
||||
fetch(`/api/user?api_key=${api_key}`, {
|
||||
fetch(`${url_prefix}/api/user?api_key=${api_key}`, {
|
||||
'method': 'PUT',
|
||||
'headers': {'Content-Type': 'application/json'},
|
||||
'body': JSON.stringify(data)
|
||||
@@ -16,7 +16,7 @@ function changePassword() {
|
||||
})
|
||||
.catch(e => {
|
||||
if (e === 401) {
|
||||
window.location.href = '/';
|
||||
window.location.href = url_prefix;
|
||||
} else {
|
||||
console.log(e);
|
||||
};
|
||||
@@ -24,11 +24,11 @@ function changePassword() {
|
||||
};
|
||||
|
||||
function deleteAccount() {
|
||||
fetch(`/api/user?api_key=${api_key}`, {
|
||||
fetch(`${url_prefix}/api/user?api_key=${api_key}`, {
|
||||
'method': 'DELETE'
|
||||
})
|
||||
.then(response => {
|
||||
window.location.href = '/';
|
||||
window.location.href = url_prefix;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ function loadTemplates(force=true) {
|
||||
return
|
||||
};
|
||||
|
||||
fetch(`/api/templates?api_key=${api_key}`)
|
||||
fetch(`${url_prefix}/api/templates?api_key=${api_key}`)
|
||||
.then(response => {
|
||||
// catch errors
|
||||
if (!response.ok) {
|
||||
@@ -57,7 +57,7 @@ function loadTemplates(force=true) {
|
||||
})
|
||||
.catch(e => {
|
||||
if (e === 401) {
|
||||
window.location.href = '/';
|
||||
window.location.href = url_prefix;
|
||||
} else {
|
||||
console.log(e);
|
||||
};
|
||||
@@ -74,7 +74,7 @@ function loadTemplate() {
|
||||
toggleColor(inputs.color);
|
||||
};
|
||||
} else {
|
||||
fetch(`/api/templates/${id}?api_key=${api_key}`)
|
||||
fetch(`${url_prefix}/api/templates/${id}?api_key=${api_key}`)
|
||||
.then(response => {
|
||||
// catch errors
|
||||
if (!response.ok) {
|
||||
@@ -99,7 +99,7 @@ function loadTemplate() {
|
||||
})
|
||||
.catch(e => {
|
||||
if (e === 401) {
|
||||
window.location.href = '/';
|
||||
window.location.href = url_prefix;
|
||||
} else {
|
||||
console.log(e);
|
||||
};
|
||||
@@ -117,7 +117,7 @@ function addTemplate() {
|
||||
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}`, {
|
||||
fetch(`${url_prefix}/api/templates?api_key=${api_key}`, {
|
||||
'method': 'POST',
|
||||
'headers': {'Content-Type': 'application/json'},
|
||||
'body': JSON.stringify(data)
|
||||
@@ -134,7 +134,7 @@ function addTemplate() {
|
||||
})
|
||||
.catch(e => {
|
||||
if (e === 401) {
|
||||
window.location.href = '/';
|
||||
window.location.href = url_prefix;
|
||||
} else {
|
||||
console.log(e);
|
||||
};
|
||||
@@ -154,7 +154,7 @@ function closeAddTemplate() {
|
||||
};
|
||||
|
||||
function showEditTemplate(id) {
|
||||
fetch(`/api/templates/${id}?api_key=${api_key}`)
|
||||
fetch(`${url_prefix}/api/templates/${id}?api_key=${api_key}`)
|
||||
.then(response => {
|
||||
// catch errors
|
||||
if (!response.ok) {
|
||||
@@ -177,7 +177,7 @@ function showEditTemplate(id) {
|
||||
})
|
||||
.catch(e => {
|
||||
if (e === 401) {
|
||||
window.location.href = '/';
|
||||
window.location.href = url_prefix;
|
||||
} else {
|
||||
console.log(e);
|
||||
};
|
||||
@@ -195,7 +195,7 @@ function saveTemplate() {
|
||||
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}`, {
|
||||
fetch(`${url_prefix}/api/templates/${id}?api_key=${api_key}`, {
|
||||
'method': 'PUT',
|
||||
'headers': {'Content-Type': 'application/json'},
|
||||
'body': JSON.stringify(data)
|
||||
@@ -210,7 +210,7 @@ function saveTemplate() {
|
||||
})
|
||||
.catch(e => {
|
||||
if (e === 401) {
|
||||
window.location.href = '/';
|
||||
window.location.href = url_prefix;
|
||||
} else {
|
||||
console.log(e);
|
||||
};
|
||||
@@ -219,7 +219,7 @@ function saveTemplate() {
|
||||
|
||||
function deleteTemplate() {
|
||||
const id = document.getElementById('template-edit-form').dataset.id;
|
||||
fetch(`/api/templates/${id}?api_key=${api_key}`, {
|
||||
fetch(`${url_prefix}/api/templates/${id}?api_key=${api_key}`, {
|
||||
'method': 'DELETE'
|
||||
})
|
||||
.then(response => {
|
||||
@@ -233,7 +233,7 @@ function deleteTemplate() {
|
||||
})
|
||||
.catch(e => {
|
||||
if (e === 401) {
|
||||
window.location.href = '/';
|
||||
window.location.href = url_prefix;
|
||||
} else {
|
||||
console.log(e);
|
||||
};
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta id="url_prefix" data-value="{{url_prefix}}">
|
||||
|
||||
<link rel="stylesheet" href="/static/css/general.css">
|
||||
<link rel="stylesheet" href="/static/css/login.css">
|
||||
<script src="/static/js/login.js" defer></script>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/general.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/login.css') }}">
|
||||
<script src="{{ url_for('static', filename='js/login.js') }}" defer></script>
|
||||
|
||||
<title>Login - MIND</title>
|
||||
</head>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<main>
|
||||
<h2>MIND</h1>
|
||||
<p>404 - Page not found :(</p>
|
||||
<a href="/">Go to home page</a>
|
||||
<a href="{{url_prefix}}">Go to home page</a>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -4,19 +4,20 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta id="url_prefix" data-value="{{url_prefix}}">
|
||||
|
||||
<link rel="stylesheet" href="/static/css/general.css">
|
||||
<link rel="stylesheet" href="/static/css/reminders_templates.css">
|
||||
<link rel="stylesheet" href="/static/css/add_edit.css">
|
||||
<link rel="stylesheet" href="/static/css/notification.css">
|
||||
<link rel="stylesheet" href="/static/css/settings.css">
|
||||
<script src="/static/js/general.js" defer></script>
|
||||
<script src="/static/js/reminders.js" defer></script>
|
||||
<script src="/static/js/add.js" defer></script>
|
||||
<script src="/static/js/edit.js" defer></script>
|
||||
<script src="/static/js/notification.js" defer></script>
|
||||
<script src="/static/js/settings.js" defer></script>
|
||||
<script src="/static/js/templates.js" defer></script>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/general.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/reminders_templates.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/add_edit.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/notification.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/settings.css') }}">
|
||||
<script src="{{ url_for('static', filename='js/general.js') }}" defer></script>
|
||||
<script src="{{ url_for('static', filename='js/reminders.js') }}" defer></script>
|
||||
<script src="{{ url_for('static', filename='js/add.js') }}" defer></script>
|
||||
<script src="{{ url_for('static', filename='js/edit.js') }}" defer></script>
|
||||
<script src="{{ url_for('static', filename='js/notification.js') }}" defer></script>
|
||||
<script src="{{ url_for('static', filename='js/settings.js') }}" defer></script>
|
||||
<script src="{{ url_for('static', filename='js/templates.js') }}" defer></script>
|
||||
|
||||
<title>Reminders - MIND</title>
|
||||
</head>
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
#-*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
from flask import Blueprint, render_template
|
||||
|
||||
ui = Blueprint('ui', __name__)
|
||||
|
||||
methods = ['GET']
|
||||
|
||||
@ui.errorhandler(404)
|
||||
def not_found(e):
|
||||
return render_template('page_not_found.html', url_prefix=logging.URL_PREFIX)
|
||||
|
||||
@ui.route('/', methods=methods)
|
||||
def ui_login():
|
||||
return render_template('login.html')
|
||||
return render_template('login.html', url_prefix=logging.URL_PREFIX)
|
||||
|
||||
@ui.route('/reminders', methods=methods)
|
||||
def ui_reminders():
|
||||
return render_template('reminders.html')
|
||||
return render_template('reminders.html', url_prefix=logging.URL_PREFIX)
|
||||
|
||||
@@ -15,6 +15,6 @@ class Test_MIND(unittest.TestCase):
|
||||
self.assertEqual(result.blueprints.get('api'), api)
|
||||
|
||||
handlers = result.error_handler_spec[None].keys()
|
||||
required_handlers = 404, 400, 405, 500
|
||||
required_handlers = 400, 405, 500
|
||||
for handler in required_handlers:
|
||||
self.assertIn(handler, handlers)
|
||||
Reference in New Issue
Block a user