some fixes + type variables

This commit is contained in:
jr-k 2024-02-28 17:38:29 +01:00
parent 691430d541
commit 604ffda4af
15 changed files with 146 additions and 23 deletions

View File

@ -61,6 +61,10 @@
"settings_variable_help_bind": "Application server bind (restart needed)", "settings_variable_help_bind": "Application server bind (restart needed)",
"settings_variable_help_lang": "Server language [fr,en] (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_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_page_title": "System infos",
"sysinfo_panel_button_restart": "Restart", "sysinfo_panel_button_restart": "Restart",

View File

@ -61,6 +61,10 @@
"settings_variable_help_bind": "Hôte d'attache du serveur d'application (redémarrage nécessaire)", "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_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_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_page_title": "Système",
"sysinfo_panel_button_restart": "Redémarrer", "sysinfo_panel_button_restart": "Redémarrer",

View File

@ -5,6 +5,7 @@ import re
import shutil import shutil
import subprocess import subprocess
import sys import sys
import time
from flask import Flask, send_from_directory 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) PlayerController(app, LANGDICT, slide_manager)
SlideshowController(app, LANGDICT, slide_manager) SlideshowController(app, LANGDICT, slide_manager, variable_manager)
SettingsController(app, LANGDICT, variable_manager) SettingsController(app, LANGDICT, variable_manager)
SysinfoController(app, LANGDICT, config) SysinfoController(app, LANGDICT, config, variable_manager)
if vars['fleet_enabled'].as_bool(): if vars['fleet_enabled'].as_bool():
FleetController(app, LANGDICT, screen_manager) FleetController(app, LANGDICT, screen_manager)

View File

@ -19,7 +19,7 @@ class SettingsController:
return render_template( return render_template(
'settings/list.jinja.html', 'settings/list.jinja.html',
l=self._lang_dict, l=self._lang_dict,
variables=self._variable_manager.get_all(), variables=self._variable_manager.get_editable_variables(),
) )
def settings_variable_edit(self): def settings_variable_edit(self):

View File

@ -1,5 +1,6 @@
import json import json
import os import os
import time
from flask import Flask, render_template, redirect, request, url_for, send_from_directory, jsonify from flask import Flask, render_template, redirect, request, url_for, send_from_directory, jsonify
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
@ -10,10 +11,11 @@ from src.utils import str_to_enum
class SlideshowController: class SlideshowController:
def __init__(self, app, lang_dict, slide_manager): def __init__(self, app, lang_dict, slide_manager, variable_manager):
self._app = app self._app = app
self._lang_dict = lang_dict self._lang_dict = lang_dict
self._slide_manager = slide_manager self._slide_manager = slide_manager
self._variable_manager = variable_manager
self.register() self.register()
def register(self): def register(self):
@ -34,6 +36,8 @@ class SlideshowController:
l=self._lang_dict, l=self._lang_dict,
enabled_slides=self._slide_manager.get_enabled_slides(), enabled_slides=self._slide_manager.get_enabled_slides(),
disabled_slides=self._slide_manager.get_disabled_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): def slideshow_slide_add(self):
@ -61,24 +65,33 @@ class SlideshowController:
slide.location = request.form['object'] slide.location = request.form['object']
self._slide_manager.add_form(slide) self._slide_manager.add_form(slide)
self._post_update()
return redirect(url_for('slideshow_slide_list')) return redirect(url_for('slideshow_slide_list'))
def slideshow_slide_edit(self): def slideshow_slide_edit(self):
self._slide_manager.update_form(request.form['id'], request.form['name'], request.form['duration']) self._slide_manager.update_form(request.form['id'], request.form['name'], request.form['duration'])
self._post_update()
return redirect(url_for('slideshow_slide_list')) return redirect(url_for('slideshow_slide_list'))
def slideshow_slide_toggle(self): def slideshow_slide_toggle(self):
data = request.get_json() data = request.get_json()
self._slide_manager.update_enabled(data.get('id'), data.get('enabled')) self._slide_manager.update_enabled(data.get('id'), data.get('enabled'))
self._post_update()
return jsonify({'status': 'ok'}) return jsonify({'status': 'ok'})
def slideshow_slide_delete(self): def slideshow_slide_delete(self):
data = request.get_json() data = request.get_json()
self._slide_manager.delete(data.get('id')) self._slide_manager.delete(data.get('id'))
self._post_update()
return jsonify({'status': 'ok'}) return jsonify({'status': 'ok'})
def slideshow_slide_position(self): def slideshow_slide_position(self):
data = request.get_json() data = request.get_json()
self._slide_manager.update_positions(data) self._slide_manager.update_positions(data)
self._post_update()
return jsonify({'status': 'ok'}) return jsonify({'status': 'ok'})
def _post_update(self):
self._variable_manager.update_by_name("last_slide_update", time.time())

View File

