Commit ccd30bff authored by Martin Matějek's avatar Martin Matějek

Refactor jinja env creation and usage in module

Use one jinja env per plugin for all notifications that belongs to it
parent 067b72c7
...@@ -44,7 +44,7 @@ class Api: ...@@ -44,7 +44,7 @@ class Api:
raise NotADirectoryError("Missing persistent messages directory {}".format(persistent_dir)) raise NotADirectoryError("Missing persistent messages directory {}".format(persistent_dir))
self.plugins = PluginStorage(plugin_dir, templates_dir) self.plugins = PluginStorage(plugin_dir, templates_dir)
self.notifications = NotificationStorage(volatile_dir, persistent_dir) self.notifications = NotificationStorage(volatile_dir, persistent_dir, self.plugins)
def get_notifications(self, media_type='simple', lang='en'): def get_notifications(self, media_type='simple', lang='en'):
"""Return all notifications""" """Return all notifications"""
......
...@@ -56,7 +56,7 @@ class Notification: ...@@ -56,7 +56,7 @@ class Notification:
return n return n
@classmethod @classmethod
def from_file(cls, path): def from_file(cls, path, plugin_storage):
"""Load notification from it's file and return new instance""" """Load notification from it's file and return new instance"""
try: try:
with open(path, 'r') as f: with open(path, 'r') as f:
...@@ -68,7 +68,12 @@ class Notification: ...@@ -68,7 +68,12 @@ class Notification:
logger.warning("Failed to deserialize json file: %s", e) logger.warning("Failed to deserialize json file: %s", e)
return None return None
skel_obj = NotificationSkeleton(**json_data['skeleton']) skel_args = json_data['skeleton']
plug = plugin_storage.get_plugin(skel_args['plugin_name'])
skel_args['jinja_env'] = plug.get_jinja_env()
skel_obj = NotificationSkeleton(**skel_args)
json_data['skeleton'] = skel_obj # replace json data with skeleton instance json_data['skeleton'] = skel_obj # replace json data with skeleton instance
return cls(**json_data) return cls(**json_data)
......
import gettext import gettext
import jinja2
import yaml import yaml
class NotificationSkeleton: class NotificationSkeleton:
ATTRS = ['name', 'plugin_name', 'version', 'template', 'actions', 'template_dirs', 'timeout', 'severity', 'persistent', 'explicit_dismiss'] ATTRS = ['name', 'plugin_name', 'version', 'template', 'actions', 'timeout', 'severity', 'persistent', 'explicit_dismiss']
DEFAULT_ATTRS = ['timeout', 'severity', 'persistent', 'explicit_dismiss'] DEFAULT_ATTRS = ['timeout', 'severity', 'persistent', 'explicit_dismiss']
def __init__(self, name, plugin_name, version, template, actions, template_dirs, timeout=None, severity='info', persistent=False, explicit_dismiss=True): def __init__(self, name, plugin_name, version, template, actions, jinja_env, timeout=None, severity='info', persistent=False, explicit_dismiss=True):
self.name = name self.name = name
self.plugin_name = plugin_name self.plugin_name = plugin_name
self.version = version self.version = version
self.template = template self.template = template
self.actions = actions self.actions = actions
self.template_dirs = template_dirs self.jinja_env = jinja_env
self.timeout = timeout self.timeout = timeout
self.severity = severity self.severity = severity
self.persistent = persistent self.persistent = persistent
self.explicit_dismiss = explicit_dismiss self.explicit_dismiss = explicit_dismiss
self.init_jinja_env() self.setup_jinja_env()
self.translations = {} self.translations = {}
def get_media_types(self): def get_media_types(self):
...@@ -57,20 +56,8 @@ class NotificationSkeleton: ...@@ -57,20 +56,8 @@ class NotificationSkeleton:
pa['name']: pa['title'] for pa in parsed['actions'] if pa['name'] in self.actions pa['name']: pa['title'] for pa in parsed['actions'] if pa['name'] in self.actions
} }
def init_jinja_env(self): def setup_jinja_env(self):
""" """Prepare templates for later use"""
Init jinja environment
Prepare template for later use
For now it will be initiated when creating new skeleton instance
"""
template_loader = jinja2.FileSystemLoader(self.template_dirs)
self.jinja_env = jinja2.Environment(
loader=template_loader,
autoescape=True,
extensions=['jinja2.ext.i18n']
)
self.jinja_message_template = self.jinja_env.get_template(self.template['src']) self.jinja_message_template = self.jinja_env.get_template(self.template['src'])
plugin_template = '{}.yml'.format(self.plugin_name) plugin_template = '{}.yml'.format(self.plugin_name)
......
...@@ -14,11 +14,12 @@ class NotificationStorage: ...@@ -14,11 +14,12 @@ class NotificationStorage:
"""In-memory notification storage that serialize and deserialize them""" """In-memory notification storage that serialize and deserialize them"""
SHORTID_LENGTH = 8 SHORTID_LENGTH = 8
def __init__(self, volatile_dir, persistent_dir): def __init__(self, volatile_dir, persistent_dir, plugin_storage):
self.storage_dirs = { self.storage_dirs = {
'persistent': persistent_dir, 'persistent': persistent_dir,
'volatile': volatile_dir, 'volatile': volatile_dir,
} }
self.plugin_storage = plugin_storage
self.notifications = {} self.notifications = {}
self.shortid_map = {} self.shortid_map = {}
...@@ -54,7 +55,7 @@ class NotificationStorage: ...@@ -54,7 +55,7 @@ class NotificationStorage:
"""Deserialize all notifications from FS""" """Deserialize all notifications from FS"""
logger.debug("Deserializing notifications from '%s'", storage_dir) logger.debug("Deserializing notifications from '%s'", storage_dir)
for filepath in glob.glob(os.path.join(storage_dir, '*.json')): for filepath in glob.glob(os.path.join(storage_dir, '*.json')):
n = Notification.from_file(filepath) n = Notification.from_file(filepath, self.plugin_storage)
if n: if n:
self.notifications[n.notif_id] = n self.notifications[n.notif_id] = n
......
import logging import logging
import os
import pathlib import pathlib
import jinja2
import yaml import yaml
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
...@@ -13,8 +16,9 @@ class Plugin: ...@@ -13,8 +16,9 @@ class Plugin:
# 'notifications' section is intentionally omitted for now # 'notifications' section is intentionally omitted for now
# until mandatory and optional attributes check for 'notifications' is implemented # until mandatory and optional attributes check for 'notifications' is implemented
def __init__(self, name, actions, templates, notifications): def __init__(self, name, template_dirs, actions, templates, notifications):
self.name = name self.name = name
self.template_dirs = template_dirs
self.actions = {} self.actions = {}
self.templates = {} self.templates = {}
self.notification_types = {} self.notification_types = {}
...@@ -30,8 +34,10 @@ class Plugin: ...@@ -30,8 +34,10 @@ class Plugin:
logger.debug("concrete notif: %s", n) logger.debug("concrete notif: %s", n)
self.notification_types[n['name']] = n self.notification_types[n['name']] = n
self.init_jinja_env()
@classmethod @classmethod
def from_file(cls, filepath): def from_file(cls, filepath, plugin_dir, templates_dir):
try: try:
with open(filepath, 'r') as f: with open(filepath, 'r') as f:
data = yaml.safe_load(f) data = yaml.safe_load(f)
...@@ -52,7 +58,12 @@ class Plugin: ...@@ -52,7 +58,12 @@ class Plugin:
# Get only file name without suffix # Get only file name without suffix
filename = pathlib.Path(filepath).stem filename = pathlib.Path(filepath).stem
return cls(filename, **data) # TODO: fix absolute plugin_dir path
jinja_template_dirs = [
os.path.join(templates_dir, filename),
os.path.join(os.getcwd(), plugin_dir),
]
return cls(filename, jinja_template_dirs, **data)
@classmethod @classmethod
def valid_schema(cls, data): def valid_schema(cls, data):
...@@ -75,6 +86,14 @@ class Plugin: ...@@ -75,6 +86,14 @@ class Plugin:
return True return True
def init_jinja_env(self):
template_loader = jinja2.FileSystemLoader(self.template_dirs)
self.jinja_env = jinja2.Environment(
loader=template_loader,
autoescape=True,
extensions=['jinja2.ext.i18n']
)
def get_actions(self): def get_actions(self):
return self.actions return self.actions
...@@ -84,6 +103,9 @@ class Plugin: ...@@ -84,6 +103,9 @@ class Plugin:
def get_notification_types(self): def get_notification_types(self):
return self.notification_types return self.notification_types
def get_jinja_env(self):
return self.jinja_env
def __str__(self): def __str__(self):
"""For debug purposes""" """For debug purposes"""
out = "{\n" out = "{\n"
......
...@@ -26,7 +26,7 @@ class PluginStorage: ...@@ -26,7 +26,7 @@ class PluginStorage:
def load(self): def load(self):
"""Load plugins from FS""" """Load plugins from FS"""
for filepath in glob.glob(os.path.join(self.plugin_dir, '*.yml')): for filepath in glob.glob(os.path.join(self.plugin_dir, '*.yml')):
p = Plugin.from_file(filepath) p = Plugin.from_file(filepath, self.plugin_dir, self.templates_dir)
if p: if p:
self.plugins[p.name] = p self.plugins[p.name] = p
...@@ -99,10 +99,7 @@ class PluginStorage: ...@@ -99,10 +99,7 @@ class PluginStorage:
if attr in skeleton: if attr in skeleton:
notification_args[attr] = skeleton[attr] notification_args[attr] = skeleton[attr]
notification_args['template_dirs'] = [ notification_args['jinja_env'] = plugin.get_jinja_env()
os.path.join(self.templates_dir, plugin_name),
os.path.join(os.getcwd(), self.plugin_dir),
]
return NotificationSkeleton(**notification_args) return NotificationSkeleton(**notification_args)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment