diff --git a/cof/forms.py b/cof/forms.py index 719719a9..0b0ae5a8 100644 --- a/cof/forms.py +++ b/cof/forms.py @@ -15,9 +15,9 @@ from django.core.validators import MinLengthValidator from .models import CofProfile, EventCommentValue, \ CalendarSubscription, Club from .widgets import TriStateCheckbox -from .shared import lock_table, unlock_table from gestion.models import Profile +from gestion.shared import lock_table, unlock_table from bda.models import Spectacle diff --git a/cof/petits_cours_views.py b/cof/petits_cours_views.py index 6bcb5cb8..92f70706 100644 --- a/cof/petits_cours_views.py +++ b/cof/petits_cours_views.py @@ -18,9 +18,10 @@ from .petits_cours_models import ( PetitCoursAbility, PetitCoursSubject ) from .decorators import buro_required -from .shared import lock_table, unlock_tables from .petits_cours_forms import DemandeForm, MatieresFormSet +from gestion.shared import lock_table, unlock_tables + class DemandeListView(ListView): model = PetitCoursDemande diff --git a/cof/templates/base_header.html b/cof/templates/base_header.html index 801783e8..4713a286 100644 --- a/cof/templates/base_header.html +++ b/cof/templates/base_header.html @@ -10,8 +10,10 @@ {% endblock %}
-   |  - Se déconnecter  +   |  + + Se déconnecter  +

{% if user.first_name %}{{ user.first_name }}{% else %}{{ user.username }}{% endif %}, {% if user.profile.is_cof %}au COF{% else %}non-COF{% endif %}

diff --git a/cof/templates/error.html b/cof/templates/error.html deleted file mode 100644 index 082abcf0..00000000 --- a/cof/templates/error.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends "base_title.html" %} - -{% block realcontent %} - {% if error_type == "use_clipper_login" %} -

Votre identifiant est lié à un compte clipper

-

Veuillez vous connecter à l'aide de votre compte clipper

- {% elif error_type == "no_password" %} -

Votre compte n'a pas de mot de passe associé

-

Veuillez nous contacter pour que nous en définissions un et que nous vous le transmettions !

- {% else %} -

{{ error_title }}

-

{{ error_description }}

