Skip to content

Commit 7740d91

Browse files
Pre-release
1 parent 0d9e6d5 commit 7740d91

30 files changed

+791
-378
lines changed

nutcase/app/app/__init__.py

+23-65
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,15 @@
11
import logging
2-
from logging.handlers import SMTPHandler, RotatingFileHandler
2+
# from logging.handlers import SMTPHandler, RotatingFileHandler
33
import os
44
from flask import Flask
55
from config import Config_Development # , Config_Production, Config
6-
# from flask_moment import Moment # https://momentjs.com/
76

8-
from app.api import webhook
9-
from app.api import configuration
7+
from app.utils import webhook
8+
from app.utils import configuration
9+
from app.utils import app_log_config
1010

1111
#=================================================
1212
# Initialise components
13-
#
14-
# moment = Moment()
15-
16-
#==================================================================================================
17-
# Add_Level function
18-
#==================================================================================================
19-
def Add_Logging_Levels():
20-
DEBUGV_LEVEL_NUM = 9
21-
DEBUGVV_LEVEL_NUM = 8
22-
23-
logging.addLevelName(DEBUGV_LEVEL_NUM, "DEBUGV")
24-
logging.addLevelName(DEBUGVV_LEVEL_NUM, "DEBUGVV")
25-
26-
def debugv(self, message, *args, **kws):
27-
if self.isEnabledFor(DEBUGV_LEVEL_NUM):
28-
self._log(DEBUGV_LEVEL_NUM, message, args, **kws)
29-
30-
def debugvv(self, message, *args, **kws):
31-
if self.isEnabledFor(DEBUGVV_LEVEL_NUM):
32-
self._log(DEBUGVV_LEVEL_NUM, message, args, **kws)
33-
34-
logging.Logger.debugv = debugv
35-
logging.Logger.debugvv = debugvv
36-
return
3713

3814
#==================================================================================================
3915
# Main app creation function
@@ -43,7 +19,7 @@ def create_app(config_class=Config_Development):
4319
app.config.from_object(config_class)
4420

4521
#====================================================================================
46-
# Define the app Blueprints
22+
# Register the app Blueprints
4723
#====================================================================================
4824
from app.main import bp as main_bp
4925
app.register_blueprint(main_bp)
@@ -55,47 +31,27 @@ def create_app(config_class=Config_Development):
5531
app.register_blueprint(events_bp, url_prefix='/events')
5632

5733
#====================================================================================
58-
# Set up email for the application log
34+
# Set up the application logging
5935
#====================================================================================
60-
# if not app.debug and not app.testing:
61-
# if app.config['MAIL_SERVER']:
62-
# auth = None
63-
# if app.config['MAIL_USERNAME'] or app.config['MAIL_PASSWORD']:
64-
# auth = (app.config['MAIL_USERNAME'],
65-
# app.config['MAIL_PASSWORD'])
66-
# secure = None
67-
# if app.config['MAIL_USE_TLS']:
68-
# secure = ()
69-
# mail_handler = SMTPHandler(
70-
# mailhost=(app.config['MAIL_SERVER'], app.config['MAIL_PORT']),
71-
# fromaddr='no-reply@' + app.config['MAIL_SERVER'],
72-
# toaddrs=app.config['MAIL_DEFAULT_SENDER'], subject=app.config['MAIL_DEFAULT_SUBJECT'] + " " + 'App Failure',
73-
# credentials=auth, secure=secure)
74-
# mail_handler.setLevel(logging.ERROR)
75-
# app.logger.addHandler(mail_handler)
36+
app_log_config.Add_Logging_Levels()
7637

77-
#====================================================================================
78-
# Set up the application log file
79-
#====================================================================================
80-
Logfile_Directory = os.path.join(app.root_path, app.config['LOGFILE_RELATIVE_PATH'])
38+
Logfile_Directory = os.path.join(app.config['CONFIG_PATH'], app.config['LOGFILE_SUBPATH'])
8139
if not os.path.exists(Logfile_Directory):
8240
os.mkdir(Logfile_Directory)
83-
Logfile_Fullname = os.path.join(Logfile_Directory, 'nutcase.log')
8441

