Skip to content

Commit

Permalink
Pre-release
Browse files Browse the repository at this point in the history
  • Loading branch information
ArthurMitchell42 committed Feb 3, 2024
1 parent 0d9e6d5 commit 7740d91
Show file tree
Hide file tree
Showing 30 changed files with 791 additions and 378 deletions.
88 changes: 23 additions & 65 deletions nutcase/app/app/__init__.py
Original file line number Diff line number Diff line change
@@ -1,39 +1,15 @@
import logging
from logging.handlers import SMTPHandler, RotatingFileHandler
# from logging.handlers import SMTPHandler, RotatingFileHandler
import os
from flask import Flask
from config import Config_Development # , Config_Production, Config
# from flask_moment import Moment # https://momentjs.com/

from app.api import webhook
from app.api import configuration
from app.utils import webhook
from app.utils import configuration
from app.utils import app_log_config

#=================================================
# Initialise components
#
# moment = Moment()

#==================================================================================================
# Add_Level function
#==================================================================================================
def Add_Logging_Levels():
DEBUGV_LEVEL_NUM = 9
DEBUGVV_LEVEL_NUM = 8

logging.addLevelName(DEBUGV_LEVEL_NUM, "DEBUGV")
logging.addLevelName(DEBUGVV_LEVEL_NUM, "DEBUGVV")

def debugv(self, message, *args, **kws):
if self.isEnabledFor(DEBUGV_LEVEL_NUM):
self._log(DEBUGV_LEVEL_NUM, message, args, **kws)

def debugvv(self, message, *args, **kws):
if self.isEnabledFor(DEBUGVV_LEVEL_NUM):
self._log(DEBUGVV_LEVEL_NUM, message, args, **kws)

logging.Logger.debugv = debugv
logging.Logger.debugvv = debugvv
return

#==================================================================================================
# Main app creation function
Expand All @@ -43,7 +19,7 @@ def create_app(config_class=Config_Development):
app.config.from_object(config_class)

#====================================================================================
# Define the app Blueprints
# Register the app Blueprints
#====================================================================================
from app.main import bp as main_bp
app.register_blueprint(main_bp)
Expand All @@ -55,47 +31,27 @@ def create_app(config_class=Config_Development):
app.register_blueprint(events_bp, url_prefix='/events')

#====================================================================================
# Set up email for the application log
# Set up the application logging
#====================================================================================
# if not app.debug and not app.testing:
# if app.config['MAIL_SERVER']:
# auth = None
# if app.config['MAIL_USERNAME'] or app.config['MAIL_PASSWORD']:
# auth = (app.config['MAIL_USERNAME'],
# app.config['MAIL_PASSWORD'])
# secure = None
# if app.config['MAIL_USE_TLS']:
# secure = ()
# mail_handler = SMTPHandler(
# mailhost=(app.config['MAIL_SERVER'], app.config['MAIL_PORT']),
# fromaddr='no-reply@' + app.config['MAIL_SERVER'],
# toaddrs=app.config['MAIL_DEFAULT_SENDER'], subject=app.config['MAIL_DEFAULT_SUBJECT'] + " " + 'App Failure',
# credentials=auth, secure=secure)
# mail_handler.setLevel(logging.ERROR)
# app.logger.addHandler(mail_handler)
app_log_config.Add_Logging_Levels()

#====================================================================================
# Set up the application log file
#====================================================================================
Logfile_Directory = os.path.join(app.root_path, app.config['LOGFILE_RELATIVE_PATH'])
Logfile_Directory = os.path.join(app.config['CONFIG_PATH'], app.config['LOGFILE_SUBPATH'])
if not os.path.exists(Logfile_Directory):
os.mkdir(Logfile_Directory)
Logfile_Fullname = os.path.join(Logfile_Directory, 'nutcase.log')

Logfile_Handler = RotatingFileHandler(Logfile_Fullname, maxBytes=250000, backupCount=10)
Log_Format = '%(asctime)s %(levelname)-8s %(module)s: %(message)s'
Logfile_Handler.setFormatter(logging.Formatter(Log_Format))
Logfile_Handler.name = "logfile_handler"
app.logger.addHandler(Logfile_Handler)

Add_Logging_Levels()
app_log_config.Add_RF_Handler( app )

#====================================================================================
# Set the logging level from the environment variable LOG_LEVEL if present.
#====================================================================================
try: app.logger.setLevel( os.environ.get('LOG_LEVEL', "DEBUG").upper() )
except Exception: app.logger.setLevel( logging.DEBUG )

Console_Level = os.environ.get('LOG_LEVEL', app.config['DEFAULT_CONSOLE_LEVEL']).upper()
Logfile_Level = os.environ.get('LOG_LEVEL', app.config['DEFAULT_LOGFILE_LEVEL']).upper()

app.logger.info("Init: Console_Level {} Logfile_Level {}".format( Console_Level, Logfile_Level ))
app_log_config.Set_Log_Level( app, Console_Level, "con" )
app_log_config.Set_Log_Level( app, Logfile_Level, "rfh" )
app.logger.setLevel( 1 ) # Set the root logger to pass everything on

#====================================================================================
# Load the app configuration from a YAML file
#====================================================================================
Expand All @@ -104,10 +60,12 @@ def create_app(config_class=Config_Development):
#====================================================================================
# Log starting and call a web hook
#====================================================================================
app.logger.info("{} starting. Version {}, Logging level {}".format(
app.config['APP_NAME'], app.config['APP_VERSION'],
logging.getLevelName(app.logger.level)).lower() )

app.logger.info("{} starting. Version {}, Logging: console {} logfile {}".format(
app.config['APP_NAME'], app.config['APP_VERSION'],
logging.getLevelName( app_log_config.Get_Handler( app, 'con' ).level),
logging.getLevelName( app_log_config.Get_Handler( app, 'rfh' ).level),
))

webhook.Call_Webhook( app, "ok", { "status": "up", "msg": "NUTCase starting" } )

return app
Expand Down
4 changes: 2 additions & 2 deletions nutcase/app/app/api/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

from app.api import bp

from app.api import scrape
from app.api import gui_data_format
from app.utils import scrape
from app.utils import gui_data_format

#====================================================================================
# Serve the end-point /api/status
Expand Down
36 changes: 24 additions & 12 deletions nutcase/app/app/main/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@
import os
import datetime;

from app.api import server_constants
from app.api import format_to_text
from app.api import format_to_json
from app.api import apc_server_handler
from app.api import configuration
from app.api import scrape
from app.api import file_utils
from app.utils import server_constants
from app.utils import format_to_text
from app.utils import format_to_json
from app.utils import apc_server_handler
from app.utils import configuration
from app.utils import scrape
from app.utils import file_utils
from app.utils import gui_data_format

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

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

if ('target_device' not in session) or (session['target_device'] != Addr + Device):
Length = current_app.config['CHART_SAMPLES']
Expand Down Expand Up @@ -146,7 +151,11 @@ def route_metrics():
#====================================================================================
@bp.route('/log')
@bp.route('/log/<Filename>')
def route_log(Filename='nutcase.log'):
def route_log(Filename=''):
if Filename == '':
Filename = current_app.config['LOGFILE_NAME']

# Get the number of lines requested
Log_Lines = current_app.config["DEFAULT_LOG_LINES"]
if Lines := request.args.get("lines"):
try:
Expand All @@ -155,15 +164,18 @@ def route_log(Filename='nutcase.log'):
except:
current_app.logger.error("Error defining log lines: {}".format( Lines ))

Logfile_Dir = os.path.join(current_app.root_path, current_app.config['LOGFILE_RELATIVE_PATH'])
Logfile_Fullname = os.path.join(Logfile_Dir, Filename )
File_List = os.listdir(Logfile_Dir)
# Generate the HTML for the list of files
Logfile_Directory = os.path.join(current_app.config['CONFIG_PATH'], current_app.config['LOGFILE_SUBPATH'])
Logfile_Fullname = os.path.join(Logfile_Directory, Filename )

File_List = gui_data_format.Generate_Log_Files_Pulldown( Logfile_Directory )

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

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

