From 32f74244bdf4656d07e36f6f41e7e5528ab93763 Mon Sep 17 00:00:00 2001 From: Kyle Date: Tue, 1 Oct 2024 14:13:06 -0400 Subject: [PATCH] Add custom favicon --- CHANGELOG.md | 1 + .../5966b3569c89_add_favicon_options.py | 44 +++++++++++++++++++ mycodo/config.py | 10 ++--- mycodo/databases/models/misc.py | 2 + mycodo/mycodo_flask/forms/forms_settings.py | 2 + mycodo/mycodo_flask/routes_static.py | 22 ++++++++++ .../mycodo_flask/templates/create_admin.html | 2 +- .../templates/forgot_password.html | 2 +- .../mycodo_flask/templates/layout-remote.html | 2 +- .../templates/layout_default.html | 2 +- .../mycodo_flask/templates/login_keypad.html | 2 +- .../templates/login_password.html | 2 +- .../templates/reset_password.html | 2 +- .../templates/settings/general.html | 15 +++++++ mycodo/mycodo_flask/utils/utils_settings.py | 3 ++ 15 files changed, 101 insertions(+), 12 deletions(-) create mode 100644 alembic_db/alembic/versions/5966b3569c89_add_favicon_options.py diff --git a/CHANGELOG.md b/CHANGELOG.md index d50ee64a8..eb1eba49a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ### Miscellaneous - Allow deletion of the last remaining Dashboard + - Add custom favicon ## 8.16.0 (2024.09.29) diff --git a/alembic_db/alembic/versions/5966b3569c89_add_favicon_options.py b/alembic_db/alembic/versions/5966b3569c89_add_favicon_options.py new file mode 100644 index 000000000..b276571db --- /dev/null +++ b/alembic_db/alembic/versions/5966b3569c89_add_favicon_options.py @@ -0,0 +1,44 @@ +"""add favicon options + +Revision ID: 5966b3569c89 +Revises: 435f35958689 +Create Date: 2024-10-01 13:39:25.265702 + +""" +import sys +import os + +sys.path.append(os.path.abspath(os.path.join(__file__, "../../../.."))) + +from alembic_db.alembic_post_utils import write_revision_post_alembic + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '5966b3569c89' +down_revision = '435f35958689' +branch_labels = None +depends_on = None + + +def upgrade(): + # write_revision_post_alembic(revision) + + with op.batch_alter_table("misc") as batch_op: + batch_op.add_column(sa.Column('favicon_display', sa.Text)) + batch_op.add_column(sa.Column('brand_favicon', sa.BLOB)) + + op.execute( + ''' + UPDATE misc + SET favicon_display='default' + ''' + ) + + +def downgrade(): + with op.batch_alter_table("misc") as batch_op: + batch_op.drop_column('favicon_display') + batch_op.drop_column('brand_favicon') diff --git a/mycodo/config.py b/mycodo/config.py index eb8a6a5b4..13195cfb3 100644 --- a/mycodo/config.py +++ b/mycodo/config.py @@ -14,7 +14,7 @@ from config_translations import TRANSLATIONS as T MYCODO_VERSION = '8.16.0' -ALEMBIC_VERSION = '435f35958689' +ALEMBIC_VERSION = '5966b3569c89' # FORCE UPGRADE MASTER # Set True to enable upgrading to the master branch of the Mycodo repository. @@ -59,10 +59,10 @@ PATH_TEMPLATE_LAYOUT = os.path.join(PATH_TEMPLATE, 'layout.html') PATH_TEMPLATE_LAYOUT_DEFAULT = os.path.join(PATH_TEMPLATE, 'layout_default.html') PATH_TEMPLATE_USER = os.path.join(PATH_TEMPLATE, 'user_templates') -PATH_CSS = os.path.join(INSTALL_DIRECTORY, 'mycodo/mycodo_flask/static/css') -PATH_CSS_USER = os.path.join(PATH_CSS, 'user_css') -PATH_JS_USER = os.path.join(INSTALL_DIRECTORY, 'mycodo/mycodo_flask/static/js/user_js') -PATH_FONTS_USER = os.path.join(INSTALL_DIRECTORY, 'mycodo/mycodo_flask/static/fonts/user_fonts') +PATH_STATIC = os.path.join(INSTALL_DIRECTORY, 'mycodo/mycodo_flask/static') +PATH_CSS_USER = os.path.join(PATH_STATIC, 'css/user_css') +PATH_JS_USER = os.path.join(PATH_STATIC, 'js/user_js') +PATH_FONTS_USER = os.path.join(PATH_STATIC, 'fonts/user_fonts') PATH_USER_SCRIPTS = os.path.join(INSTALL_DIRECTORY, 'mycodo/user_scripts') PATH_PYTHON_CODE_USER = os.path.join(INSTALL_DIRECTORY, 'mycodo/user_python_code') PATH_MEASUREMENTS_BACKUP = os.path.join(INSTALL_DIRECTORY, 'mycodo/backup_measurements') diff --git a/mycodo/databases/models/misc.py b/mycodo/databases/models/misc.py index 109e764d6..8187d8a8d 100644 --- a/mycodo/databases/models/misc.py +++ b/mycodo/databases/models/misc.py @@ -52,6 +52,8 @@ class Misc(CRUDMixin, db.Model): hostname_override = db.Column(db.String, default='') brand_image = db.Column(db.BLOB, default=b'') brand_image_height = db.Column(db.Integer, default=55) + favicon_display = db.Column(db.String, default='default') + brand_favicon = db.Column(db.BLOB, default=b'') custom_css = db.Column(db.String, default='') custom_layout = db.Column(db.String, default='') diff --git a/mycodo/mycodo_flask/forms/forms_settings.py b/mycodo/mycodo_flask/forms/forms_settings.py index 6d390ef69..1ad64a619 100644 --- a/mycodo/mycodo_flask/forms/forms_settings.py +++ b/mycodo/mycodo_flask/forms/forms_settings.py @@ -98,6 +98,8 @@ class SettingsGeneral(FlaskForm): hostname_override = StringField(lazy_gettext('Brand Text')) brand_image = FileField(lazy_gettext('Brand Image')) brand_image_height = IntegerField(lazy_gettext('Brand Image Height')) + favicon_display = StringField(lazy_gettext('Favicon Display')) + brand_favicon = FileField(lazy_gettext('Favicon Image')) daemon_debug_mode = BooleanField(lazy_gettext('Enable Daemon Debug Logging')) force_https = BooleanField(lazy_gettext('Force HTTPS')) hide_success = BooleanField(lazy_gettext('Hide success messages')) diff --git a/mycodo/mycodo_flask/routes_static.py b/mycodo/mycodo_flask/routes_static.py index b6b08bccd..013c65893 100644 --- a/mycodo/mycodo_flask/routes_static.py +++ b/mycodo/mycodo_flask/routes_static.py @@ -5,14 +5,17 @@ import socket import subprocess import traceback +from io import BytesIO import flask_login from flask import (current_app, redirect, render_template, request, send_from_directory, url_for) +from flask import send_file from flask.blueprints import Blueprint from mycodo.config import (ALEMBIC_VERSION, INSTALL_DIRECTORY, LANGUAGES, MYCODO_VERSION, THEMES, THEMES_DARK) +from mycodo.config import PATH_STATIC from mycodo.config_translations import TRANSLATIONS from mycodo.databases.models import Dashboard, Misc from mycodo.mycodo_client import DaemonControl @@ -86,6 +89,25 @@ def inject_variables(): upgrade_available=misc.mycodo_upgrade_available) +@blueprint.app_errorhandler(404) +def not_found(error): + return render_template('404.html', error=error), 404 + + +@blueprint.route('/favicon.png') +def favicon(): + """Return favicon image""" + misc = Misc.query.first() + + if misc.favicon_display == 'default': + return send_from_directory(os.path.join(PATH_STATIC, 'img'), "favicon.png") + else: + return send_file( + BytesIO(misc.brand_favicon), + mimetype='image/png' + ) + + @blueprint.route('/robots.txt') def static_from_root(): """Return static robots.txt.""" diff --git a/mycodo/mycodo_flask/templates/create_admin.html b/mycodo/mycodo_flask/templates/create_admin.html index 394d925f4..e25264b8b 100644 --- a/mycodo/mycodo_flask/templates/create_admin.html +++ b/mycodo/mycodo_flask/templates/create_admin.html @@ -7,7 +7,7 @@ - + Mycodo - {{_('Create Admin')}} - {{host}} diff --git a/mycodo/mycodo_flask/templates/forgot_password.html b/mycodo/mycodo_flask/templates/forgot_password.html index c28c79754..9b22c2ff4 100644 --- a/mycodo/mycodo_flask/templates/forgot_password.html +++ b/mycodo/mycodo_flask/templates/forgot_password.html @@ -7,7 +7,7 @@ - + Mycodo Reset Password - {{host}} diff --git a/mycodo/mycodo_flask/templates/layout-remote.html b/mycodo/mycodo_flask/templates/layout-remote.html index 76063700b..5e1f1320b 100644 --- a/mycodo/mycodo_flask/templates/layout-remote.html +++ b/mycodo/mycodo_flask/templates/layout-remote.html @@ -7,7 +7,7 @@ - + Mycodo {{mycodo_version}} - {{host}}{% block title %}{% endblock %} diff --git a/mycodo/mycodo_flask/templates/layout_default.html b/mycodo/mycodo_flask/templates/layout_default.html index 87da528e8..c61d0a915 100644 --- a/mycodo/mycodo_flask/templates/layout_default.html +++ b/mycodo/mycodo_flask/templates/layout_default.html @@ -7,7 +7,7 @@ - + diff --git a/mycodo/mycodo_flask/templates/login_keypad.html b/mycodo/mycodo_flask/templates/login_keypad.html index 2f45719f5..795608d04 100644 --- a/mycodo/mycodo_flask/templates/login_keypad.html +++ b/mycodo/mycodo_flask/templates/login_keypad.html @@ -7,7 +7,7 @@ - + {{host}} - Mycodo {{dict_translation['login']['title']}} diff --git a/mycodo/mycodo_flask/templates/login_password.html b/mycodo/mycodo_flask/templates/login_password.html index 910467b2c..556f9d42f 100644 --- a/mycodo/mycodo_flask/templates/login_password.html +++ b/mycodo/mycodo_flask/templates/login_password.html @@ -7,7 +7,7 @@ - + {{host}} - Mycodo {{dict_translation['login']['title']}} diff --git a/mycodo/mycodo_flask/templates/reset_password.html b/mycodo/mycodo_flask/templates/reset_password.html index b5197b0ce..f7349f7ea 100644 --- a/mycodo/mycodo_flask/templates/reset_password.html +++ b/mycodo/mycodo_flask/templates/reset_password.html @@ -7,7 +7,7 @@ - + {{host}} - Mycodo Reset Password diff --git a/mycodo/mycodo_flask/templates/settings/general.html b/mycodo/mycodo_flask/templates/settings/general.html index 79d066cfa..7e43b720b 100644 --- a/mycodo/mycodo_flask/templates/settings/general.html +++ b/mycodo/mycodo_flask/templates/settings/general.html @@ -109,6 +109,21 @@