85-
Logfile_Handler = RotatingFileHandler(Logfile_Fullname, maxBytes=250000, backupCount=10)
86-
Log_Format = '%(asctime)s %(levelname)-8s %(module)s: %(message)s'
87-
Logfile_Handler.setFormatter(logging.Formatter(Log_Format))
88-
Logfile_Handler.name = "logfile_handler"
89-
app.logger.addHandler(Logfile_Handler)
90-
91-
Add_Logging_Levels()
42+
app_log_config.Add_RF_Handler( app )
9243

9344
#====================================================================================
9445
# Set the logging level from the environment variable LOG_LEVEL if present.
9546
#====================================================================================
96-
try: app.logger.setLevel( os.environ.get('LOG_LEVEL', "DEBUG").upper() )
97-
except Exception: app.logger.setLevel( logging.DEBUG )
98-
47+
Console_Level = os.environ.get('LOG_LEVEL', app.config['DEFAULT_CONSOLE_LEVEL']).upper()
48+
Logfile_Level = os.environ.get('LOG_LEVEL', app.config['DEFAULT_LOGFILE_LEVEL']).upper()
49+
50+
app.logger.info("Init: Console_Level {} Logfile_Level {}".format( Console_Level, Logfile_Level ))
51+
app_log_config.Set_Log_Level( app, Console_Level, "con" )
52+
app_log_config.Set_Log_Level( app, Logfile_Level, "rfh" )
53+
app.logger.setLevel( 1 ) # Set the root logger to pass everything on
54+
9955
#====================================================================================
10056
# Load the app configuration from a YAML file
10157
#====================================================================================
@@ -104,10 +60,12 @@ def create_app(config_class=Config_Development):
10460
#====================================================================================
10561
# Log starting and call a web hook
10662
#====================================================================================
107-
app.logger.info("{} starting. Version {}, Logging level {}".format(
108-
app.config['APP_NAME'], app.config['APP_VERSION'],
109-
logging.getLevelName(app.logger.level)).lower() )
110-
63+
app.logger.info("{} starting. Version {}, Logging: console {} logfile {}".format(
64+
app.config['APP_NAME'], app.config['APP_VERSION'],
65+
logging.getLevelName( app_log_config.Get_Handler( app, 'con' ).level),
66+
logging.getLevelName( app_log_config.Get_Handler( app, 'rfh' ).level),
67+
))
68+
11169
webhook.Call_Webhook( app, "ok", { "status": "up", "msg": "NUTCase starting" } )
11270

11371
return app

nutcase/app/app/api/routes.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
from app.api import bp
44

5-
from app.api import scrape
6-
from app.api import gui_data_format
5+
from app.utils import scrape
6+
from app.utils import gui_data_format
77

88
#====================================================================================
99
# Serve the end-point /api/status

nutcase/app/app/main/routes.py

+24-12
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@
99
import os
1010
import datetime;
1111

12-
from app.api import server_constants
13-
from app.api import format_to_text
14-
from app.api import format_to_json
15-
from app.api import apc_server_handler
16-
from app.api import configuration
17-
from app.api import scrape
18-
from app.api import file_utils
12+
from app.utils import server_constants
13+
from app.utils import format_to_text
14+
from app.utils import format_to_json
15+
from app.utils import apc_server_handler
16+
from app.utils import configuration
17+
from app.utils import scrape
18+
from app.utils import file_utils
19+
from app.utils import gui_data_format
1920

2021
#=======================================================================
2122
# before_app_request - Run before every request to check config file
@@ -39,9 +40,13 @@ def route_index():
3940
# title = 'Get URL failed',
4041
# body = 'Return code '
4142
# ))
43+
# TODO - reduce logging levels
44+
for a in request.args:
45+
current_app.logger.debug("request.args: key {} value {}".format( a, request.args[a] ))
4246

