180 lines
6.1 KiB
Python
180 lines
6.1 KiB
Python
import datetime
|
|
from django.utils import timezone
|
|
from django.core.exceptions import ImproperlyConfigured
|
|
from django.apps import apps
|
|
from django.contrib.auth.decorators import login_required, permission_required
|
|
from django.template import Template, Context
|
|
from django.views.generic.base import ContextMixin, TemplateResponseMixin
|
|
|
|
|
|
|
|
## Mixins ##
|
|
|
|
class PermissionRequiredMixin(object):
|
|
permissions = []
|
|
@classmethod
|
|
def as_view(cls, **initkwargs):
|
|
view = super(PermissionRequiredMixin, cls).as_view(**initkwargs)
|
|
return permission_required(cls.permissions)(view)
|
|
|
|
|
|
|
|
class TemplateFieldsMetaclass(type):
|
|
""" Loads Template objects with given string for
|
|
header, header_small, title, ...
|
|
|
|
Theses strings shall be found in cls.Template
|
|
"""
|
|
def __init__(cls, bases, Dict):
|
|
pass
|
|
|
|
|
|
def user_processor(request, context):
|
|
context['user_group'] = request.user.groups.first()
|
|
return context
|
|
|
|
class WebsiteTemplateMixin(TemplateResponseMixin):
|
|
""" Mixin for easy integration of 'website' templates
|
|
|
|
Each child can specify:
|
|
- title : title of the page
|
|
- header : header of the page
|
|
- header_small : sub-header of the page
|
|
|
|
If 'content_template' is not defined, value will fallback to template_name
|
|
in child view.
|
|
"""
|
|
base_template = "base_site.html"
|
|
content_template = None
|
|
app_name = None
|
|
|
|
class Configuration:
|
|
stylesheets = ['base.css']
|
|
navbar_apps = ['maraudes', 'suivi']
|
|
page_blocks = ['header', 'header_small', 'title']
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self.user = None
|
|
self._page_blocks = []
|
|
if not hasattr(self, "PageInfo"):
|
|
raise ImproperlyConfigured("You must define a PageInfo on ", self)
|
|
for attr, val in self.PageInfo.__dict__.items():
|
|
if attr[0] is not "_" and type(val) is str:
|
|
setattr(self, attr, Template(val))
|
|
self._page_blocks.append(attr)
|
|
|
|
def get_template_names(self):
|
|
""" Ensure same template for all children views. """
|
|
return [self.base_template]
|
|
|
|
def get_content_template(self):
|
|
if hasattr(self, 'template_name'): #Ensure easy integration with other views
|
|
self.content_template = self.template_name
|
|
return self.content_template
|
|
|
|
def get_apps_config(self):
|
|
""" Load additionnal config data on each app registered in navbar
|
|
Add :
|
|
- menu_icon : glyphicon in sidebar
|
|
- disabled : show/hide in sidebar
|
|
"""
|
|
## Utils ##
|
|
APP_ICONS = {
|
|
'maraudes': 'road',
|
|
'suivi': 'eye-open',
|
|
}
|
|
app_names = self.Configuration.navbar_apps
|
|
self._apps = []
|
|
for name in app_names:
|
|
app_config = apps.get_app_config(name)
|
|
app_config.menu_icon = APP_ICONS[name]
|
|
#TODO: Seems unsafe (only need module perm)
|
|
app_config.disabled = not self.request.user.has_module_perms(name)
|
|
print(self.request.user, app_config, '-> has perm:', not app_config.disabled)
|
|
self._apps.append(app_config)
|
|
return self._apps
|
|
|
|
@property
|
|
def apps(self):
|
|
if not hasattr(self, '_apps'):
|
|
self._apps = self.get_apps_config()
|
|
return self._apps
|
|
|
|
def get_active_app(self):
|
|
if not self.app_name:
|
|
self.app_name = self.__class__.__module__.split(".")[0]
|
|
active_app = apps.get_app_config(self.app_name)
|
|
if not active_app in self.apps: #TODO: how do we deal with this ?
|
|
print("%s must be registered in Configuration.navbar_apps" % active_app)
|
|
return None
|
|
return active_app
|
|
|
|
@property
|
|
def active_app(self):
|
|
if not hasattr(self, '_active_app'):
|
|
self._active_app = self.get_active_app()
|
|
return self._active_app
|
|
|
|
def get_menu(self):
|
|
""" Renvoie la liste des templates utilisés comme menu pour l'application
|
|
active
|
|
"""
|
|
return self.app_menu
|
|
|
|
def insert_menu(self, template_name):
|
|
""" Insert menu at beginning of self.app_menu """
|
|
if not template_name in self.app_menu:
|
|
self.app_menu.insert(0, template_name)
|
|
|
|
def _update_context_with_rendered_blocks(self, context):
|
|
""" Render text for existing PageInfo attributes.
|
|
See Configuration.page_blocks for valid attribute names """
|
|
render_context = Context(context)
|
|
for attr in self._page_blocks:
|
|
name = "page_%s" % attr
|
|
context[name] = getattr(self, attr).render(render_context)
|
|
return context
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
self._update_context_with_rendered_blocks(context)
|
|
#Website processor
|
|
context['stylesheets'] = self.Configuration.stylesheets
|
|
context['apps'] = self.apps
|
|
context['active_app'] = self.active_app
|
|
# User processor
|
|
context = user_processor(self.request, context)
|
|
#Webpage
|
|
context['content_template'] = self.get_content_template()
|
|
context['app_menu'] = self.get_menu()
|
|
return context
|
|
|
|
class WebsiteAjaxTemplateMixin(WebsiteTemplateMixin):
|
|
""" Mixin that returns content_template instead of base_template when
|
|
request is Ajax.
|
|
"""
|
|
is_ajax = False
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
if not hasattr(self, 'content_template') or not self.content_template:
|
|
self.content_template = self.get_content_template()
|
|
if not hasattr(self, 'ajax_template'):
|
|
self.ajax_template = '%s_inner.html' % self.content_template.split(".")[0]
|
|
if request.is_ajax():
|
|
self.is_ajax = True
|
|
return super().dispatch(request, *args, **kwargs)
|
|
|
|
def get_template_names(self):
|
|
if self.is_ajax:
|
|
return [self.ajax_template]
|
|
return super().get_template_names()
|
|
|
|
class WebsiteProtectedMixin(WebsiteTemplateMixin, PermissionRequiredMixin):
|
|
pass
|
|
|
|
class WebsiteProtectedWithAjaxMixin(WebsiteAjaxTemplateMixin, PermissionRequiredMixin):
|
|
pass
|
|
|