@ -9,15 +9,17 @@ from src.utils import get_ip_address
class SysinfoController: class SysinfoController:
def __init__(self, app, lang_dict, config): def __init__(self, app, lang_dict, config, variable_manager):
self._app = app self._app = app
self._lang_dict = lang_dict self._lang_dict = lang_dict
self._config = config self._config = config
self._variable_manager = variable_manager
self.register() self.register()
def register(self): def register(self):
self._app.add_url_rule('/sysinfo', 'sysinfo_attribute_list', self.sysinfo, methods=['GET']) 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', '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): def sysinfo(self):
ipaddr = get_ip_address() ipaddr = get_ip_address()
@ -25,6 +27,7 @@ class SysinfoController:
'sysinfo/list.jinja.html', 'sysinfo/list.jinja.html',
ipaddr=ipaddr if ipaddr else self._lang_dict['common_unknown_ipaddr'], ipaddr=ipaddr if ipaddr else self._lang_dict['common_unknown_ipaddr'],
l=self._lang_dict, l=self._lang_dict,
ro_variables=self._variable_manager.get_readonly_variables(),
) )
def sysinfo_restart(self): def sysinfo_restart(self):
@ -43,3 +46,12 @@ class SysinfoController:
return jsonify({'status': 'ok'}) 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})

View File

@ -1,7 +1,9 @@
from typing import Dict, Optional, List, Tuple, Union from typing import Dict, Optional, List, Tuple, Union
from src.model.Variable import Variable from src.model.Variable import Variable
from src.model.VariableType import VariableType
from pysondb import PysonDB from pysondb import PysonDB
from pysondb.errors import IdDoesNotExistError from pysondb.errors import IdDoesNotExistError
import time
class VariableManager: class VariableManager:
@ -14,20 +16,27 @@ class VariableManager:
def init(self, lang_dict: Optional[Dict] = None) -> None: def init(self, lang_dict: Optional[Dict] = None) -> None:
default_vars = [ default_vars = [
{"name": "port", "value": 5000, "description": lang_dict['settings_variable_help_port'] 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', "description": lang_dict['settings_variable_help_bind'] 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", "description": lang_dict['settings_variable_help_lang'] 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", "description": lang_dict['settings_variable_help_fleet_enabled'] 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: 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: if not variable:
self.add_form(default_var) self.add_form(default_var)
variable = self.get_one_by_name(default_var['name'])
elif variable.description != default_var['description']: elif variable.description != default_var['description']:
self._db.update_by_id(variable.id, {"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]: def get_variable_map(self) -> Dict[str, Variable]:
var_map = {} var_map = {}
@ -60,6 +69,9 @@ class VariableManager:
def get_by(self, query) -> List[Variable]: def get_by(self, query) -> List[Variable]:
return self.hydrate_dict(self._db.get_by_query(query=query)) 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]: def get_one_by(self, query) -> Optional[Variable]:
variables = self.hydrate_dict(self._db.get_by_query(query=query)) variables = self.hydrate_dict(self._db.get_by_query(query=query))
if len(variables) == 1: if len(variables) == 1:
@ -76,9 +88,18 @@ class VariableManager:
return VariableManager.hydrate_list(raw_variables) 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: def update_form(self, id: str, value: Union[int, bool, str]) -> None:
self._db.update_by_id(id, {"value": value}) 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: def add_form(self, variable: Union[Variable, Dict]) -> None:
db_variable = variable db_variable = variable

View File

@ -1,15 +1,19 @@
import json import json
import time
from typing import Optional, Union from typing import Optional, Union
from src.model.VariableType import VariableType
from src.utils import str_to_enum
class Variable: 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._id = id if id else None
self._name = name self._name = name
self._type = str_to_enum(type, VariableType) if isinstance(type, str) else type
self._description = description self._description = description
self._value = value self._value = value
self._editable = editable
@property @property
def id(self) -> Union[int, str]: def id(self) -> Union[int, str]:
@ -23,6 +27,14 @@ class Variable:
def name(self, value: str): def name(self, value: str):
self._name = value self._name = value
@property
def type(self) -> VariableType:
return self._type
@type.setter
def type(self, value: VariableType):
self._type = value
@property @property
def description(self) -> str: def description(self) -> str:
return self._description return self._description
@ -31,6 +43,14 @@ class Variable:
def description(self, value: str): def description(self, value: str):
self._description = value self._description = value
@property
def editable(self) -> bool:
return self._editable
@editable.setter
def editable(self, value: bool):
self._editable = value
@property @property
def value(self) -> Union[int, bool, str]: def value(self) -> Union[int, bool, str]:
return self._value return self._value
@ -44,7 +64,9 @@ class Variable:
f"id='{self.id}',\n" \ f"id='{self.id}',\n" \
f"name='{self.name}',\n" \ f"name='{self.name}',\n" \
f"value='{self.value}',\n" \ f"value='{self.value}',\n" \
f"type='{self.type}',\n" \
f"description='{self.description}',\n" \ f"description='{self.description}',\n" \
f"editable='{self.editable}',\n" \
f")" f")"
def to_json(self) -> str: def to_json(self) -> str:
@ -55,14 +77,30 @@ class Variable:
"id": self.id, "id": self.id,
"name": self.name, "name": self.name,
"value": self.value, "value": self.value,
"type": self.type.value,
"description": self.description, "description": self.description,
"editable": self.editable,
} }
def as_bool(self): def as_bool(self) -> bool:
return bool(int(self._value)) return bool(int(self._value))
def as_string(self): def as_string(self) -> str:
return str(self._value) return str(self._value)
def as_int(self): def as_int(self) -> int:
return int(self._value) 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()

View File

@ -0,0 +1,9 @@
from enum import Enum
class VariableType(Enum):
BOOL = 'bool'
STRING = 'string'
INT = 'int'
TIMESTAMP = 'timestamp'

View File

@ -64,10 +64,12 @@
{% endblock %} {% endblock %}
</div> </div>
<script> <script>
var l = {'js_slideshow_slide_delete_confirmation': '{{ l.slideshow_slide_delete_confirmation }}'}; var l = {
var l = {'js_fleet_screen_delete_confirmation': '{{ l.js_fleet_screen_delete_confirmation }}'}; 'js_slideshow_slide_delete_confirmation': '{{ l.slideshow_slide_delete_confirmation }}',
var l = {'js_sysinfo_restart_confirmation': '{{ l.js_sysinfo_restart_confirmation }}'}; 'js_fleet_screen_delete_confirmation': '{{ l.js_fleet_screen_delete_confirmation }}',
var l = {'js_sysinfo_restart_loading': '{{ l.js_sysinfo_restart_loading }}'}; 'js_sysinfo_restart_confirmation': '{{ l.js_sysinfo_restart_confirmation }}',
'js_sysinfo_restart_loading': '{{ l.js_sysinfo_restart_loading }}'
};
</script> </script>
<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script> <script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
{% block add_js %}{% endblock %} {% block add_js %}{% endblock %}

View File

@ -34,7 +34,6 @@
items = data; items = data;
}).catch(function(err) { }).catch(function(err) {
console.error(err); console.error(err);
document.location.reload();
}); });
}, playlistCheck); }, playlistCheck);