4347
Addr = request.args.get("addr", default='default')
4448
Device = request.args.get("dev", default='default')
49+
current_app.logger.debug("route_index: Addr {} Device {}".format( Addr, Device ))
4550

4651
if ('target_device' not in session) or (session['target_device'] != Addr + Device):
4752
Length = current_app.config['CHART_SAMPLES']
@@ -146,7 +151,11 @@ def route_metrics():
146151
#====================================================================================
147152
@bp.route('/log')
148153
@bp.route('/log/<Filename>')
149-
def route_log(Filename='nutcase.log'):
154+
def route_log(Filename=''):
155+
if Filename == '':
156+
Filename = current_app.config['LOGFILE_NAME']
157+
158+
# Get the number of lines requested
150159
Log_Lines = current_app.config["DEFAULT_LOG_LINES"]
151160
if Lines := request.args.get("lines"):
152161
try:
@@ -155,15 +164,18 @@ def route_log(Filename='nutcase.log'):
155164
except:
156165
current_app.logger.error("Error defining log lines: {}".format( Lines ))
157166

158-
Logfile_Dir = os.path.join(current_app.root_path, current_app.config['LOGFILE_RELATIVE_PATH'])
159-
Logfile_Fullname = os.path.join(Logfile_Dir, Filename )
160-
File_List = os.listdir(Logfile_Dir)
167+
# Generate the HTML for the list of files
168+
Logfile_Directory = os.path.join(current_app.config['CONFIG_PATH'], current_app.config['LOGFILE_SUBPATH'])
169+
Logfile_Fullname = os.path.join(Logfile_Directory, Filename )
170+
171+
File_List = gui_data_format.Generate_Log_Files_Pulldown( Logfile_Directory )
161172

173+
# Get lines from the requested log file
162174
rtn, Lines = file_utils.Tail_File( Logfile_Fullname, Log_Lines )
163175
if not rtn:
164176
Lines = [ "<pre>Log file not found</pre>" ]
165177

166-
return render_template('main/log.html', title="Log file", lines=Lines, files=File_List, filename=Filename )
178+
return render_template('main/log.html', title="Log file", lines=Lines, files=Markup(File_List), filename=Filename )
167179

168180
#====================================================================================
169181
# Serve the end-point /help

nutcase/app/app/templates/bootstrap/bs5_base_top_navbar.html

