diff --git a/cof/settings_dev.py b/cof/settings_dev.py index 610ae549..79e82c4c 100644 --- a/cof/settings_dev.py +++ b/cof/settings_dev.py @@ -9,10 +9,6 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/1.8/ref/settings/ """ -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - # Build paths inside the project like this: os.path.join(BASE_DIR, ...) import os @@ -165,6 +161,8 @@ AUTHENTICATION_BACKENDS = ( 'gestioncof.shared.COFCASBackend', ) +# LDAP_SERVER_URL = 'ldaps://ldap.spi.ens.fr:636' + # EMAIL_HOST="nef.ens.fr" RECAPTCHA_PUBLIC_KEY = "DUMMY" diff --git a/cof/urls.py b/cof/urls.py index b4c4da3c..7ec728da 100644 --- a/cof/urls.py +++ b/cof/urls.py @@ -4,10 +4,6 @@ Fichier principal de configuration des urls du projet GestioCOF """ -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - import autocomplete_light from django.conf import settings @@ -61,7 +57,8 @@ urlpatterns = [ name='password_change_done'), # Inscription d'un nouveau membre url(r'^registration$', gestioncof_views.registration), - url(r'^registration/clipper/(?P[\w-]+)$', + url(r'^registration/clipper/(?P[\w-]+)/' + r'(?P.*)$', gestioncof_views.registration_form2, name="clipper-registration"), url(r'^registration/user/(?P.+)$', gestioncof_views.registration_form2, name="user-registration"), diff --git a/gestioncof/autocomplete.py b/gestioncof/autocomplete.py index ed0a1e5a..738d484f 100644 --- a/gestioncof/autocomplete.py +++ b/gestioncof/autocomplete.py @@ -1,15 +1,14 @@ # -*- coding: utf-8 -*- -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals +from ldap3 import Connection from django import shortcuts from django.http import Http404 from django.db.models import Q - from django.contrib.auth.models import User -from gestioncof.models import CofProfile, Clipper +from django.conf import settings + +from gestioncof.models import CofProfile from gestioncof.decorators import buro_required @@ -25,37 +24,49 @@ def autocomplete(request): queries = {} bits = q.split() + # Fetching data from User and CofProfile tables queries['members'] = CofProfile.objects.filter(Q(is_cof=True)) queries['users'] = User.objects.filter(Q(profile__is_cof=False)) - queries['clippers'] = Clipper.objects for bit in bits: queries['members'] = queries['members'].filter( - Q(user__first_name__icontains=bit) - | Q(user__last_name__icontains=bit) - | Q(user__username__icontains=bit) - | Q(login_clipper__icontains=bit)) + Q(user__first_name__icontains=bit) + | Q(user__last_name__icontains=bit) + | Q(user__username__icontains=bit) + | Q(login_clipper__icontains=bit)) queries['users'] = queries['users'].filter( - Q(first_name__icontains=bit) - | Q(last_name__icontains=bit) - | Q(username__icontains=bit)) - queries['clippers'] = queries['clippers'].filter( - Q(fullname__icontains=bit) - | Q(username__icontains=bit)) + Q(first_name__icontains=bit) + | Q(last_name__icontains=bit) + | Q(username__icontains=bit)) queries['members'] = queries['members'].distinct() queries['users'] = queries['users'].distinct() - usernames = list(queries['members'].values_list('login_clipper', - flat='True')) \ + + # Clearing redundancies + usernames = ( + list(queries['members'].values_list('login_clipper', flat='True')) + list(queries['users'].values_list('profile__login_clipper', flat='True')) - queries['clippers'] = queries['clippers'] \ - .exclude(username__in=usernames).distinct() - # add clippers + ) + # Fetching data from the SPI + if hasattr(settings, 'LDAP_SERVER_URL'): + # Fetching + ldap_query = '(|{:s})'.format(''.join( + ['(cn=*{:s}*)'.format(bit) for bit in bits] + )) + with Connection(settings.LDAP_SERVER_URL) as conn: + queries['clippers'] = conn.search( + 'dc=spi,dc=ens,dc=fr', query, + attributes=['uid', 'cn'] + ) + # Clearing redundancies + queries['clippers'] = [ + {'clipper': clipper.uid, 'fullname': clipper.cn} + for clipper in queries['clippers'] + if clipper.uid not in usernames + ] + + # Resulting data data.update(queries) - - options = 0 - for query in queries.values(): - options += len(query) - data['options'] = options + data['options'] = sum([len(query) for query in queries]) return shortcuts.render(request, "autocomplete_user.html", data) diff --git a/gestioncof/migrations/0009_delete_clipper.py b/gestioncof/migrations/0009_delete_clipper.py new file mode 100644 index 00000000..e537107b --- /dev/null +++ b/gestioncof/migrations/0009_delete_clipper.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('gestioncof', '0008_py3'), + ] + + operations = [ + migrations.DeleteModel( + name='Clipper', + ), + ] diff --git a/gestioncof/models.py b/gestioncof/models.py index 19590aff..fa9d943a 100644 --- a/gestioncof/models.py +++ b/gestioncof/models.py @@ -1,9 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - from django.db import models from django.contrib.auth.models import User from django.utils.translation import ugettext_lazy as _ @@ -258,15 +254,6 @@ class SurveyAnswer(models.Model): self.survey.title) -@python_2_unicode_compatible -class Clipper(models.Model): - username = models.CharField("Identifiant", max_length=20) - fullname = models.CharField("Nom complet", max_length=200) - - def __str__(self): - return "Clipper %s" % self.username - - @python_2_unicode_compatible class CalendarSubscription(models.Model): token = models.UUIDField() diff --git a/gestioncof/templates/autocomplete_user.html b/gestioncof/templates/autocomplete_user.html index 26411eee..face824d 100644 --- a/gestioncof/templates/autocomplete_user.html +++ b/gestioncof/templates/autocomplete_user.html @@ -15,7 +15,7 @@ {% if clippers %}
  • Utilisateurs clipper
  • {% for clipper in clippers %}{% if forloop.counter < 5 %} -
  • {{ clipper|highlight_clipper:q }}
  • +
  • {{ clipper|highlight_clipper:q }}
  • {% elif forloop.counter == 5 %}
  • ...{% endif %}{% endfor %} {% endif %} diff --git a/gestioncof/templatetags/utils.py b/gestioncof/templatetags/utils.py index 16a1f4e3..90855165 100644 --- a/gestioncof/templatetags/utils.py +++ b/gestioncof/templatetags/utils.py @@ -43,7 +43,7 @@ def highlight_user(user, q): @register.filter def highlight_clipper(clipper, q): if clipper.fullname: - text = "%s (%s)" % (clipper.fullname, clipper.username) + text = "%s (%s)" % (clipper.fullname, clipper.clipper) else: - text = clipper.username + text = clipper.clipper return highlight_text(text, q) diff --git a/gestioncof/views.py b/gestioncof/views.py index 3bc8c2f9..9ed62682 100644 --- a/gestioncof/views.py +++ b/gestioncof/views.py @@ -1,9 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - import unicodecsv import uuid from datetime import timedelta @@ -25,7 +21,7 @@ from gestioncof.models import Event, EventRegistration, EventOption, \ from gestioncof.models import EventCommentField, EventCommentValue, \ CalendarSubscription from gestioncof.shared import send_custom_mail -from gestioncof.models import CofProfile, Clipper, Club +from gestioncof.models import CofProfile, Club from gestioncof.decorators import buro_required, cof_required from gestioncof.forms import UserProfileForm, EventStatusFilterForm, \ SurveyForm, SurveyStatusFilterForm, RegistrationUserForm, \ @@ -321,11 +317,10 @@ def registration_set_ro_fields(user_form, profile_form): @buro_required -def registration_form2(request, login_clipper=None, username=None): +def registration_form2(request, login_clipper=None, username=None, fullname=None): events = Event.objects.filter(old=False).all() member = None if login_clipper: - clipper = get_object_or_404(Clipper, username=login_clipper) try: # check if the given user is already registered member = User.objects.get(username=login_clipper) username = member.username @@ -336,8 +331,8 @@ def registration_form2(request, login_clipper=None, username=None): user_form = RegistrationUserForm(initial={ 'username': login_clipper, 'email': "%s@clipper.ens.fr" % login_clipper}) - if clipper.fullname: - bits = clipper.fullname.split(" ") + if fullname: + bits = fullname.split(" ") user_form.fields['first_name'].initial = bits[0] if len(bits) > 1: user_form.fields['last_name'].initial = " ".join(bits[1:]) @@ -412,12 +407,12 @@ def registration(request): try: member = User.objects.get(username=username) user_form = RegistrationUserForm(request_dict, instance=member) - except User.DoesNotExist: - try: - clipper = Clipper.objects.get(username=username) - login_clipper = clipper.username - except Clipper.DoesNotExist: + if member.profile.login_clipper: + login_clipper = member.profile.login_clipper + else: user_form.force_long_username() + except User.DoesNotExist: + user_form.force_long_username() else: user_form.force_long_username() diff --git a/kfet/autocomplete.py b/kfet/autocomplete.py index 2a24a51e..b8b2e841 100644 --- a/kfet/autocomplete.py +++ b/kfet/autocomplete.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- -from __future__ import (absolute_import, division, - print_function, unicode_literals) -from builtins import * +import ldap3 from django.shortcuts import render from django.http import Http404 from django.db.models import Q -from gestioncof.models import User, Clipper +from django.conf import settings + +from gestioncof.models import User from kfet.decorators import teamkfet_required from kfet.models import Account @@ -25,58 +25,66 @@ def account_create(request): queries = {} search_words = q.split() + # Fetching data from User, CofProfile and Account tables queries['kfet'] = Account.objects queries['users_cof'] = User.objects.filter(Q(profile__is_cof = True)) queries['users_notcof'] = User.objects.filter(Q(profile__is_cof = False)) - queries['clippers'] = Clipper.objects for word in search_words: queries['kfet'] = queries['kfet'].filter( - Q(cofprofile__user__username__icontains = word) - | Q(cofprofile__user__first_name__icontains = word) - | Q(cofprofile__user__last_name__icontains = word) - ) + Q(cofprofile__user__username__icontains = word) + | Q(cofprofile__user__first_name__icontains = word) + | Q(cofprofile__user__last_name__icontains = word) + ) queries['users_cof'] = queries['users_cof'].filter( - Q(username__icontains = word) - | Q(first_name__icontains = word) - | Q(last_name__icontains = word) - ) + Q(username__icontains = word) + | Q(first_name__icontains = word) + | Q(last_name__icontains = word) + ) queries['users_notcof'] = queries['users_notcof'].filter( - Q(username__icontains = word) - | Q(first_name__icontains = word) - | Q(last_name__icontains = word) - ) - queries['clippers'] = queries['clippers'].filter( - Q(username__icontains = word) - | Q(fullname__icontains = word) - ) + Q(username__icontains = word) + | Q(first_name__icontains = word) + | Q(last_name__icontains = word) + ) + # Clearing redundancies queries['kfet'] = queries['kfet'].distinct() - - usernames = list( \ + usernames = list( queries['kfet'].values_list('cofprofile__user__username', flat=True)) + queries['kfet'] = [ + (account, account.cofprofile.user) + for account in queries['kfet'] + ] - queries['kfet'] = [ (account, account.cofprofile.user) \ - for account in queries['kfet'] ] - - queries['users_cof'] = \ + queries['users_cof'] = \ queries['users_cof'].exclude(username__in=usernames).distinct() - queries['users_notcof'] = \ + queries['users_notcof'] = \ queries['users_notcof'].exclude(username__in=usernames).distinct() - - usernames += list( \ + usernames += list( queries['users_cof'].values_list('username', flat=True)) - usernames += list( \ + usernames += list( queries['users_notcof'].values_list('username', flat=True)) - queries['clippers'] = \ - queries['clippers'].exclude(username__in=usernames).distinct() + # Fetching data from the SPI + if hasattr(settings, 'LDAP_SERVER_URL'): + # Fetching + ldap_query = '(|{:s})'.format(''.join( + ['(cn=*{:s}*)'.format(bit) for bit in bits] + )) + with Connection(settings.LDAP_SERVER_URL) as conn: + queries['clippers'] = conn.search( + 'dc=spi,dc=ens,dc=fr', ldap_query, + attributes=['uid', 'cn'] + ) + # Clearing redundancies + queries['clippers'] = [ + {'clipper': clipper.uid, 'fullname': clipper.cn} + for clipper in queries['clippers'] + if clipper.uid not in usernames + ] + # Resulting data data.update(queries) - - options = 0 - for query in queries.values(): - options += len(query) - data['options'] = options + data['options'] = sum([len(query) for query in queries]) return render(request, "kfet/account_create_autocomplete.html", data) diff --git a/kfet/templates/kfet/account_create_autocomplete.html b/kfet/templates/kfet/account_create_autocomplete.html index 1185c3a8..2f326801 100644 --- a/kfet/templates/kfet/account_create_autocomplete.html +++ b/kfet/templates/kfet/account_create_autocomplete.html @@ -36,7 +36,7 @@
  • Utilisateurs clipper
  • {% for clipper in clippers %}
  • - + {{ clipper|highlight_clipper:q }}
  • diff --git a/kfet/urls.py b/kfet/urls.py index 9b9ebf21..d54349d4 100644 --- a/kfet/urls.py +++ b/kfet/urls.py @@ -35,7 +35,8 @@ urlpatterns = [ name = 'kfet.account.create_special'), url(r'^accounts/new/user/(?P.+)$', views.account_create_ajax, name = 'kfet.account.create.fromuser'), - url(r'^accounts/new/clipper/(?P.+)$', views.account_create_ajax, + url(r'^accounts/new/clipper/(?P[\w-]+)/(?P.*)$', + views.account_create_ajax, name = 'kfet.account.create.fromclipper'), url(r'^accounts/new/empty$', views.account_create_ajax, name = 'kfet.account.create.empty'), diff --git a/kfet/views.py b/kfet/views.py index 3f1e1f4d..df7d5821 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -22,7 +22,7 @@ from django.db.models import F, Sum, Prefetch, Count, Func from django.db.models.functions import Coalesce from django.utils import timezone from django.utils.crypto import get_random_string -from gestioncof.models import CofProfile, Clipper +from gestioncof.models import CofProfile from kfet.decorators import teamkfet_required from kfet.models import (Account, Checkout, Article, Settings, AccountNegative, CheckoutStatement, GenericTeamToken, Supplier, SupplierArticle, Inventory, @@ -216,19 +216,20 @@ def account_form_set_readonly_fields(user_form, cof_form): cof_form.fields['login_clipper'].widget.attrs['readonly'] = True cof_form.fields['is_cof'].widget.attrs['disabled'] = True -def get_account_create_forms(request=None, username=None, login_clipper=None): +def get_account_create_forms(request=None, username=None, login_clipper=None, + fullname=None): user = None - clipper = None + clipper = False if login_clipper and (login_clipper == username or not username): # à partir d'un clipper # le user associé à ce clipper ne devrait pas encore exister - clipper = get_object_or_404(Clipper, username = login_clipper) + clipper = True try: # Vérification que clipper ne soit pas déjà dans User user = User.objects.get(username=login_clipper) # Ici, on nous a menti, le user existe déjà username = user.username - clipper = None + clipper = False except User.DoesNotExist: # Clipper (sans user déjà existant) @@ -236,9 +237,9 @@ def get_account_create_forms(request=None, username=None, login_clipper=None): user_initial = { 'username' : login_clipper, 'email' : "%s@clipper.ens.fr" % login_clipper} - if clipper.fullname: + if fullname: # Prefill du nom et prénom - names = clipper.fullname.split() + names = fullname.split() # Le premier, c'est le prénom user_initial['first_name'] = names[0] if len(names) > 1: @@ -302,8 +303,11 @@ def get_account_create_forms(request=None, username=None, login_clipper=None): @login_required @teamkfet_required -def account_create_ajax(request, username=None, login_clipper=None): - forms = get_account_create_forms(request=None, username=username, login_clipper=login_clipper) +def account_create_ajax(request, username=None, login_clipper=None, + fullname=None): + forms = get_account_create_forms( + request=None, username=username, login_clipper=login_clipper, + fullname=fullname) return render(request, "kfet/account_create_form.html", { 'account_form' : forms['account_form'], 'cof_form' : forms['cof_form'], diff --git a/requirements.txt b/requirements.txt index f7f6deca..6f7155e0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,3 +18,4 @@ git+https://github.com/Aureplop/channels.git#egg=channel statistics==1.0.3.5 future==0.15.2 django-widget-tweaks==1.4.1 +ldap3