diff --git a/data/www/js/sysinfo.js b/data/www/js/restart.js similarity index 100% rename from data/www/js/sysinfo.js rename to data/www/js/restart.js diff --git a/lang/en.json b/lang/en.json index 2fe9ea7..7eeae81 100644 --- a/lang/en.json +++ b/lang/en.json @@ -61,6 +61,10 @@ "settings_variable_help_bind": "Application server bind (restart needed)", "settings_variable_help_lang": "Server language [fr,en] (restart needed)", "settings_variable_help_fleet_enabled": "Enable fleet screen management view (restart needed)", + "settings_variable_help_external_url": "External url (i.e: https://screen-01.company.com or http://10.10.3.100)", + + "settings_variable_help_ro_editable": "Last application reboot datetime", + "settings_variable_help_ro_last_slide_update": "Last slide update datetime", "sysinfo_page_title": "System infos", "sysinfo_panel_button_restart": "Restart", diff --git a/lang/fr.json b/lang/fr.json index 3576281..6501062 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -61,6 +61,10 @@ "settings_variable_help_bind": "Hôte d'attache du serveur d'application (redémarrage nécessaire)", "settings_variable_help_lang": "Langage de l'application [fr,en] (redémarrage nécessaire)", "settings_variable_help_fleet_enabled": "Activer la gestion de flotte des écrans (redémarrage nécessaire)", + "settings_variable_help_external_url": "URL externe (i.e: https://screen-01.company.com or http://10.10.3.100)", + + "settings_variable_help_ro_editable": "Date de dernier redémarrage de l'application", + "settings_variable_help_ro_last_slide_update": "Date de dernière modification d'une slide", "sysinfo_page_title": "Système", "sysinfo_panel_button_restart": "Redémarrer", diff --git a/obscreen.py b/obscreen.py index dcfc808..f890f1d 100755 --- a/obscreen.py +++ b/obscreen.py @@ -5,6 +5,7 @@ import re import shutil import subprocess import sys +import time from flask import Flask, send_from_directory @@ -87,10 +88,16 @@ def inject_global_vars(): ) +@app.template_filter('ctime') +def time_ctime(s): + return time.ctime(s) + + + PlayerController(app, LANGDICT, slide_manager) -SlideshowController(app, LANGDICT, slide_manager) +SlideshowController(app, LANGDICT, slide_manager, variable_manager) SettingsController(app, LANGDICT, variable_manager) -SysinfoController(app, LANGDICT, config) +SysinfoController(app, LANGDICT, config, variable_manager) if vars['fleet_enabled'].as_bool(): FleetController(app, LANGDICT, screen_manager) diff --git a/src/controller/SettingsController.py b/src/controller/SettingsController.py index 7b18304..b07d790 100644 --- a/src/controller/SettingsController.py +++ b/src/controller/SettingsController.py @@ -19,7 +19,7 @@ class SettingsController: return render_template( 'settings/list.jinja.html', l=self._lang_dict, - variables=self._variable_manager.get_all(), + variables=self._variable_manager.get_editable_variables(), ) def settings_variable_edit(self): diff --git a/src/controller/SlideshowController.py b/src/controller/SlideshowController.py index 0a53728..5f8698e 100644 --- a/src/controller/SlideshowController.py +++ b/src/controller/SlideshowController.py @@ -1,5 +1,6 @@ import json import os +import time from flask import Flask, render_template, redirect, request, url_for, send_from_directory, jsonify from werkzeug.utils import secure_filename @@ -10,10 +11,11 @@ from src.utils import str_to_enum class SlideshowController: - def __init__(self, app, lang_dict, slide_manager): + def __init__(self, app, lang_dict, slide_manager, variable_manager): self._app = app self._lang_dict = lang_dict self._slide_manager = slide_manager + self._variable_manager = variable_manager self.register() def register(self): @@ -34,6 +36,8 @@ class SlideshowController: l=self._lang_dict, enabled_slides=self._slide_manager.get_enabled_slides(), disabled_slides=self._slide_manager.get_disabled_slides(), + var_last_restart=self._variable_manager.get_one_by_name('last_restart'), + var_external_url=self._variable_manager.get_one_by_name('external_url') ) def slideshow_slide_add(self): @@ -61,24 +65,33 @@ class SlideshowController: slide.location = request.form['object'] self._slide_manager.add_form(slide) + self._post_update() return redirect(url_for('slideshow_slide_list')) def slideshow_slide_edit(self): self._slide_manager.update_form(request.form['id'], request.form['name'], request.form['duration']) + self._post_update() return redirect(url_for('slideshow_slide_list')) def slideshow_slide_toggle(self): data = request.get_json() self._slide_manager.update_enabled(data.get('id'), data.get('enabled')) + self._post_update() return jsonify({'status': 'ok'}) def slideshow_slide_delete(self): data = request.get_json() self._slide_manager.delete(data.get('id')) + self._post_update() return jsonify({'status': 'ok'}) def slideshow_slide_position(self): data = request.get_json() self._slide_manager.update_positions(data) + self._post_update() return jsonify({'status': 'ok'}) + + def _post_update(self): + self._variable_manager.update_by_name("last_slide_update", time.time()) + diff --git a/src/controller/SysinfoController.py b/src/controller/SysinfoController.py index 489ca78..2842b42 100644 --- a/src/controller/SysinfoController.py +++ b/src/controller/SysinfoController.py @@ -9,15 +9,17 @@ from src.utils import get_ip_address class SysinfoController: - def __init__(self, app, lang_dict, config): + def __init__(self, app, lang_dict, config, variable_manager): self._app = app self._lang_dict = lang_dict self._config = config + self._variable_manager = variable_manager self.register() def register(self): self._app.add_url_rule('/sysinfo', 'sysinfo_attribute_list', self.sysinfo, methods=['GET']) self._app.add_url_rule('/sysinfo/restart', 'sysinfo_restart', self.sysinfo_restart, methods=['POST']) + self._app.add_url_rule('/sysinfo/restart/needed', 'sysinfo_restart_needed', self.sysinfo_restart_needed, methods=['GET']) def sysinfo(self): ipaddr = get_ip_address() @@ -25,6 +27,7 @@ class SysinfoController: 'sysinfo/list.jinja.html', ipaddr=ipaddr if ipaddr else self._lang_dict['common_unknown_ipaddr'], l=self._lang_dict, + ro_variables=self._variable_manager.get_readonly_variables(), ) def sysinfo_restart(self): @@ -43,3 +46,12 @@ class SysinfoController: return jsonify({'status': 'ok'}) + def sysinfo_restart_needed(self): + var_last_slide_update = self._variable_manager.get_one_by_name('last_slide_update') + var_last_restart = self._variable_manager.get_one_by_name('last_restart') + + if var_last_slide_update.value <= var_last_restart.value: + return jsonify({'status': False}) + + return jsonify({'status': True}) + diff --git a/src/manager/VariableManager.py b/src/manager/VariableManager.py index f45bfde..9c860bd 100644 --- a/src/manager/VariableManager.py +++ b/src/manager/VariableManager.py @@ -1,7 +1,9 @@ from typing import Dict, Optional, List, Tuple, Union from src.model.Variable import Variable +from src.model.VariableType import VariableType from pysondb import PysonDB from pysondb.errors import IdDoesNotExistError +import time class VariableManager: @@ -14,20 +16,27 @@ class VariableManager: def init(self, lang_dict: Optional[Dict] = None) -> None: default_vars = [ - {"name": "port", "value": 5000, "description": lang_dict['settings_variable_help_port'] if lang_dict else ""}, - {"name": "bind", "value": '0.0.0.0', "description": lang_dict['settings_variable_help_bind'] if lang_dict else ""}, - {"name": "lang", "value": "en", "description": lang_dict['settings_variable_help_lang'] if lang_dict else ""}, - {"name": "fleet_enabled", "value": "0", "description": lang_dict['settings_variable_help_fleet_enabled'] if lang_dict else ""}, + {"name": "port", "value": 5000, "type": VariableType.INT.value, "editable": True, "description": lang_dict['settings_variable_help_port'] if lang_dict else ""}, + {"name": "bind", "value": '0.0.0.0', "type": VariableType.STRING.value, "editable": True, "description": lang_dict['settings_variable_help_bind'] if lang_dict else ""}, + {"name": "lang", "value": "en", "type": VariableType.STRING.value, "editable": True, "description": lang_dict['settings_variable_help_lang'] if lang_dict else ""}, + {"name": "fleet_enabled", "value": "0", "type": VariableType.BOOL.value, "editable": True, "description": lang_dict['settings_variable_help_fleet_enabled'] if lang_dict else ""}, + {"name": "external_url", "value": "", "type": VariableType.STRING.value, "editable": True, "description": lang_dict['settings_variable_help_external_url'] if lang_dict else ""}, + {"name": "last_restart", "value": time.time(), "type": VariableType.TIMESTAMP.value, "editable": False, "description": lang_dict['settings_variable_help_ro_editable'] if lang_dict else ""}, + {"name": "last_slide_update", "value": time.time(), "type": VariableType.TIMESTAMP.value, "editable": False, "description": lang_dict['settings_variable_help_ro_last_slide_update'] if lang_dict else ""}, ] for default_var in default_vars: - variable = self.get_one_by(query=lambda v: v['name'] == default_var['name']) + variable = self.get_one_by_name(default_var['name']) if not variable: self.add_form(default_var) + variable = self.get_one_by_name(default_var['name']) elif variable.description != default_var['description']: self._db.update_by_id(variable.id, {"description": default_var['description']}) + if variable.name == 'last_restart': + self._db.update_by_id(variable.id, {"value": time.time()}) + def get_variable_map(self) -> Dict[str, Variable]: var_map = {} @@ -60,6 +69,9 @@ class VariableManager: def get_by(self, query) -> List[Variable]: return self.hydrate_dict(self._db.get_by_query(query=query)) + def get_one_by_name(self, name: str) -> Optional[Variable]: + return self.get_one_by(query=lambda v: v['name'] == name) + def get_one_by(self, query) -> Optional[Variable]: variables = self.hydrate_dict(self._db.get_by_query(query=query)) if len(variables) == 1: @@ -76,9 +88,18 @@ class VariableManager: return VariableManager.hydrate_list(raw_variables) + def get_editable_variables(self) -> List[Variable]: + return [variable for variable in self.get_all() if variable.editable] + + def get_readonly_variables(self) -> List[Variable]: + return [variable for variable in self.get_all() if not variable.editable] + def update_form(self, id: str, value: Union[int, bool, str]) -> None: self._db.update_by_id(id, {"value": value}) + def update_by_name(self, name: str, value) -> Optional[Variable]: + return self._db.update_by_query(query=lambda v: v['name'] == name, new_data={"value": value}) + def add_form(self, variable: Union[Variable, Dict]) -> None: db_variable = variable diff --git a/src/model/Variable.py b/src/model/Variable.py index e477578..b92f251 100644 --- a/src/model/Variable.py +++ b/src/model/Variable.py @@ -1,15 +1,19 @@ import json +import time from typing import Optional, Union - +from src.model.VariableType import VariableType +from src.utils import str_to_enum class Variable: - def __init__(self, name: str = '', description: str = '', value: Union[int, bool, str] = '', id: Optional[str] = None): + def __init__(self, name: str = '', description: str = '', type: Union[VariableType, str] = VariableType.STRING, value: Union[int, bool, str] = '', editable: bool = True, id: Optional[str] = None): self._id = id if id else None self._name = name + self._type = str_to_enum(type, VariableType) if isinstance(type, str) else type self._description = description self._value = value + self._editable = editable @property def id(self) -> Union[int, str]: @@ -23,6 +27,14 @@ class Variable: def name(self, value: str): self._name = value + @property + def type(self) -> VariableType: + return self._type + + @type.setter + def type(self, value: VariableType): + self._type = value + @property def description(self) -> str: return self._description @@ -31,6 +43,14 @@ class Variable: def description(self, value: str): self._description = value + @property + def editable(self) -> bool: + return self._editable + + @editable.setter + def editable(self, value: bool): + self._editable = value + @property def value(self) -> Union[int, bool, str]: return self._value @@ -44,7 +64,9 @@ class Variable: f"id='{self.id}',\n" \ f"name='{self.name}',\n" \ f"value='{self.value}',\n" \ + f"type='{self.type}',\n" \ f"description='{self.description}',\n" \ + f"editable='{self.editable}',\n" \ f")" def to_json(self) -> str: @@ -55,14 +77,30 @@ class Variable: "id": self.id, "name": self.name, "value": self.value, + "type": self.type.value, "description": self.description, + "editable": self.editable, } - def as_bool(self): + def as_bool(self) -> bool: return bool(int(self._value)) - def as_string(self): + def as_string(self) -> str: return str(self._value) - def as_int(self): - return int(self._value) \ No newline at end of file + def as_int(self) -> int: + return int(self._value) + + def as_ctime(self): + return time.ctime(self._value) + + def display(self): + if self.type == VariableType.INT: + return self.as_int() + elif self.type == VariableType.BOOL: + return self.as_bool() + elif self.type == VariableType.TIMESTAMP: + return self.as_ctime() + + return self.as_string() + diff --git a/src/model/VariableType.py b/src/model/VariableType.py new file mode 100644 index 0000000..da7b6e4 --- /dev/null +++ b/src/model/VariableType.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class VariableType(Enum): + + BOOL = 'bool' + STRING = 'string' + INT = 'int' + TIMESTAMP = 'timestamp' diff --git a/views/base.jinja.html b/views/base.jinja.html index c74f4ee..ae43f9d 100755 --- a/views/base.jinja.html +++ b/views/base.jinja.html @@ -64,10 +64,12 @@ {% endblock %} {% block add_js %}{% endblock %} diff --git a/views/player/player.jinja.html b/views/player/player.jinja.html index 9c0b114..a6b5017 100755 --- a/views/player/player.jinja.html +++ b/views/player/player.jinja.html @@ -34,7 +34,6 @@ items = data; }).catch(function(err) { console.error(err); - document.location.reload(); }); }, playlistCheck); diff --git a/views/slideshow/component/table.jinja.html b/views/slideshow/component/table.jinja.html index 2a9c6ca..dd38f76 100644 --- a/views/slideshow/component/table.jinja.html +++ b/views/slideshow/component/table.jinja.html @@ -50,6 +50,10 @@ + {% elif var_external_url.value|length > 0 %} + + + {% endif %} diff --git a/views/slideshow/list.jinja.html b/views/slideshow/list.jinja.html index fda5929..202d813 100644 --- a/views/slideshow/list.jinja.html +++ b/views/slideshow/list.jinja.html @@ -8,6 +8,7 @@ {% block add_js %} + {% endblock %} {% block page %} @@ -15,6 +16,10 @@

{{ l.slideshow_page_title }}

+ {% if fleet_mode %} + + {% endif %} +
@@ -37,7 +42,6 @@ -