+19-15
Original file line numberDiff line numberDiff line change
@@ -34,52 +34,52 @@
3434
<aside id="id-nav-bar">
3535
<nav class="navbar navbar-expand-md bg-body-tertiary">
3636
<a class="navbar-brand px-3" href="https://github.com/ArthurMitchell42/nutcase"><img src="/static/favicon.ico" style="width:22px;height:22px;"> {{ config['APP_NAME'] }} <span class="fs-6 text-muted">- V{{ config['APP_VERSION'] }} {% if config['CONFIG_SET'] != 'Prd' %} {{ config['CONFIG_SET'] }} {% endif %}</span></a>
37-
<!-- <div id="ph_debug">debug</div> -->
37+
<div id="ph_debug">debug</div>
3838
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
3939
<span class="navbar-toggler-icon"></span>
4040
</button>
4141
<div class="collapse navbar-collapse justify-content-end" id="navbarNavDropdown">
4242
<ul class="navbar-nav">
43-
<li class="nav-item">
43+
<li class="nav-item" data-bs-toggle="tooltip_navbar" data-bs-placement="bottom" data-bs-html="true" data-bs-title="<small>Click for warning</small>">
4444
<a class="nav-link d-none" data-bs-toggle="modal" data-bs-target="#warningModal" role="button" id="icon-navbar-warning"><i class="bi bi-exclamation-triangle-fill text-warning"></i></a>
4545
</li>
4646
<li class="nav-item dropdown">
4747
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
48-
<i class="bi bi-pc-display-horizontal"></i>
48+
<i class="bi bi-pc-display-horizontal" data-bs-toggle="tooltip_navbar" data-bs-placement="top" data-bs-html="true" data-bs-title="<small>List of your devices</small>"></i>
4949
</a>
5050
<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink" id="ph-device-menu">
5151
<a class="dropdown-item" href="https://github.com/ArthurMitchell42/nutcase/wiki/The-Configuration-File#3-the-servers-section">None configured</a>
5252
</div>
5353
</li>
5454
<li class="nav-item dropdown">
5555
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownDownload" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
56-
<i class="bi bi-download"></i>
56+
<i class="bi bi-download" data-bs-toggle="tooltip_navbar" data-bs-placement="top" data-bs-html="true" data-bs-title="<small>View/download data</small>"></i>
5757
</a>
5858
<div class="dropdown-menu" aria-labelledby="navbarDropdownDownload" id="ph-download-menu">
59-
<a class="dropdown-item" href="https://github.com/ArthurMitchell42/nutcase/wiki/The-Configuration-File#3-the-servers-section">------</a>
59+
<a class="dropdown-item" href="/">Please go to<br>the home page</a>
6060
</div>
6161
</li>
6262
<li class="nav-item border-start border-secondary-subtle">
63-
<a class="nav-link" href="{{ url_for('main.route_index') }}"><i class="bi bi-house-fill"></i></a>
63+
<a class="nav-link" href="{{ url_for('main.route_index') }}" data-bs-toggle="tooltip_navbar" data-bs-placement="bottom" data-bs-html="true" data-bs-title="<small>Home GUI</small>"><i class="bi bi-house-fill"></i></a>
6464
</li>
6565
<li class="nav-item">
66-
<a class="nav-link" href="{{ url_for('main.route_log') }}"><i class="bi bi-clipboard2-pulse-fill"></i></a>
66+
<a class="nav-link" href="{{ url_for('main.route_log') }}" data-bs-toggle="tooltip_navbar" data-bs-placement="bottom" data-bs-html="true" data-bs-title="<small>Log files</small>"><i class="bi bi-clipboard2-pulse-fill"></i></a>
6767
</li>
68-
<li class="nav-item">
68+
<li class="nav-item" data-bs-toggle="tooltip_navbar" data-bs-placement="bottom" data-bs-html="true" data-bs-title="<small>Details</small>">
6969
<a class="nav-link" data-bs-toggle="collapse" href="#info-data" role="button"><i class="bi bi-info-circle-fill"></i></a>
7070
</li>
7171
<li class="nav-item">
72-
<a class="nav-link" href="https://github.com/ArthurMitchell42/nutcase/wiki"><i class="bi bi-github"></i></a>
72+
<a class="nav-link" href="https://github.com/ArthurMitchell42/nutcase/wiki" data-bs-toggle="tooltip_navbar" data-bs-placement="bottom" data-bs-html="true" data-bs-title="<small>Manual (GitHub)</small>"><i class="bi bi-github"></i></a>
7373
</li>
74-
<li class="nav-item">
74+
<li class="nav-item" data-bs-toggle="tooltip_navbar" data-bs-placement="bottom" data-bs-html="true" data-bs-title="<small>Usage help</small>">
7575
<a class="nav-link" href="{{ url_for('main.route_help') }}"><i class="bi bi-book"></i></a>
7676
</li>
77-
<li class="nav-item border-end border-secondary-subtle">
77+
<li class="nav-item border-end border-secondary-subtle" data-bs-toggle="tooltip_navbar" data-bs-placement="bottom" data-bs-html="true" data-bs-title="<small>Page help</small>">
7878
<a class="nav-link" data-bs-toggle="modal" data-bs-target="#helpModal" role="button"><i class="bi bi-question-circle-fill"></i></a>
7979
</li>
8080

8181

