bump 2.2.0

This commit is contained in:
jr-k 2024-07-30 18:13:00 +02:00
parent 20dcb3659a
commit 143f6b5b44
19 changed files with 153 additions and 71 deletions

3
.gitignore vendored
View File

@ -19,4 +19,5 @@ var/run/*
.env
venv/
node_modules
tmp.py
tmp.py
!/plugins/user/Dashboard/*

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

0
data/www/plugins/.gitkeep Executable file
View File

View File

@ -0,0 +1,3 @@
.inner h3 {
color: red !important;
}

View File

@ -115,9 +115,24 @@ main {
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
padding: 0 10px 40px 10px;
padding: 10px 10px 40px 10px;
background: $layoutBackground;
align-self: stretch;
h1, h2, h3, h4, h5, h6 {
color: $gscaleD;
}
p {
font-size: 12px;
line-height: 18px;
display: flex;
margin-bottom: 5px;
flex-direction: row;
justify-content: flex-start;
align-items: center;
color: $gscale6;
}
}
}

View File

@ -1,4 +1,3 @@
class WebDirConstant:
FOLDER_TEMPLATES = "views"
@ -6,6 +5,6 @@ class WebDirConstant:
FOLDER_STATIC_WEB_UPLOADS = "uploads"
FOLDER_STATIC_WEB_ASSETS = "www"
FOLDER_PLUGIN_HOOK = "hook"
FOLDER_PLUGIN_STATIC_SRC = "static"
FOLDER_PLUGIN_STATIC_DST = "plugins"
FOLDER_CONTROLLER = "controller"

View File

@ -11,7 +11,7 @@ class CoreController(ObController):
self._app.add_url_rule('/favicon.ico', 'favicon', self.favicon, methods=['GET'])
def manifest(self):
with open("{}/manifest.jinja.json".format(self.get_template_folder()), 'r') as file:
with open("{}/manifest.jinja.json".format(self.get_template_dir()), 'r') as file:
template_content = file.read()
rendered_content = render_template_string(template_content)
@ -19,4 +19,4 @@ class CoreController(ObController):
return self._app.response_class(rendered_content, mimetype='application/json')
def favicon(self):
return send_file("{}/favicon.ico".format(self.get_web_folder()), mimetype='image/x-icon')
return send_file("{}/favicon.ico".format(self.get_web_dir()), mimetype='image/x-icon')

View File

@ -28,11 +28,11 @@ class ObController(abc.ABC):
return self._plugin
def get_template_folder(self):
return self._web_server.get_template_folder()
def get_template_dir(self):
return self._web_server.get_template_dir()
def get_web_folder(self):
return self._web_server.get_web_folder()
def get_web_dir(self):
return self._web_server.get_web_dir()
def reload_web_server(self):
self._web_server.reload()
@ -45,3 +45,6 @@ class ObController(abc.ABC):
def get_external_storage_server(self):
return self._kernel.external_storage_server
def render_view(self, template_file: str, **parameters: dict) -> str:
return self._template_renderer.render_view(template_file, self.plugin(), **parameters)

View File

@ -13,8 +13,6 @@ from src.model.hook.FunctionalHookRegistration import FunctionalHookRegistration
from src.service.ModelStore import ModelStore
from src.service.TemplateRenderer import TemplateRenderer
from src.constant.WebDirConstant import WebDirConstant
from src.service.AliasFileSystemLoader import AliasFileSystemLoader
class ObPlugin(abc.ABC):
@ -26,7 +24,7 @@ class ObPlugin(abc.ABC):
self._plugin_dir = plugin_dir
self._model_store = model_store
self._template_renderer = template_renderer
self._rendering_env = self._init_rendering_env()
self._rendering_env = template_renderer.init_rendering_env(self._plugin_dir)
@abc.abstractmethod
def use_id(self) -> str:
@ -60,6 +58,9 @@ class ObPlugin(abc.ABC):
def get_plugin_variable_name(self, name: str) -> str:
return "{}_{}".format(self.get_plugin_variable_prefix(), name)
def get_plugin_static_src_dir(self) -> str:
return "{}/{}".format(self._plugin_dir, WebDirConstant.FOLDER_PLUGIN_STATIC_SRC)
def add_variable(self, name: str, value='', section: str = '', type: VariableType = VariableType.STRING, editable: bool = True, description: str = '', description_edition: str = '', selectables: Optional[Dict[str, str]] = None, unit: Optional[VariableUnit] = None, refresh_player: bool = False) -> Variable:
return self._model_store.variable().set_variable(
name=self.get_plugin_variable_name(name),
@ -81,32 +82,9 @@ class ObPlugin(abc.ABC):
def add_functional_hook_registration(self, hook: HookType, priority: int = 0, function=None) -> FunctionalHookRegistration:
return FunctionalHookRegistration(plugin=self, hook=hook, priority=priority, function=function)
def _init_rendering_env(self) -> Environment:
alias_paths = {
"::": "{}/".format(WebDirConstant.FOLDER_TEMPLATES),
"@": "{}/{}/".format(self._plugin_dir.replace(self._kernel.get_application_dir(), ''), WebDirConstant.FOLDER_TEMPLATES)
}
env = Environment(
loader=AliasFileSystemLoader(
searchpath=self._kernel.get_application_dir(),
alias_paths=alias_paths
),
autoescape=select_autoescape(['html', 'xml'])
)
return env
def render_view(self, template_file: str, **parameters: dict) -> str:
template = self.get_rendering_env().get_template(template_file)
return template.render(
request=request,
url_for=url_for,
**parameters,
**self._template_renderer.get_view_globals(),
)
def translate(self, token, resolve=False) -> Union[Dict, str]:
token = token if token.startswith(self.use_id()) else "{}_{}".format(self.use_id(), token)
return self._model_store.lang().translate(token) if resolve else token
def render_view(self, template_file: str, **parameters: dict) -> str:
return self._template_renderer.render_view(template_file, self, **parameters)

View File

@ -38,4 +38,6 @@ class HookType(Enum):
H_ROOT_JAVASCRIPT = 'h_root_javascript'
H_ROOT_NAV_ELEMENT_START = 'h_root_nav_element_start'
H_ROOT_NAV_ELEMENT_END = 'h_root_nav_element_end'
H_ROOT_PILL_ELEMENT_START = 'h_root_pill_element_start'
H_ROOT_PILL_ELEMENT_END = 'h_root_pill_element_end'
H_ROOT_FOOTER = 'h_root_footer'

View File

@ -1,4 +1,5 @@
import os
import shutil
import logging
import inspect
import importlib
@ -14,6 +15,7 @@ from src.model.enum.VariableType import VariableType
from src.model.enum.HookType import HookType
from src.model.hook.HookRegistration import HookRegistration
from src.model.hook.StaticHookRegistration import StaticHookRegistration
from src.util.UtilFile import copy_files
from typing import List, Dict
@ -164,6 +166,12 @@ class PluginStore:
# WEB CONTROLLERS
self.load_controllers(plugin)
# STATIC FILES
static_src = plugin.get_plugin_static_src_dir()
static_dst = self._web_server.get_plugin_static_dst_dir(plugin.use_id())
if os.path.exists(static_src):
copy_files(static_src, static_dst)
def clean_dead_variables(self) -> None:
for variable_name, variable in self._dead_variables_candidates.items():
logging.debug("Removing dead plugin variable {}".format(variable_name))

View File

@ -1,8 +1,9 @@
import os
import json
from flask import Flask, send_from_directory, Markup, url_for
from typing import List
from flask import Flask, send_from_directory, Markup, url_for, request
from flask_login import current_user
from typing import List, Optional
from jinja2 import Environment, FileSystemLoader, select_autoescape
from src.service.ModelStore import ModelStore
from src.model.enum.HookType import HookType
@ -10,6 +11,7 @@ from src.model.hook.HookRegistration import HookRegistration
from src.model.hook.StaticHookRegistration import StaticHookRegistration
from src.model.hook.FunctionalHookRegistration import FunctionalHookRegistration
from src.constant.WebDirConstant import WebDirConstant
from src.service.AliasFileSystemLoader import AliasFileSystemLoader
from src.util.utils import get_safe_cron_descriptor, \
is_cron_in_datetime_moment, \
is_cron_in_week_moment, \
@ -23,6 +25,7 @@ class TemplateRenderer:
self._kernel = kernel
self._model_store = model_store
self._render_hook = render_hook
self._rendering_env = self.init_rendering_env()
def cron_descriptor(self, expression: str, use_24hour_time_format=True) -> str:
return get_safe_cron_descriptor(expression, use_24hour_time_format, self._model_store.lang().get_lang(local_with_country=True))
@ -80,3 +83,44 @@ class TemplateRenderer:
content.append(hook_registration.function())
return Markup("".join(content))
def init_rendering_env(self, base_folder: Optional[str] = None) -> Environment:
base_folder = "{}/".format(base_folder.replace(self._kernel.get_application_dir(), '')) if base_folder else ''
alias_paths = {
"::": "{}/".format(WebDirConstant.FOLDER_TEMPLATES),
"@": "{}{}/".format(base_folder, WebDirConstant.FOLDER_TEMPLATES)
}
env = Environment(
loader=AliasFileSystemLoader(
searchpath=self._kernel.get_application_dir(),
alias_paths=alias_paths
),
autoescape=select_autoescape(['html', 'xml'])
)
return env
def get_rendering_env(self) -> Environment:
return self._rendering_env
def render_view(self, template_file: str, plugin: Optional = None, **parameters: dict) -> str:
base_rendering_env = plugin.get_rendering_env() if plugin else self.get_rendering_env()
template = base_rendering_env.get_template(template_file)
if plugin:
parameters['STATIC_PLUGIN_PREFIX'] = "/{}/{}/{}/{}/".format(
WebDirConstant.FOLDER_STATIC,
WebDirConstant.FOLDER_STATIC_WEB_ASSETS,
WebDirConstant.FOLDER_PLUGIN_STATIC_DST,
plugin.use_id()
)
return template.render(
request=request,
url_for=url_for,
current_user=current_user,
**parameters,
**self.get_view_globals(),
)

View File

@ -53,20 +53,23 @@ class WebServer:
def get_app(self):
return self._app
def get_template_folder(self) -> str:
def get_template_dir(self) -> str:
return "{}/{}".format(self._kernel.get_application_dir(), WebDirConstant.FOLDER_TEMPLATES)
def get_static_folder(self) -> str:
def get_static_dir(self) -> str:
return "{}/{}".format(self._kernel.get_application_dir(), WebDirConstant.FOLDER_STATIC)
def get_web_folder(self) -> str:
def get_web_dir(self) -> str:
return "{}/{}/{}".format(self._kernel.get_application_dir(), WebDirConstant.FOLDER_STATIC, WebDirConstant.FOLDER_STATIC_WEB_ASSETS)
def get_plugin_static_dst_dir(self, plugin_id: str) -> str:
return "{}/{}/{}".format(self.get_web_dir(), WebDirConstant.FOLDER_PLUGIN_STATIC_DST, plugin_id)
def _setup_flask_app(self) -> None:
self._app = Flask(
__name__,
template_folder=self.get_template_folder(),
static_folder=self.get_static_folder(),
template_folder=self.get_template_dir(),
static_folder=self.get_static_dir(),
)
self._app.config['UPLOAD_FOLDER'] = "{}/{}".format(WebDirConstant.FOLDER_STATIC, WebDirConstant.FOLDER_STATIC_WEB_UPLOADS)
@ -118,5 +121,5 @@ class WebServer:
def _setup_web_errors(self) -> None:
@self._app.errorhandler(404)
def not_found(e):
return send_from_directory(self.get_template_folder(), 'core/error404.html'), 404
return send_from_directory(self.get_template_dir(), 'core/error404.html'), 404

View File

@ -1,6 +1,7 @@
import os
import uuid
import math
import shutil
def randomize_filename(old_filename: str) -> str:
@ -17,3 +18,20 @@ def convert_size(size_bytes):
p = math.pow(1024, i)
s = round(size_bytes / p, 2)
return f"{s} {size_name[i]}"
def copy_files(src, dst):
if not os.path.exists(dst):
os.makedirs(dst)
for root, dirs, files in os.walk(src):
# Construct the destination path
dst_path = os.path.join(dst, os.path.relpath(root, src))
if not os.path.exists(dst_path):
os.makedirs(dst_path)
for file in files:
# Copy each file to the destination
src_file = os.path.join(root, file)
dst_file = os.path.join(dst_path, file)
shutil.copy2(src_file, dst_file)

View File

@ -1 +1 @@
2.1.1
2.2.0

View File

@ -168,25 +168,14 @@
{% if authenticated_view %}
<div class="context-bar {{ 'hidden' if not show_context_bar }}">
{% if current_dynmenu %}
<div class="context-menu">
<div class="inner">
<ul class="pills">
{% for menu in current_dynmenu.pills %}
<li class="{{ 'active' if active_route == menu.route or active_route == menu.route_alt }}">
{% set href = menu.url_for if menu.url_for else url_for(menu.route) %}
<a href="{{ href }}">
<span class="icon">
<i class="fa {{ menu.icon }}"></i>
</span>
{{ menu.name }}
</a>
</li>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
{% block pill_menu %}
{% if current_dynmenu %}
{% with pills=current_dynmenu.pills %}
{% include 'core/pill-menu.jinja.html' %}
{% endwith %}
{% endif %}
{% endblock %}
<div class="context-divider"></div>

View File

@ -0,0 +1,19 @@
<div class="context-menu">
<div class="inner">
<ul class="pills">
{{ HOOK(H_ROOT_PILL_ELEMENT_START) }}
{% for menu in pills %}
<li class="{{ 'active' if active_route == menu.route or active_route == menu.route_alt }}">
{% set href = menu.url_for if menu.url_for else url_for(menu.route) %}
<a href="{{ href }}">
<span class="icon">
<i class="fa {{ menu.icon }}"></i>
</span>
{{ menu.name }}
</a>
</li>
{% endfor %}
{{ HOOK(H_ROOT_PILL_ELEMENT_END) }}
</ul>
</div>
</div>

View File

@ -36,7 +36,7 @@
<div class="top-actions">
{{ HOOK(H_SLIDESHOW_CONTENT_TOOLBAR_ACTIONS_START) }}
<button type="button" class="folder-add btn-neutral">
<button type="button" class="btn folder-add btn-neutral">
<i class="fa fa-folder-plus icon-left"></i>
{{ l.common_new_folder }}
</button>