Merge branch 'website'

tested branching, but best to keep it straight forward for now
This commit is contained in:
Arthur Gerbaud
2016-12-01 11:28:07 +01:00
19 changed files with 237 additions and 201 deletions

View File

@@ -0,0 +1,54 @@
{% load bootstrap3 %}
<li class="dropdown app-menu"><a class="dropdown-toggle" data-toggle="dropdown" href="#">Création<b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="#" id="new-sujet">{% bootstrap_icon "user" %} Nouveau sujet</a></li>
<li><a href="#" id="new-lieu">{% bootstrap_icon "globe" %} Nouveau lieu</a></li>
</ul>
<script type="text/javascript">
/* Lier les boutons de création
* Thanks to Derek Morgan, https://dmorgan.info/posts/django-views-bootstrap-modals/
*/
$(function() {
var formAjaxSubmit = function(form, modal) {
$(form).submit(function (e) {
e.preventDefault();
$.ajax({
type: $(this).attr('method'),
url: $(this).attr('action'),
data: $(this).serialize(),
success: function (xhr, ajaxOptions, thrownError) {
if ( $(xhr).find('.has-error').length > 0 || $(xhr).find('.alert-danger').length > 0) {
$(modal).find('.modal-body').html(xhr);
formAjaxSubmit(form, modal);
} else {
$(modal).modal('toggle');
// Reload page ?
location.reload(true)
}
},
error: function (xhr, ajaxOptions, thrownError) {
// handle response errors here
}
});
});
};
/* TODO: Use formAjaxSubmit above, but reload page on form success */
$('#new-sujet').click(function() {
$('#form-modal-body').load('{% url "sujets:create" %}?next={% url "maraudes:create" pk=maraude.id %}', function () {
$('.modal-title').text("Nouveau sujet");
$('#form-modal').modal('toggle');
formAjaxSubmit("#form-modal-body form", "#form-modal");
});
});
$('#new-lieu').click(function() {
$('#form-modal-body').load('{% url "maraudes:lieu-create" %}?next={% url "maraudes:create" pk=maraude.id %}', function () {
$('.modal-title').text("Nouveau lieu");
$('#form-modal').modal('toggle');
formAjaxSubmit("#form-modal-body form", "#form-modal");
});
});
});
</script>

View File

@@ -1,56 +0,0 @@
{% if user.is_superuser %}{% load bootstrap3 %}
<li class="dropdown app-menu"><a class="dropdown-toggle" data-toggle="dropdown" href="#">Création<b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="#" id="new-sujet">{% bootstrap_icon "user" %} Nouveau sujet</a></li>
<li><a href="#" id="new-lieu">{% bootstrap_icon "globe" %} Nouveau lieu</a></li>
</ul>
{% endif %}
<script type="text/javascript">
/* Lier les boutons de création
* Thanks to Derek Morgan, https://dmorgan.info/posts/django-views-bootstrap-modals/
*/
$(function() {
var formAjaxSubmit = function(form, modal) {
$(form).submit(function (e) {
e.preventDefault();
$.ajax({
type: $(this).attr('method'),
url: $(this).attr('action'),
data: $(this).serialize(),
success: function (xhr, ajaxOptions, thrownError) {
if ( $(xhr).find('.has-error').length > 0 || $(xhr).find('.alert-danger').length > 0) {
$(modal).find('.modal-body').html(xhr);
formAjaxSubmit(form, modal);
} else {
$(modal).modal('toggle');
// Reload page ?
location.reload(true)
}
},
error: function (xhr, ajaxOptions, thrownError) {
// handle response errors here
}
});
});
};
/* TODO: Use formAjaxSubmit above, but reload page on form success */
$('#new-sujet').click(function() {
$('#form-modal-body').load('{% url "sujets:create" %}?next={% url "maraudes:create" pk=maraude.id %}', function () {
$('.modal-title').text("Nouveau sujet");
$('#form-modal').modal('toggle');
formAjaxSubmit("#form-modal-body form", "#form-modal");
});
});
$('#new-lieu').click(function() {
$('#form-modal-body').load('{% url "maraudes:lieu-create" %}?next={% url "maraudes:create" pk=maraude.id %}', function () {
$('.modal-title').text("Nouveau lieu");
$('#form-modal').modal('toggle');
formAjaxSubmit("#form-modal-body form", "#form-modal");
});
});
});
</script>