82-
<li class="nav-item ps-1">
82+
<li class="nav-item ps-1" data-bs-toggle="tooltip_navbar" data-bs-placement="bottom" data-bs-html="true" data-bs-title="<small>Events</small>">
8383
<a href="{{ url_for('events.route_events_log') }}" style="text-decoration: none;">
8484
<span class="nav-link">
8585
<i class="bi bi-info-circle position-relative header-icons">
@@ -94,7 +94,7 @@
9494
</span>
9595
</a>
9696
</li>
97-
<li class="nav-item">
97+
<li class="nav-item" data-bs-toggle="tooltip_navbar" data-bs-placement="bottom" data-bs-html="true" data-bs-title="<small>Events</small>">
9898
<a href="{{ url_for('events.route_events_log') }}" style="text-decoration: none;">
9999
<span class="nav-link">
100100
<i class="bi bi-exclamation-triangle position-relative header-icons">
@@ -109,7 +109,7 @@
109109
</span>
110110
</a>
111111
</li>
112-
<li class="nav-item">
112+
<li class="nav-item" data-bs-toggle="tooltip_navbar" data-bs-placement="bottom" data-bs-html="true" data-bs-title="<small>Events</small>">
113113
<a href="{{ url_for('events.route_events_log') }}" style="text-decoration: none;">
114114
<span class="nav-link">
115115
<i class="bi bi-bell position-relative header-icons">
@@ -125,7 +125,6 @@
125125
</a>
126126
</li>
127127

128-
129128
<li class="nav-item ms-2 border-start border-secondary-subtle"">
130129
<!-- Theme icon -->
131130
<div class="dropdown me-2 bd-mode-toggle" style="padding-top: 0.5rem;">
@@ -212,6 +211,11 @@
212211
// });
213212
})
214213

214+
//======================================
215+
// Enable all tool tips
216+
const tooltipTriggerList_navbar = document.querySelectorAll('[data-bs-toggle="tooltip_navbar"]')
217+
const tooltipList_navbar = [...tooltipTriggerList_navbar].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))
218+
215219
</script>
216220

217221
{% block script %}{% endblock %}

nutcase/app/app/templates/events/events_log.html

+41
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,47 @@
4242

4343
</div>
4444

45+
<!--============================================ Help Modal ============================================-->
46+
<div class="modal fade" id="helpModal" tabindex="-1" aria-labelledby="helpLabel" aria-hidden="true">
47+
<div class="modal-dialog">
48+
<div class="modal-content">
49+
<div class="modal-header">
50+
<img src="/static/favicon.ico" alt="NUTCase" style="width:64px;height:64px;">
51+
<h5 class="modal-title" id="helpLabel">NUTCase Events Help</h5>
52+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
53+
</div>
54+
<div class="modal-body">
55+
This feature is not implemented yet<br>
56+
</div>
57+
<div class="modal-body">
58+
<div class="d-flex flex-column m-1">
59+
<div class="d-flex">
60+
<div class="d-flex flex-column flex-fill">
61+
<a href="https://www.paypal.com/donate?hosted_button_id=N6F4E9YCD5VC8" style="text-decoration: none;">
62+
<i class="bi bi-paypal fs-3"></i> Like this app? <br>Then why not buy me a coffee?
63+
</a>
64+
</div>
65+
<div class="d-flex flex-column flex-fill align-items-end">
66+
<a href="https://www.paypal.com/donate?hosted_button_id=N6F4E9YCD5VC8" style="text-decoration: none;">
67+
<img src="/static/images/paypal_donate.jpg" class="rounded float-end"
68+
width="100" height="100" alt="Like the app? Then why not buy me a coffee.">
69+
</a>
70+
</div>
71+
</div>
72+
</div>
73+
</div>
74+
<div class="modal-body">
75+
Credits:<br>
76+
<a href="https://www.flaticon.com/free-icons/oaknut" title="oaknut icons">Oaknut icon by Dreamcreateicons</a><br>
77+
<a href="https://icons.getbootstrap.com/" title="Bootstrap">Bootstrap & Icons</a>
78+
</div>
79+
<div class="modal-footer">
80+
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
81+
</div>
82+
</div>
83+
</div>
84+
</div>
85+
4586
</main>
4687
{% endblock %}
4788

0 commit comments

Comments
 (0)