diff --git a/requirements.txt b/requirements.txt index ca9833d..ffa8e2c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,6 +13,7 @@ Jinja2==2.11.2 lxml==4.5.2 MarkupSafe==1.1.1 pigpio==1.46 +pygments pyserial==3.4 pytest=6.0.1 PyYAML==5.3.1 diff --git a/src/callattendant.py b/src/callattendant.py index 46ed791..fca8a53 100755 --- a/src/callattendant.py +++ b/src/callattendant.py @@ -282,6 +282,7 @@ def make_config(filename=None): # Load the config file, which may overwrite defaults if filename is not None: cfg.from_pyfile(filename) + cfg["CONFIG_FILE"] = filename # Always print the configuration print_config(cfg) diff --git a/src/userinterface/static/css/pygments.css b/src/userinterface/static/css/pygments.css new file mode 100644 index 0000000..2a4cfcb --- /dev/null +++ b/src/userinterface/static/css/pygments.css @@ -0,0 +1,68 @@ +.hll { background-color: #ffffcc } +.c { color: #408080; font-style: italic } /* Comment */ +.err { border: 1px solid #FF0000 } /* Error */ +.k { color: #008000; font-weight: bold } /* Keyword */ +.o { color: #666666 } /* Operator */ +.ch { color: #408080; font-style: italic } /* Comment.Hashbang */ +.cm { color: #408080; font-style: italic } /* Comment.Multiline */ +.cp { color: #BC7A00 } /* Comment.Preproc */ +.cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */ +.c1 { color: #408080; font-style: italic } /* Comment.Single */ +.cs { color: #408080; font-style: italic } /* Comment.Special */ +.gd { color: #A00000 } /* Generic.Deleted */ +.ge { font-style: italic } /* Generic.Emph */ +.gr { color: #FF0000 } /* Generic.Error */ +.gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.gi { color: #00A000 } /* Generic.Inserted */ +.go { color: #888888 } /* Generic.Output */ +.gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.gs { font-weight: bold } /* Generic.Strong */ +.gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.gt { color: #0044DD } /* Generic.Traceback */ +.kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.kp { color: #008000 } /* Keyword.Pseudo */ +.kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.kt { color: #B00040 } /* Keyword.Type */ +.m { color: #666666 } /* Literal.Number */ +.s { color: #BA2121 } /* Literal.String */ +.na { color: #7D9029 } /* Name.Attribute */ +.nb { color: #008000 } /* Name.Builtin */ +.nc { color: #0000FF; font-weight: bold } /* Name.Class */ +.no { color: #880000 } /* Name.Constant */ +.nd { color: #AA22FF } /* Name.Decorator */ +.ni { color: #999999; font-weight: bold } /* Name.Entity */ +.ne { color: #D2413A; font-weight: bold } /* Name.Exception */ +.nf { color: #0000FF } /* Name.Function */ +.nl { color: #A0A000 } /* Name.Label */ +.nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.nt { color: #008000; font-weight: bold } /* Name.Tag */ +.nv { color: #19177C } /* Name.Variable */ +.ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.w { color: #bbbbbb } /* Text.Whitespace */ +.mb { color: #666666 } /* Literal.Number.Bin */ +.mf { color: #666666 } /* Literal.Number.Float */ +.mh { color: #666666 } /* Literal.Number.Hex */ +.mi { color: #666666 } /* Literal.Number.Integer */ +.mo { color: #666666 } /* Literal.Number.Oct */ +.sa { color: #BA2121 } /* Literal.String.Affix */ +.sb { color: #BA2121 } /* Literal.String.Backtick */ +.sc { color: #BA2121 } /* Literal.String.Char */ +.dl { color: #BA2121 } /* Literal.String.Delimiter */ +.sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.s2 { color: #BA2121 } /* Literal.String.Double */ +.se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ +.sh { color: #BA2121 } /* Literal.String.Heredoc */ +.si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ +.sx { color: #008000 } /* Literal.String.Other */ +.sr { color: #BB6688 } /* Literal.String.Regex */ +.s1 { color: #BA2121 } /* Literal.String.Single */ +.ss { color: #19177C } /* Literal.String.Symbol */ +.bp { color: #008000 } /* Name.Builtin.Pseudo */ +.fm { color: #0000FF } /* Name.Function.Magic */ +.vc { color: #19177C } /* Name.Variable.Class */ +.vg { color: #19177C } /* Name.Variable.Global */ +.vi { color: #19177C } /* Name.Variable.Instance */ +.vm { color: #19177C } /* Name.Variable.Magic */ +.il { color: #666666 } /* Literal.Number.Integer.Long */ diff --git a/src/userinterface/static/gear.svg b/src/userinterface/static/gear.svg new file mode 100644 index 0000000..5414b1d --- /dev/null +++ b/src/userinterface/static/gear.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/userinterface/static/question-circle.svg b/src/userinterface/static/question-circle.svg new file mode 100644 index 0000000..ba10723 --- /dev/null +++ b/src/userinterface/static/question-circle.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/userinterface/templates/base.html b/src/userinterface/templates/base.html index dd9e58c..651aa0c 100644 --- a/src/userinterface/templates/base.html +++ b/src/userinterface/templates/base.html @@ -10,6 +10,8 @@ + {% block stylesheet %} + {% endblock %} diff --git a/src/userinterface/templates/settings.html b/src/userinterface/templates/settings.html new file mode 100644 index 0000000..ecc2f34 --- /dev/null +++ b/src/userinterface/templates/settings.html @@ -0,0 +1,21 @@ +{% extends "base.html" %} + +{% block title %}Settings{% endblock %} + +{% block stylesheet %} + +{% endblock %} + +{% block content %} +
+