+
+ {{form_settings_general.favicon_display.label(class_='col-sm-12 control-label')}} +
+ +
+
+
+ {{form_settings_general.brand_favicon.label(class_='col-sm-12 control-label checkbox-nopad')}} +
+ Data Saved: {% if settings.brand_favicon %}True{% else %}False{% endif %} +
+
{{form_settings_general.rpyc_timeout.label(class_='col-sm-12 control-label checkbox-nopad')}}
diff --git a/mycodo/mycodo_flask/utils/utils_settings.py b/mycodo/mycodo_flask/utils/utils_settings.py index 76ac1fd15..faf64444e 100644 --- a/mycodo/mycodo_flask/utils/utils_settings.py +++ b/mycodo/mycodo_flask/utils/utils_settings.py @@ -407,6 +407,9 @@ def settings_general_mod(form): if form.brand_image.data: mod_misc.brand_image = form.brand_image.data.read() mod_misc.brand_image_height = form.brand_image_height.data + mod_misc.favicon_display = form.favicon_display.data + if form.brand_favicon.data: + mod_misc.brand_favicon = form.brand_favicon.data.read() mod_misc.daemon_debug_mode = form.daemon_debug_mode.data mod_misc.hide_alert_success = form.hide_success.data mod_misc.hide_alert_info = form.hide_info.data