- {% endif %} -{% endblock %} diff --git a/cof/views.py b/cof/views.py index 4b18a862..93425ab3 100644 --- a/cof/views.py +++ b/cof/views.py @@ -9,7 +9,6 @@ from custommail.shortcuts import send_custom_mail from django.shortcuts import redirect, get_object_or_404, render from django.http import Http404, HttpResponse, HttpResponseForbidden from django.contrib.auth.decorators import login_required -from django.contrib.auth.views import login as django_login_view from django.contrib.auth.models import User from django.contrib.sites.models import Site from django.utils import timezone @@ -50,50 +49,6 @@ def home(request): return render(request, "home.html", data) -def login(request): - if request.user.is_authenticated(): - return redirect("cof.views.home") - context = {} - if request.method == "GET" and 'next' in request.GET: - context['next'] = request.GET['next'] - return render(request, "login_switch.html", context) - - -def login_ext(request): - if request.method == "POST" and "username" in request.POST: - try: - user = User.objects.get(username=request.POST["username"]) - if not user.has_usable_password() or user.password in ("", "!"): - profile, created = CofProfile.objects.get_or_create(user=user) - if profile.login_clipper: - return render(request, "error.html", - {"error_type": "use_clipper_login"}) - else: - return render(request, "error.html", - {"error_type": "no_password"}) - except User.DoesNotExist: - pass - context = {} - if request.method == "GET" and 'next' in request.GET: - context['next'] = request.GET['next'] - if request.method == "POST" and 'next' in request.POST: - context['next'] = request.POST['next'] - return django_login_view(request, template_name='login.html', - extra_context=context) - - -@login_required -def logout(request): - try: - profile = request.user.profile - except CofProfile.DoesNotExist: - profile, created = CofProfile.objects.get_or_create(user=request.user) - if profile.login_clipper: - return redirect("django_cas_ng.views.logout") - else: - return redirect("django.contrib.auth.views.logout") - - @login_required def survey(request, survey_id): survey = get_object_or_404(Survey, id=survey_id) diff --git a/gestioCOF/settings_dev.py b/gestioCOF/settings_dev.py index fe1981df..253f924f 100644 --- a/gestioCOF/settings_dev.py +++ b/gestioCOF/settings_dev.py @@ -33,7 +33,6 @@ INSTALLED_APPS = ( 'django.contrib.sites', 'django.contrib.messages', 'django.contrib.staticfiles', - 'grappelli', 'django.contrib.admin', 'django.contrib.admindocs', 'autocomplete_light', @@ -80,7 +79,7 @@ TEMPLATES = [ 'django.core.context_processors.i18n', 'django.core.context_processors.media', 'django.core.context_processors.static', - 'cof.shared.context_processor', + 'gestion.context_processors.context_processor', 'kfet.context_processors.auth', ], }, @@ -130,9 +129,6 @@ MEDIA_URL = '/media/' # Various additional settings SITE_ID = 1 -GRAPPELLI_ADMIN_HEADLINE = "GestioCOF" -GRAPPELLI_ADMIN_TITLE = "GestioCOF" - MAIL_DATA = { 'petits_cours': { 'FROM': "Le COF ", @@ -146,7 +142,7 @@ MAIL_DATA = { 'REPLYTO': 'BdA-Revente '}, } -LOGIN_URL = "cof-login" +LOGIN_URL = "gestion:login" LOGIN_REDIRECT_URL = "home" CAS_SERVER_URL = 'https://cas.eleves.ens.fr/' @@ -155,7 +151,7 @@ CAS_REDIRECT_URL = '/' CAS_EMAIL_FORMAT = "%s@clipper.ens.fr" AUTHENTICATION_BACKENDS = ( 'django.contrib.auth.backends.ModelBackend', - 'cof.shared.COFCASBackend', + 'gestion.backends.COFCASBackend', 'kfet.backends.GenericTeamBackend', ) diff --git a/gestioCOF/urls.py b/gestioCOF/urls.py index 1c5fe9e3..ec531778 100644 --- a/gestioCOF/urls.py +++ b/gestioCOF/urls.py @@ -10,16 +10,16 @@ from django.conf import settings from django.conf.urls import include, url from django.conf.urls.static import static from django.contrib import admin -from django.views.generic.base import TemplateView from django.contrib.auth import views as django_views -from django_cas_ng import views as django_cas_views -from cof import views as cof_views, csv_views +from cof import views as cof_views from cof.urls import export_patterns, petitcours_patterns, \ surveys_patterns, events_patterns, calendar_patterns, \ clubs_patterns from cof.autocomplete import autocomplete +from gestion import views as gestion_views + autocomplete_light.autodiscover() admin.autodiscover() @@ -28,6 +28,10 @@ urlpatterns = [ url(r'^$', cof_views.home, name='home'), # The common views url(r"^", include("gestion.urls", namespace='gestion')), + # Admin urls + url(r'^admin/logout/', gestion_views.logout), + url(r'^admin/doc/', include('django.contrib.admindocs.urls')), + url(r'^admin/', include(admin.site.urls)), # Le BdA url(r'^bda/', include('bda.urls')), # Les exports @@ -42,15 +46,6 @@ urlpatterns = [ url(r'^calendar/', include(calendar_patterns)), # Clubs url(r'^clubs/', include(clubs_patterns)), - # Authentification - url(r'^cof/denied$', TemplateView.as_view(template_name='cof-denied.html'), - name="cof-denied"), - url(r'^cas/login$', django_cas_views.login, name="cas_login_view"), - url(r'^cas/logout$', django_cas_views.logout), - url(r'^outsider/login$', cof_views.login_ext), - url(r'^outsider/logout$', django_views.logout, {'next_page': 'home'}), - url(r'^login$', cof_views.login, name="cof-login"), - url(r'^logout$', cof_views.logout), # Infos persos url(r'^outsider/password-change$', django_views.password_change), url(r'^outsider/password-change-done$', @@ -67,14 +62,6 @@ urlpatterns = [ # Autocompletion url(r'^autocomplete/registration$', autocomplete), url(r'^autocomplete/', include('autocomplete_light.urls')), - # Interface admin - url(r'^admin/logout/', cof_views.logout), - url(r'^admin/doc/', include('django.contrib.admindocs.urls')), - url(r'^admin/(?P[\d\w]+)/(?P[\d\w]+)/csv/', - csv_views.admin_list_export, - {'fields': ['username', ]}), - url(r'^admin/', include(admin.site.urls)), - url(r'^grappelli/', include('grappelli.urls')), # Liens utiles du COF et du BdA url(r'^utile_cof$', cof_views.utile_cof), url(r'^utile_bda$', cof_views.utile_bda), diff --git a/cof/shared.py b/gestion/backends.py similarity index 55% rename from cof/shared.py rename to gestion/backends.py index 6b1a7705..9cc87abe 100644 --- a/cof/shared.py +++ b/gestion/backends.py @@ -1,17 +1,11 @@ # -*- coding: utf-8 -*- -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - -from django.contrib.sites.models import Site from django.conf import settings from django_cas_ng.backends import CASBackend from django_cas_ng.utils import get_cas_client from django.contrib.auth import get_user_model -from django.db import connection -from .models import CofProfile +from gestion.models import Profile User = get_user_model() @@ -32,9 +26,12 @@ class COFCASBackend(CASBackend): # éviter les doublons. username = username.strip().lower() - profiles = CofProfile.objects.filter(login_clipper=username) + profiles = Profile.objects.filter(login_clipper=username) if len(profiles) > 0: - profile = profiles.order_by('-is_cof')[0] + # XXX. We have to deal with multiple profiles, this should not + # happen + # profile = profiles.order_by('-is_cof')[0] + profile = profiles.first() user = profile.user return user try: @@ -50,49 +47,11 @@ class COFCASBackend(CASBackend): user = self.authenticate_cas(ticket, service, request) if user is None: return user - try: - profile = user.profile - except CofProfile.DoesNotExist: - profile, created = CofProfile.objects.get_or_create(user=user) - profile.save() + profile = user.profile if not profile.login_clipper: profile.login_clipper = user.username profile.save() if not user.email: user.email = settings.CAS_EMAIL_FORMAT % profile.login_clipper user.save() - if profile.is_buro and not user.is_staff: - user.is_staff = True - user.save() return user - - -def context_processor(request): - '''Append extra data to the context of the given request''' - data = { - "user": request.user, - "site": Site.objects.get_current(), - } - return data - - -def lock_table(*models): - query = "LOCK TABLES " - for i, model in enumerate(models): - table = model._meta.db_table - if i > 0: - query += ", " - query += "%s WRITE" % table - cursor = connection.cursor() - cursor.execute(query) - row = cursor.fetchone() - return row - - -def unlock_tables(*models): - cursor = connection.cursor() - cursor.execute("UNLOCK TABLES") - row = cursor.fetchone() - return row - -unlock_table = unlock_tables diff --git a/gestion/context_processors.py b/gestion/context_processors.py new file mode 100644 index 00000000..d909f6c2 --- /dev/null +++ b/gestion/context_processors.py @@ -0,0 +1,10 @@ +from django.contrib.sites.models import Site + + +def context_processor(request): + '''Append extra data to the context of the given request''' + data = { + "user": request.user, + "site": Site.objects.get_current(), + } + return data diff --git a/gestion/shared.py b/gestion/shared.py new file mode 100644 index 00000000..39bc5da7 --- /dev/null +++ b/gestion/shared.py @@ -0,0 +1,27 @@ +""" +Locking/unlocking tools to prevent tables to be corrupted +""" + +from django.db import connection + + +def lock_table(*models): + query = "LOCK TABLES " + for i, model in enumerate(models): + table = model._meta.db_table + if i > 0: + query += ", " + query += "%s WRITE" % table + cursor = connection.cursor() + cursor.execute(query) + row = cursor.fetchone() + return row + + +def unlock_tables(*models): + cursor = connection.cursor() + cursor.execute("UNLOCK TABLES") + row = cursor.fetchone() + return row + +unlock_table = unlock_tables diff --git a/gestion/templates/gestion/error.html b/gestion/templates/gestion/error.html new file mode 100644 index 00000000..a35d2872 --- /dev/null +++ b/gestion/templates/gestion/error.html @@ -0,0 +1,20 @@ +{% extends "base_title.html" %} + +{% block realcontent %} + {% if error_type == "use_clipper_login" %} +