Settings

+ +
Current Configuration
+ {{ curr_settings|safe }} + +
Config File: {{ config_file }}
+ {{ file_settings|safe }} + +
+{% endblock %} + diff --git a/src/userinterface/webapp.py b/src/userinterface/webapp.py index bbd171f..d48483c 100644 --- a/src/userinterface/webapp.py +++ b/src/userinterface/webapp.py @@ -37,13 +37,16 @@ import string import _thread from datetime import datetime, timedelta -from pprint import pprint +from pprint import pprint, pformat from glob import glob +import sqlite3 from flask import Flask, request, g, current_app, render_template, redirect, \ jsonify, url_for, flash from flask_paginate import Pagination, get_page_args -import sqlite3 +from pygments import highlight +from pygments.lexers import PythonLexer +from pygments.formatters import HtmlFormatter from screening.query_db import query_db from screening.blacklist import Blacklist @@ -831,6 +834,40 @@ def messages_played(): return jsonify(success=success, msg_no=msg_no, unplayed_count=unplayed_count) +@app.route('/settings', methods=['GET']) +def settings(): + """ + Display the current settings. + + CSS: pygmentize -S colorful -f html > pygments.css + """ + # Get the application-wide config object + config = current_app.config.get("APPLICATION_CONFIG") + + # Read the current config into a str for display + config_contents = pformat(config) + + # Read the config file contents into a buffer for display + file_contents = "" + file_name = config.get("CONFIG_FILE") + if file_name: + file_path = os.path.join(config["ROOT_PATH"], file_name) + with open(file_path, mode="r") as f: + file_contents += f.read() + + # Convert the strings to pretty HTML + curr_settings = highlight(config_contents, PythonLexer(), HtmlFormatter()) + file_settings = highlight(file_contents, PythonLexer(), HtmlFormatter()) + + + return render_template( + "settings.html", + active_nav_item='settings', + config_file=file_name, + curr_settings=curr_settings, + file_settings=file_settings) + + def format_phone_no(number): return'{}-{}-{}'.format(number[0:3], number[3:6], number[6:]) @@ -912,6 +949,8 @@ def run_flask(config): ''' app.secret_key = get_random_string() with app.app_context(): + # Application-wide config dict + app.config["APPLICATION_CONFIG"] = config # Override Flask settings with CallAttendant config settings app.config["DEBUG"] = config["DEBUG"] app.config["TESTING"] = config["TESTING"]