View File

@@ -7,7 +7,7 @@ from django.test import TestCase
from .models import Maraude, Maraudeur, ReferentMaraude from .models import Maraude, Maraudeur, ReferentMaraude
# Create your tests here. # Create your tests here.
from alsa.base_data import MARAUDEURS from maraudes_project.base_data import MARAUDEURS
MARAUDE_DAYS = [ MARAUDE_DAYS = [
True, True, False, True, True, False, False True, True, False, True, True, False, False

View File

@@ -6,11 +6,11 @@ from . import views
urlpatterns = [ urlpatterns = [
url(r'^$', views.IndexView.as_view(), name="index"), url(r'^$', views.IndexView.as_view(), name="index"),
url(r'planning/$', views.PlanningView.as_view(), name="planning"), url(r'^planning/$', views.PlanningView.as_view(), name="planning"),
url(r'liste/$', views.MaraudeListView.as_view(), name="liste"), url(r'^liste/$', views.MaraudeListView.as_view(), name="liste"),
url(r'lieu/create/$', views.LieuCreateView.as_view(), name="lieu-create"), url(r'^lieu/create/$', views.LieuCreateView.as_view(), name="lieu-create"),
# Compte-rendus de maraude # Compte-rendus de maraude
url(r'^(?P<pk>[0-9]+)/$', views.MaraudeDetailsView.as_view(), name="details"), url(r'^(?P<pk>[0-9]+)/$', views.MaraudeDetailsView.as_view(), name="details"),
url(r'^(?P<pk>[0-9]+)/update/$', views.CompteRenduUpdateView.as_view(), name="update"), url(r'^(?P<pk>[0-9]+)/update/$', views.CompteRenduUpdateView.as_view(), name="update"),
url(r'^(?P<pk>[0-9]+)/cr/$', views.CompteRenduCreateView.as_view(), name="create"), url(r'^(?P<pk>[0-9]+)/create/$', views.CompteRenduCreateView.as_view(), name="create"),
] ]

View File

@@ -25,11 +25,24 @@ from .forms import ( RencontreForm, RencontreInlineFormSet,
from utilisateurs.models import Maraudeur from utilisateurs.models import Maraudeur
from website import decorators as website from website import decorators as website
webpage = website.webpage( maraudes = website.app_config(
name="maraudes",
groups=[Maraudeur],
menu=["maraudes/menu/dernieres_maraudes.html"],
admin_menu=["maraudes/menu/admin_menu.html"],
ajax=False, ajax=False,
app_users=[Maraudeur],
app_menu=["maraudes/menu_dernieres_maraudes.html", "maraudes/menu_administration.html"]
) )
compte_rendu = website.app_config(
name="maraudes",
groups=[Maraudeur],
menu=["compte_rendu/menu/creation.html"],
ajax=False,
)
maraudes_ajax = website.app_config(
name="maraudes",
groups=[Maraudeur],
ajax=True,
)
from django.core.mail import send_mail from django.core.mail import send_mail
@@ -51,7 +64,7 @@ class DerniereMaraudeMixin(object):
@webpage @maraudes
class IndexView(DerniereMaraudeMixin, generic.TemplateView): class IndexView(DerniereMaraudeMixin, generic.TemplateView):
class PageInfo: class PageInfo:
@@ -88,7 +101,7 @@ class IndexView(DerniereMaraudeMixin, generic.TemplateView):
return Maraude.objects.next return Maraude.objects.next
## MARAUDES ## MARAUDES
@webpage @maraudes
class MaraudeDetailsView(DerniereMaraudeMixin, generic.DetailView): class MaraudeDetailsView(DerniereMaraudeMixin, generic.DetailView):
""" Vue détaillé d'un compte-rendu de maraude """ """ Vue détaillé d'un compte-rendu de maraude """
@@ -109,7 +122,7 @@ class MaraudeDetailsView(DerniereMaraudeMixin, generic.DetailView):
@webpage @maraudes
class MaraudeListView(DerniereMaraudeMixin, generic.ListView): class MaraudeListView(DerniereMaraudeMixin, generic.ListView):
""" Vue de la liste des compte-rendus de maraude """ """ Vue de la liste des compte-rendus de maraude """
@@ -129,7 +142,7 @@ class MaraudeListView(DerniereMaraudeMixin, generic.ListView):
## COMPTE-RENDU DE MARAUDE ## COMPTE-RENDU DE MARAUDE
@webpage @compte_rendu
class CompteRenduCreateView(generic.DetailView): class CompteRenduCreateView(generic.DetailView):
""" Vue pour la création d'un compte-rendu de maraude """ """ Vue pour la création d'un compte-rendu de maraude """
@@ -147,8 +160,8 @@ class CompteRenduCreateView(generic.DetailView):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
# Overrides app_menu and replace it #WARNING: Overrides app_menu and replace it
self.app_menu = ["compte_rendu/menu_creation.html"] self._user_menu = ["compte_rendu/menu/creation.html"]
def get_forms(self, *args, initial=None): def get_forms(self, *args, initial=None):
self.form = RencontreForm(*args, self.form = RencontreForm(*args,
@@ -235,7 +248,7 @@ class CompteRenduCreateView(generic.DetailView):
@webpage @compte_rendu
class CompteRenduUpdateView(generic.DetailView): class CompteRenduUpdateView(generic.DetailView):
""" Vue pour mettre à jour le compte-rendu de la maraude """ """ Vue pour mettre à jour le compte-rendu de la maraude """
@@ -301,7 +314,7 @@ class CompteRenduUpdateView(generic.DetailView):
## PLANNING ## PLANNING
@webpage @maraudes
class PlanningView(generic.TemplateView): class PlanningView(generic.TemplateView):
""" Display and edit the planning of next Maraudes """ """ Display and edit the planning of next Maraudes """
@@ -371,7 +384,7 @@ class PlanningView(generic.TemplateView):
## LIEU ## LIEU
@website.webpage(ajax=True, permissions=['maraudes.add_lieu']) @maraudes_ajax
class LieuCreateView(generic.edit.CreateView): class LieuCreateView(generic.edit.CreateView):
model = Lieu model = Lieu
template_name = "maraudes/lieu_create.html" template_name = "maraudes/lieu_create.html"

View File

@@ -1,4 +1,3 @@
{% if user.is_superuser %}
{% load bootstrap3 %} {% load bootstrap3 %}
<li class="dropdown app-menu"> <li class="dropdown app-menu">
<a class="dropdown-toggle" data-toggle="dropdown" href="#"> <a class="dropdown-toggle" data-toggle="dropdown" href="#">
@@ -9,4 +8,3 @@
<li><a href="{% url 'admin:app_list' app_label='sujets' %}"> <li><a href="{% url 'admin:app_list' app_label='sujets' %}">
{% bootstrap_icon "wrench" %} Gérer les sujets</a></li> {% bootstrap_icon "wrench" %} Gérer les sujets</a></li>
</ul> </ul>
{% endif %}

View File

@@ -1,6 +1,6 @@
{% load bootstrap3 %} {% load bootstrap3 %}
<li class="app-menu"> <li class="app-menu">
<a href="{% url 'sujets:liste' %}">Liste des sujets <a href="{% url 'suivi:liste' %}">Liste des sujets
<span class="pull-right">{% bootstrap_icon "list" %}</span> <span class="pull-right">{% bootstrap_icon "list" %}</span>
</a> </a>
</li> </li>

View File

@@ -1,9 +1,9 @@
from django.conf.urls import url from django.conf.urls import url
from . import views from . import views
from sujets import views as sujets_views
urlpatterns = [ urlpatterns = [
url(r'^$', views.IndexView.as_view(), name="index"), url(r'^$', views.IndexView.as_view(), name="index"),
url(r'liste/$', views.SujetListView.as_view(), name="liste"),
url(r'(?P<pk>[0-9]+)/$', views.SuiviSujetView.as_view(), name="details"), url(r'(?P<pk>[0-9]+)/$', views.SuiviSujetView.as_view(), name="details"),
] ]

View File

@@ -1,4 +1,4 @@
from django.shortcuts import render, reverse from django.shortcuts import reverse, redirect
from django.views import generic from django.views import generic
from django.utils import timezone from django.utils import timezone
@@ -9,15 +9,17 @@ from notes.forms import AutoNoteForm
# Create your views here. # Create your views here.
from utilisateurs.models import Maraudeur from utilisateurs.models import Maraudeur
from website import decorators as website from website import decorators as website
webpage = website.webpage( suivi = website.app_config(
name="suivi",
groups=[Maraudeur],
menu=["suivi/menu/sujets.html"],
admin_menu=["suivi/menu/admin_sujets.html"],
ajax=False, ajax=False,
app_users=[Maraudeur],
app_menu=["suivi/menu/sujets.html", "suivi/menu/admin_sujets.html"]
) )
@webpage @suivi
class IndexView(NoteFormMixin, generic.TemplateView): class IndexView(NoteFormMixin, generic.TemplateView):
class PageInfo: class PageInfo:
title = "Suivi des bénéficiaires" title = "Suivi des bénéficiaires"
@@ -36,10 +38,33 @@ class IndexView(NoteFormMixin, generic.TemplateView):
#TemplateView #TemplateView
template_name = "suivi/index.html" template_name = "suivi/index.html"
@suivi
class SujetListView(generic.ListView):
class PageInfo:
title = "Sujet - Liste des sujets"
header = "Liste des sujets"
#ListView
model = Sujet
template_name = "sujets/sujet_liste.html"
paginate_by = 30
def post(self, request, **kwargs):
from watson import search as watson
search_text = request.POST.get('q')
results = watson.filter(Sujet, search_text)
if results.count() == 1:
return redirect(results[0].get_absolute_url())
self.queryset = results
return self.get(request, **kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['query_text'] = self.request.POST.get('q', None)
return context
# Import app_config from 'sujets' application, using
@webpage # its admin_menu option
from sujets.views import sujets
@sujets
class SuiviSujetView(NoteFormMixin, generic.DetailView): class SuiviSujetView(NoteFormMixin, generic.DetailView):
class PageInfo: class PageInfo:
title = "Sujet - {{sujet}}" title = "Sujet - {{sujet}}"
@@ -59,9 +84,6 @@ class SuiviSujetView(NoteFormMixin, generic.DetailView):
model = Sujet model = Sujet
template_name = "suivi/details.html" template_name = "suivi/details.html"
context_object_name = "sujet" context_object_name = "sujet"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.insert_menu("sujets/menu_sujet.html")
def get_context_data(self, *args, **kwargs): def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs) context = super().get_context_data(*args, **kwargs)
context['notes'] = self.object.notes.by_date(reverse=True) context['notes'] = self.object.notes.by_date(reverse=True)

View File

@@ -5,7 +5,7 @@ from .models import Sujet
import datetime import datetime
current_year = datetime.date.today().year current_year = datetime.date.today().year
YEAR_CHOICE = (year - 2 for year in range(current_year, current_year + 10)) YEAR_CHOICE = tuple(year - 2 for year in range(current_year, current_year + 10))
class SujetCreateForm(ModelForm): class SujetCreateForm(ModelForm):
class Meta: class Meta:

View File

@@ -5,6 +5,5 @@ from . import views
urlpatterns = [ urlpatterns = [
url(r'(?P<pk>[0-9]+)/$', views.SujetDetailsView.as_view(), name="details"), url(r'(?P<pk>[0-9]+)/$', views.SujetDetailsView.as_view(), name="details"),
url(r'(?P<pk>[0-9]+)/update/$', views.SujetUpdateView.as_view(), name="update"), url(r'(?P<pk>[0-9]+)/update/$', views.SujetUpdateView.as_view(), name="update"),
url(r'liste/$', views.SujetListView.as_view(), name="liste"),
url(r'create/$', views.SujetCreateView.as_view(), name="create"), url(r'create/$', views.SujetCreateView.as_view(), name="create"),
] ]

View File

@@ -7,15 +7,16 @@ from .forms import SujetCreateForm
### Webpage config ### Webpage config
from utilisateurs.models import Maraudeur from utilisateurs.models import Maraudeur
from website import decorators as website from website import decorators as website
webpage = website.webpage( sujets = website.app_config(
name="suivi",
groups=[Maraudeur],
menu=["suivi/menu/sujets.html"],
admin_menu=["sujets/menu/admin_sujet.html"],
ajax=True, ajax=True,
app_users=[Maraudeur],
app_name="suivi",
app_menu=["sujets/menu/admin_sujet.html"]
) )
### Views ### Views
@webpage @sujets
class SujetDetailsView(generic.DetailView): class SujetDetailsView(generic.DetailView):
class PageInfo: class PageInfo:
title = "Sujet - {{ sujet }}" title = "Sujet - {{ sujet }}"
@@ -27,33 +28,10 @@ class SujetDetailsView(generic.DetailView):
@webpage
class SujetListView(generic.ListView):
class PageInfo:
title = "Sujet - Liste des sujets"
header = "Liste des sujets"
#ListView
model = Sujet
template_name = "sujets/sujet_liste.html"
paginate_by = 30
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.insert_menu("sujets/menu/admin_sujet.html")
def post(self, request, **kwargs):
from watson import search as watson
search_text = request.POST.get('q')
results = watson.filter(Sujet, search_text)
if results.count() == 1:
return redirect(results[0].get_absolute_url())
self.queryset = results
return self.get(request, **kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['query_text'] = self.request.POST.get('q', None)
return context
@webpage
@sujets
class SujetUpdateView(generic.edit.UpdateView): class SujetUpdateView(generic.edit.UpdateView):
class PageInfo: class PageInfo:
title = "Mise à jour - {{sujet}}" title = "Mise à jour - {{sujet}}"
@@ -66,7 +44,7 @@ class SujetUpdateView(generic.edit.UpdateView):
@webpage @sujets
class SujetCreateView(generic.edit.CreateView): class SujetCreateView(generic.edit.CreateView):
class PageInfo: class PageInfo:
title = "Nouveau sujet" title = "Nouveau sujet"

View File

@@ -2,7 +2,7 @@ import datetime
from django.db import models from django.db import models
from django.contrib.auth.models import User from django.contrib.auth.models import User, AnonymousUser
# Create your models here. # Create your models here.
class SingletonModel(models.Model): class SingletonModel(models.Model):
@@ -20,6 +20,13 @@ class SingletonModel(models.Model):
except cls.DoesNotExist: except cls.DoesNotExist:
return cls() return cls()
## Visiteur
class Visiteur(AnonymousUser):
def __str__(self):
return "Visiteur"
class Organisme(models.Model): class Organisme(models.Model):
""" Organisme : Association, Entreprise, Service public, ...""" """ Organisme : Association, Entreprise, Service public, ..."""

View File

@@ -5,16 +5,19 @@ def _insert_bases(cls, bases):
new_bases = tuple(bases) + old_bases new_bases = tuple(bases) + old_bases
cls.__bases__ = new_bases cls.__bases__ = new_bases
def webpage(**options): def app_config(**options):
""" Class decorators that insert needed bases according to options : """ Insert per-application configuration options :
-- name : name of the app to register under in navbar
-- groups : user groups needed to access this application
-- menu : user menu templates to be used
-- admin_menu : admin menu templates, only appear for superuser
-- ajax : view will return content_template for Ajax requests -- ajax : view will return content_template for Ajax requests
-- permissions : list of permissions needed to access view
""" """
name = options.pop('name', None)
groups = options.pop('groups', []) #Transition from app_users
menu = options.pop('menu', [])
admin_menu = options.pop('admin_menu', [])
ajax = options.pop('ajax', False) ajax = options.pop('ajax', False)
permissions = options.pop('permissions', [])
app_menu = options.pop('app_menu', [])
app_name = options.pop('app_name', None)
app_users = options.pop('app_users', [])
new_bases = [] new_bases = []
if ajax: if ajax:
@@ -22,18 +25,15 @@ def webpage(**options):
else: else:
new_bases.append(WebsiteTemplateMixin) new_bases.append(WebsiteTemplateMixin)
if permissions: if groups: #TODO: use group instaed of user class
new_bases.append(PermissionRequiredMixin)
if app_users:
new_bases.append(SpecialUserRequiredMixin) new_bases.append(SpecialUserRequiredMixin)
def class_decorator(cls): def class_decorator(cls):
_insert_bases(cls, new_bases) _insert_bases(cls, new_bases)
if permissions: cls._user_menu = menu
cls.permissions = permissions cls._admin_menu = admin_menu
cls.app_menu = app_menu.copy() #avoid conflict between Views cls.app_name = name
cls.app_name = app_name cls.app_users = groups.copy()
cls.app_users = app_users.copy()
return cls return cls
return class_decorator return class_decorator

View File

@@ -57,50 +57,14 @@ def user_processor(request, context):
context['user_group'] = request.user.groups.first() context['user_group'] = request.user.groups.first()
return context return context
class WebsiteTemplateMixin(TemplateResponseMixin):
""" Mixin for easy integration of 'website' templates
Each child can specify: class NavbarMixin(object):
- 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 registered_apps = ['maraudes', 'suivi']
in child view.
"""
base_template = "base_site.html"
content_template = None
app_name = 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):
# Ensure easy integration with generic views
if hasattr(self, 'template_name'):
self.content_template = self.template_name
else:
raise ImproperlyConfigured(self, "has no template defined !")
return self.content_template
def get_apps_config(self): def get_apps_config(self):
""" Load additionnal config data on each app registered in navbar """ Load additionnal config data on each app registered in navbar
Add : Add :
@@ -112,7 +76,7 @@ class WebsiteTemplateMixin(TemplateResponseMixin):
'maraudes': 'road', 'maraudes': 'road',
'suivi': 'eye-open', 'suivi': 'eye-open',
} }
app_names = self.Configuration.navbar_apps app_names = self.registered_apps
self._apps = [] self._apps = []
for name in app_names: for name in app_names:
app_config = apps.get_app_config(name) app_config = apps.get_app_config(name)
@@ -147,16 +111,64 @@ class WebsiteTemplateMixin(TemplateResponseMixin):
self._active_app = self.get_active_app() self._active_app = self.get_active_app()
return self._active_app return self._active_app
def get_menu(self): @property
def menu(self):
""" Renvoie la liste des templates utilisés comme menu pour l'application """ Renvoie la liste des templates utilisés comme menu pour l'application
active active
""" """
return self.app_menu if not self.request.user.is_superuser:
return self._user_menu
return self._user_menu + self._admin_menu
class WebsiteTemplateMixin(NavbarMixin, 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
_user_menu = []
_admin_menu = []
_groups = []
class Configuration:
stylesheets = ['base.css']
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):
# Ensure easy integration with generic views
if hasattr(self, 'template_name'):
self.content_template = self.template_name
else:
raise ImproperlyConfigured(self, "has no template defined !")
return self.content_template
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): def _update_context_with_rendered_blocks(self, context):
""" Render text for existing PageInfo attributes. """ Render text for existing PageInfo attributes.
@@ -178,7 +190,7 @@ class WebsiteTemplateMixin(TemplateResponseMixin):
context = user_processor(self.request, context) context = user_processor(self.request, context)
#Webpage #Webpage
context['content_template'] = self.get_content_template() context['content_template'] = self.get_content_template()
context['app_menu'] = self.get_menu() context['app_menu'] = self.menu
return context return context
class WebsiteAjaxTemplateMixin(WebsiteTemplateMixin): class WebsiteAjaxTemplateMixin(WebsiteTemplateMixin):
@@ -201,9 +213,4 @@ class WebsiteAjaxTemplateMixin(WebsiteTemplateMixin):
return [self.ajax_template] return [self.ajax_template]
return super().get_template_names() return super().get_template_names()
class WebsiteProtectedMixin(WebsiteTemplateMixin, PermissionRequiredMixin):
pass
class WebsiteProtectedWithAjaxMixin(WebsiteAjaxTemplateMixin, PermissionRequiredMixin):
pass

View File

@@ -23,6 +23,9 @@
<a id="UserMenu" href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"> <a id="UserMenu" href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
<strong style="color:#fff;">{% bootstrap_icon "user" %} &middot; {{user}} </strong>&middot; {{ user_group }}<span class="caret"></span></a> <strong style="color:#fff;">{% bootstrap_icon "user" %} &middot; {{user}} </strong>&middot; {{ user_group }}<span class="caret"></span></a>
<ul class="dropdown-menu" aria-labelledby="UserMenu"> <ul class="dropdown-menu" aria-labelledby="UserMenu">
{% if next %}
<p class="well-sm text-center"><strong style="color:#980300;">Vous n'avez pas l'autorisation<br/> d'accéder à cette page.</strong></p>
{%endif%}
{% if user.is_authenticated %} {% if user.is_authenticated %}
{% if user.is_superuser %}<li><a href="{% url 'admin:index' %}">{% bootstrap_icon "wrench" %} Administration</a></li>{% endif %} {% if user.is_superuser %}<li><a href="{% url 'admin:index' %}">{% bootstrap_icon "wrench" %} Administration</a></li>{% endif %}
<li><a href="{% url 'logout' %}">{% bootstrap_icon "log-out" %} Déconnecter</a></li> <li><a href="{% url 'logout' %}">{% bootstrap_icon "log-out" %} Déconnecter</a></li>
@@ -30,7 +33,6 @@
<li> <li>
<form class="navbar-form navbar-left" method="post" action="/login/">{% csrf_token %} <form class="navbar-form navbar-left" method="post" action="/login/">{% csrf_token %}
{% if next %} {% if next %}
<p class="well-sm text-center"><strong style="color:#980300;">Vous devez vous connecter<br/> pour accéder à cette page.</strong></p>
<input name="next" value="{{next}}" hidden /> <input name="next" value="{{next}}" hidden />
{% endif %} {% endif %}
<div class="form-group form-horizontal"> <div class="form-group form-horizontal">

View File

@@ -3,7 +3,7 @@ from django.urls import reverse
from django import views from django import views
from .mixins import WebsiteTemplateMixin from .mixins import WebsiteTemplateMixin
from django.contrib.auth.views import login from django.contrib.auth import login, authenticate
from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect
class Index(WebsiteTemplateMixin, views.generic.TemplateView): class Index(WebsiteTemplateMixin, views.generic.TemplateView):
@@ -16,21 +16,33 @@ class Index(WebsiteTemplateMixin, views.generic.TemplateView):
header = "La Maraude ALSA" header = "La Maraude ALSA"
header_small = "accueil" header_small = "accueil"
def _get_user_entry_point(self): def get_context_data(self, **kwargs):
# Should find best entry point according to user Group context = super().get_context_data(**kwargs)
context["next"] = self.request.GET.get("next", "")
return context
def _get_entry_point(user):
from utilisateurs.models import Maraudeur
if isinstance(user, Maraudeur):
return reverse('maraudes:index') return reverse('maraudes:index')
else:
def get(self, request, *args, **kwargs): return reverse('index')
if request.user.is_authenticated():
return redirect(self._get_user_entry_point())
return super().get(request, *args, **kwargs)
def login_view(request): def login_view(request):
if request.method == 'GET': if request.method == 'GET':
return HttpResponsePermanentRedirect('/') return HttpResponsePermanentRedirect('/')
elif request.method == 'POST': elif request.method == 'POST':
#TODO: authenticate instead of mis-using 'login' view. username = request.POST['username']
response = login(request) password = request.POST['password']
return HttpResponseRedirect('/') user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
next = request.POST.get('next', None)
if not next:
next = _get_entry_point(user)
return HttpResponseRedirect(next)
else:
return HttpResponseRedirect('/')