#====================================================================================
# Serve the end-point /help
Expand Down
34 changes: 19 additions & 15 deletions nutcase/app/app/templates/bootstrap/bs5_base_top_navbar.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,52 +34,52 @@
<aside id="id-nav-bar">
<nav class="navbar navbar-expand-md bg-body-tertiary">
<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>
<!-- <div id="ph_debug">debug</div> -->
<div id="ph_debug">debug</div>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse justify-content-end" id="navbarNavDropdown">
<ul class="navbar-nav">
<li class="nav-item">
<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>">
<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>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="bi bi-pc-display-horizontal"></i>
<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>
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink" id="ph-device-menu">
<a class="dropdown-item" href="https://github.com/ArthurMitchell42/nutcase/wiki/The-Configuration-File#3-the-servers-section">None configured</a>
</div>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownDownload" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="bi bi-download"></i>
<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>
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdownDownload" id="ph-download-menu">
<a class="dropdown-item" href="https://github.com/ArthurMitchell42/nutcase/wiki/The-Configuration-File#3-the-servers-section">------</a>
<a class="dropdown-item" href="/">Please go to<br>the home page</a>
</div>
</li>
<li class="nav-item border-start border-secondary-subtle">
<a class="nav-link" href="{{ url_for('main.route_index') }}"><i class="bi bi-house-fill"></i></a>
<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>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('main.route_log') }}"><i class="bi bi-clipboard2-pulse-fill"></i></a>
<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>
</li>
<li class="nav-item">
<li class="nav-item" data-bs-toggle="tooltip_navbar" data-bs-placement="bottom" data-bs-html="true" data-bs-title="<small>Details</small>">
<a class="nav-link" data-bs-toggle="collapse" href="#info-data" role="button"><i class="bi bi-info-circle-fill"></i></a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://github.com/ArthurMitchell42/nutcase/wiki"><i class="bi bi-github"></i></a>
<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>
</li>
<li class="nav-item">
<li class="nav-item" data-bs-toggle="tooltip_navbar" data-bs-placement="bottom" data-bs-html="true" data-bs-title="<small>Usage help</small>">
<a class="nav-link" href="{{ url_for('main.route_help') }}"><i class="bi bi-book"></i></a>
</li>
<li class="nav-item border-end border-secondary-subtle">
<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>">
<a class="nav-link" data-bs-toggle="modal" data-bs-target="#helpModal" role="button"><i class="bi bi-question-circle-fill"></i></a>
</li>


<li class="nav-item ps-1">
<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>">
<a href="{{ url_for('events.route_events_log') }}" style="text-decoration: none;">
<span class="nav-link">
<i class="bi bi-info-circle position-relative header-icons">
Expand All @@ -94,7 +94,7 @@
</span>
</a>
</li>
<li class="nav-item">
<li class="nav-item" data-bs-toggle="tooltip_navbar" data-bs-placement="bottom" data-bs-html="true" data-bs-title="<small>Events</small>">
<a href="{{ url_for('events.route_events_log') }}" style="text-decoration: none;">
<span class="nav-link">
<i class="bi bi-exclamation-triangle position-relative header-icons">
Expand All @@ -109,7 +109,7 @@
</span>
</a>
</li>
<li class="nav-item">
<li class="nav-item" data-bs-toggle="tooltip_navbar" data-bs-placement="bottom" data-bs-html="true" data-bs-title="<small>Events</small>">
<a href="{{ url_for('events.route_events_log') }}" style="text-decoration: none;">
<span class="nav-link">
<i class="bi bi-bell position-relative header-icons">
Expand All @@ -125,7 +125,6 @@
</a>
</li>


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

//======================================
// Enable all tool tips
const tooltipTriggerList_navbar = document.querySelectorAll('[data-bs-toggle="tooltip_navbar"]')
const tooltipList_navbar = [...tooltipTriggerList_navbar].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))

</script>

{% block script %}{% endblock %}
Expand Down
41 changes: 41 additions & 0 deletions nutcase/app/app/templates/events/events_log.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,47 @@

</div>

<!--============================================ Help Modal ============================================-->
<div class="modal fade" id="helpModal" tabindex="-1" aria-labelledby="helpLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<img src="/static/favicon.ico" alt="NUTCase" style="width:64px;height:64px;">
<h5 class="modal-title" id="helpLabel">NUTCase Events Help</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
This feature is not implemented yet<br>
</div>
<div class="modal-body">
<div class="d-flex flex-column m-1">
<div class="d-flex">
<div class="d-flex flex-column flex-fill">
<a href="https://www.paypal.com/donate?hosted_button_id=N6F4E9YCD5VC8" style="text-decoration: none;">
<i class="bi bi-paypal fs-3"></i> Like this app? <br>Then why not buy me a coffee?
</a>
</div>
<div class="d-flex flex-column flex-fill align-items-end">
<a href="https://www.paypal.com/donate?hosted_button_id=N6F4E9YCD5VC8" style="text-decoration: none;">
<img src="/static/images/paypal_donate.jpg" class="rounded float-end"
width="100" height="100" alt="Like the app? Then why not buy me a coffee.">
</a>
</div>
</div>
</div>
</div>
<div class="modal-body">
Credits:<br>
<a href="https://www.flaticon.com/free-icons/oaknut" title="oaknut icons">Oaknut icon by Dreamcreateicons</a><br>
<a href="https://icons.getbootstrap.com/" title="Bootstrap">Bootstrap & Icons</a>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>

</main>
{% endblock %}

Expand Down
Loading

0 comments on commit 7740d91

Please sign in to comment.