Votre identifiant est lié à un compte clipper

+

+ Veuillez vous connecter à l'aide de votre + compte clipper +

+ {% elif error_type == "no_password" %} +

Votre compte n'a pas de mot de passe associé

+

+ Veuillez nous contacter pour que + nous en définissions un et que nous vous le transmettions ! +

+ {% else %} +

{{ error_title }}

+

{{ error_description }}

+ {% endif %} +{% endblock %} diff --git a/cof/templates/login.html b/gestion/templates/gestion/login.html similarity index 93% rename from cof/templates/login.html rename to gestion/templates/gestion/login.html index 67b2134d..65329371 100644 --- a/cof/templates/login.html +++ b/gestion/templates/gestion/login.html @@ -15,7 +15,7 @@

Identifiants incorrects.

{% endif %}
+ action="{% url 'gestion:login_ext' %}?next={{ next|urlencode }}"> {% csrf_token %}
diff --git a/cof/templates/login_switch.html b/gestion/templates/gestion/login_switch.html similarity index 70% rename from cof/templates/login_switch.html rename to gestion/templates/gestion/login_switch.html index 7945973e..f5901ea6 100644 --- a/cof/templates/login_switch.html +++ b/gestion/templates/gestion/login_switch.html @@ -12,13 +12,13 @@
-
- Compte clipper -
+ href="{% url 'gestion:cas_login' %}?next={{ next|urlencode }}"> +
+ Compte clipper +
+ href="{% url 'gestion:login_ext' %}?next={{ next|urlencode }}">
Extérieur
diff --git a/gestion/urls.py b/gestion/urls.py index 037101dc..55e5658a 100644 --- a/gestion/urls.py +++ b/gestion/urls.py @@ -1,8 +1,24 @@ -from django.conf.urls import url +from django.conf.urls import url, include +from django.views.generic.base import TemplateView +from django.contrib.auth import views as django_views +from django.contrib import admin +from django_cas_ng import views as django_cas_views from . import views urlpatterns = [ + # Profile edition url(r"^profile/?$", views.profile, name="profile"), + + # Authentication + url(r'^cof/denied$', + TemplateView.as_view(template_name='cof-denied.html'), + name="denied"), + url(r'^cas/login$', django_cas_views.login, name="cas_login"), + url(r'^cas/logout$', django_cas_views.logout, name="cas_logout"), + url(r'^outsider/login$', views.login_ext, name="login_ext"), + url(r'^outsider/logout$', django_views.logout, {'next_page': 'home'}), + url(r'^login$', views.login, name="login"), + url(r'^logout$', views.logout, name="logout"), ] diff --git a/gestion/views.py b/gestion/views.py index 7615f3c9..407a883c 100644 --- a/gestion/views.py +++ b/gestion/views.py @@ -1,9 +1,59 @@ -from django.shortcuts import render +""" +The common views of the different organisations. +- Authentication +- Profile edition +""" + +from django.shortcuts import render, redirect from django.contrib.auth.decorators import login_required +from django.contrib.auth.models import User +from django.contrib.auth.views import ( + login as django_login, logout as django_logout +) from .forms import ProfileForm, UserForm +def login(request): + if request.user.is_authenticated(): + return redirect("cof.views.home") + context = {} + # Fetch the next page from the request data + if request.method == "GET" and 'next' in request.GET: + context['next'] = request.GET['next'] + return render(request, "gestion/login_switch.html", context) + + +def login_ext(request): + if request.method == "POST" and "username" in request.POST: + try: + user = User.objects.get(username=request.POST["username"]) + if user.profile.login_clipper: + return render(request, "gestion/error.html", + {"error_type": "use_clipper_login"}) + if not user.has_usable_password() or user.password in ("", "!"): + return render(request, "gestion/error.html", + {"error_type": "no_password"}) + except User.DoesNotExist: + pass + context = {} + # Fetch the next page from the request data + if request.method == "GET" and 'next' in request.GET: + context['next'] = request.GET['next'] + if request.method == "POST" and 'next' in request.POST: + context['next'] = request.POST['next'] + return django_login(request, template_name='gestion/login.html', + extra_context=context) + + +@login_required +def logout(request): + if request.user.profile.login_clipper: + return redirect("gestion:cas_logout") + else: + return django_logout(request) + + @login_required def profile(request): success = False diff --git a/kfet/templates/kfet/base_nav.html b/kfet/templates/kfet/base_nav.html index 79a7bd96..7fcd3e40 100644 --- a/kfet/templates/kfet/base_nav.html +++ b/kfet/templates/kfet/base_nav.html @@ -51,7 +51,7 @@ {% endif %} {% if user.is_authenticated %} -
  • +
  • {% endif %}