View File

@ -50,6 +50,10 @@
<a href="{{ slide.location }}" class="item-download slide-download" target="_blank"> <a href="{{ slide.location }}" class="item-download slide-download" target="_blank">
<i class="fa fa-eye"></i> <i class="fa fa-eye"></i>
</a> </a>
{% elif var_external_url.value|length > 0 %}
<a href="{{ var_external_url.value }}/{{ slide.location }}" class="item-download slide-download" target="_blank">
<i class="fa fa-eye"></i>
</a>
{% endif %} {% endif %}
<a href="javascript:void(0);" class="item-delete slide-delete"> <a href="javascript:void(0);" class="item-delete slide-delete">
<i class="fa fa-trash"></i> <i class="fa fa-trash"></i>

View File

@ -8,6 +8,7 @@
{% block add_js %} {% block add_js %}
<script src="{{ STATIC_PREFIX }}js/tablednd-fixed.js"></script> <script src="{{ STATIC_PREFIX }}js/tablednd-fixed.js"></script>
<script src="{{ STATIC_PREFIX }}js/slideshow.js"></script> <script src="{{ STATIC_PREFIX }}js/slideshow.js"></script>
<script src="{{ STATIC_PREFIX }}js/restart.js"></script>
{% endblock %} {% endblock %}
{% block page %} {% block page %}
@ -15,6 +16,10 @@
<h2>{{ l.slideshow_page_title }}</h2> <h2>{{ l.slideshow_page_title }}</h2>
<div class="toolbar-actions"> <div class="toolbar-actions">
{% if fleet_mode %}
<button class="normal sysinfo-restart"><i class="fa fa-refresh icon-left"></i>{{ l.sysinfo_panel_button_restart }}</button>
{% endif %}
<button class="purple slide-add item-add"><i class="fa fa-plus icon-left"></i>{{ l.slideshow_slide_button_add }}</button> <button class="purple slide-add item-add"><i class="fa fa-plus icon-left"></i>{{ l.slideshow_slide_button_add }}</button>
</div> </div>
</div> </div>
@ -37,7 +42,6 @@
</div> </div>
</div> </div>
<div class="modals hidden"> <div class="modals hidden">
<div class="modals-outer"> <div class="modals-outer">
<a href="javascript:void(0);" class="modal-close"> <a href="javascript:void(0);" class="modal-close">

View File

@ -6,7 +6,7 @@
{% endblock %} {% endblock %}
{% block add_js %} {% block add_js %}
<script src="{{ STATIC_PREFIX }}js/sysinfo.js"></script> <script src="{{ STATIC_PREFIX }}js/restart.js"></script>
{% endblock %} {% endblock %}
{% block page %} {% block page %}
@ -31,6 +31,12 @@
<td>{{ l.sysinfo_panel_td_ipaddr }}</td> <td>{{ l.sysinfo_panel_td_ipaddr }}</td>
<td>{{ ipaddr }}</td> <td>{{ ipaddr }}</td>
</tr> </tr>
{% for ro_variable in ro_variables %}
<tr>
<td>{{ ro_variable.description }}</td>
<td>{{ ro_variable.display() }}</td>
</tr>
{% endfor %}
</tbody> </tbody>
</table> </table>
</div> </div>