Fabs 10 years ago
parent
commit
7e69b2f289

+ 34 - 33
coin/members/admin.py

@@ -35,53 +35,53 @@ class MemberAdmin(UserAdmin):
     add_form = MemberCreationForm
 
     fieldsets = (
-            ('Adhérent', {'fields':(
-                'status',
-                'type',   
+        ('Adhérent', {'fields': (
+            'status',
+            'type',
                 ('first_name', 'last_name', 'organization_name'),
                 ('entry_date', 'resign_date'))}),
-            ('Coordonnées', {'fields':(
-                'email', 
-                ('home_phone_number', 'mobile_phone_number'),
-                'address',
-                ('postal_code', 'city', 'country'))}),
-            ('Authentification', {'fields':(
-                ('username','password'))}),
-            ('Permissions', {'fields':(
-                ('is_active', 'is_staff', 'is_superuser'))})
-            )
+        ('Coordonnées', {'fields': (
+            'email',
+            ('home_phone_number', 'mobile_phone_number'),
+            'address',
+            ('postal_code', 'city', 'country'))}),
+        ('Authentification', {'fields': (
+            ('username', 'password'))}),
+        ('Permissions', {'fields': (
+            ('is_active', 'is_staff', 'is_superuser'))})
+    )
 
     add_fieldsets = (
-            ('Adhérent', {'fields':(
-                'status',
-                'type',   
-                ('first_name', 'last_name', 'organization_name'),
-                ('entry_date', 'resign_date'))}),
-            ('Coordonnées', {'fields':(
-                'email', 
-                ('home_phone_number', 'mobile_phone_number'),
-                'address',
-                ('postal_code', 'city', 'country'))}),
-            ('Authentification', {'fields':(
-                ('username', 'password'),)}),
-            ('Permissions', {'fields':(
-                ('is_active', 'is_staff', 'is_superuser', 'date_joined'))})
-            )
-
+        ('Adhérent', {'fields': (
+            'status',
+            'type',
+            ('first_name', 'last_name', 'organization_name'),
+            ('entry_date', 'resign_date'))}),
+        ('Coordonnées', {'fields': (
+            'email',
+            ('home_phone_number', 'mobile_phone_number'),
+            'address',
+            ('postal_code', 'city', 'country'))}),
+        ('Authentification', {'fields': (
+            ('username', 'password'),)}),
+        ('Permissions', {'fields': (
+            ('is_active', 'is_staff', 'is_superuser', 'date_joined'))})
+    )
 
     radio_fields = {"type": admin.HORIZONTAL}
 
     save_on_top = True
 
     inlines = [CryptoKeyInline, MembershipFeeInline]
-    
+
     def get_readonly_fields(self, request, obj=None):
         if obj:
-            # Remove help_text for readonly field (can't do that in the Form 
+            # Remove help_text for readonly field (can't do that in the Form
             # django seems to user help_text from model for readonly fields)
-            username_field = [f for f in obj._meta.fields if f.name == 'username']
+            username_field = [
+                f for f in obj._meta.fields if f.name == 'username']
             username_field[0].help_text = ''
-            return ['username',]
+            return ['username', ]
         else:
             return []
 
@@ -99,6 +99,7 @@ class MemberAdmin(UserAdmin):
             '%d membre(s) définis comme non adhérent(s).' % rows_updated)
     set_as_non_member.short_description = "Définir comme non adhérent"
 
+
 class MembershipFeeAdmin(admin.ModelAdmin):
     list_display = ('member', 'end_date', 'amount')
     form = autocomplete_light.modelform_factory(MembershipFee)

+ 8 - 6
coin/members/autocomplete_light_registry.py

@@ -6,9 +6,11 @@ from models import Member
 
 # This will generate a MemberAutocomplete class
 autocomplete_light.register(Member,
-    # Just like in ModelAdmin.search_fields
-    search_fields=['^first_name', 'last_name', 'organization_name'],
-    # This will actually data-minimum-characters which will set
-    # widget.autocomplete.minimumCharacters.
-    autocomplete_js_attributes={'placeholder': 'Other model name ?',},
-)
+                            # Just like in ModelAdmin.search_fields
+                            search_fields=[
+                                '^first_name', 'last_name', 'organization_name'],
+                            # This will actually data-minimum-characters which
+                            # will set widget.autocomplete.minimumCharacters.
+                            autocomplete_js_attributes={
+                                'placeholder': 'Other model name ?', },
+                            )

+ 7 - 4
coin/members/forms.py

@@ -8,15 +8,17 @@ from coin.members.models import Member
 
 
 class MemberCreationForm(forms.ModelForm):
+
     """
     This form was inspired from django.contrib.auth.forms.UserCreationForm
     and adapted to coin specificities
     """
     username = forms.RegexField(required=False,
-        label="Nom d'utilisateur", max_length=30, regex=r"^[\w.@+-]+$",
-        help_text="Laisser vide pour le générer automatiquement à partir du "
-                  "nom et du prénom")
-    password = forms.CharField(required=False, label='Mot de passe', widget=forms.PasswordInput)
+                                label="Nom d'utilisateur", max_length=30, regex=r"^[\w.@+-]+$",
+                                help_text="Laisser vide pour le générer automatiquement à partir du "
+                                "nom et du prénom")
+    password = forms.CharField(
+        required=False, label='Mot de passe', widget=forms.PasswordInput)
 
     class Meta:
         model = Member
@@ -34,6 +36,7 @@ class MemberCreationForm(forms.ModelForm):
 
 
 class MemberChangeForm(forms.ModelForm):
+
     """
     This form was inspired from django.contrib.auth.forms.UserChangeForm
     and adapted to coin specificities

+ 29 - 24
coin/members/models.py

@@ -48,10 +48,11 @@ class Member(CoinLdapSyncMixin, AbstractUser):
                                            verbose_name='téléphone mobile')
     # TODO: use a django module that provides an address model? (would
     # support more countries and address types)
-    address = models.TextField(verbose_name='adresse postale', blank=True, null=True)
+    address = models.TextField(
+        verbose_name='adresse postale', blank=True, null=True)
     postal_code = models.CharField(max_length=5, blank=True, null=True,
                                    validators=[RegexValidator(regex=r'^\d{5}$',
-                                               message='Code postal non valide.')],
+                                                              message='Code postal non valide.')],
                                    verbose_name='code postal')
     city = models.CharField(max_length=200, blank=True, null=True,
                             verbose_name='commune')
@@ -70,14 +71,14 @@ class Member(CoinLdapSyncMixin, AbstractUser):
 
     # Following fields are managed by the parent class AbstractUser :
     # username, first_name, last_name, email
-    # However we hack the model to force theses fields to be required. (see below)
-    
+    # However we hack the model to force theses fields to be required. (see
+    # below)
+
     # This property is used to change password in LDAP. Used in sync_to_ldap.
     # Should not be defined manually. Prefer use set_password method that hash
     # passwords for both ldap and local db
     _password_ldap = None
 
-
     def __unicode__(self):
         name = self.first_name + ' ' + self.last_name
         if self.organization_name:
@@ -94,7 +95,7 @@ class Member(CoinLdapSyncMixin, AbstractUser):
     def end_date_of_membership(self):
         try:
             return self.membership_fees.order_by('-end_date')[0].end_date
-        #TODO: bad practice de tout matcher comme ca
+        # TODO: bad practice de tout matcher comme ca
         except:
             return None
 
@@ -114,7 +115,7 @@ class Member(CoinLdapSyncMixin, AbstractUser):
         """
         super(Member, self).set_password(new_password, *args, **kwargs)
         self._password_ldap = utils.ldap_hash(new_password)
-        
+
     def get_active_subscriptions(self, date=datetime.date.today()):
         """
         Return list of OfferSubscription which are active today
@@ -162,7 +163,7 @@ class Member(CoinLdapSyncMixin, AbstractUser):
 
         # Fail if no username specified
         assert self.username, ('Can\'t sync with LDAP because missing username '
-                              'value for the Member : %s' % self)
+                               'value for the Member : %s' % self)
 
         # If try to sync a superuser in creation mode
         # Try to retrieve the user in ldap. If exists, switch to update mode
@@ -179,7 +180,8 @@ class Member(CoinLdapSyncMixin, AbstractUser):
             ldap_user = LdapUser.objects.get(pk=self.username)
 
         if creation:
-            max_uid_number = LdapUser.objects.order_by('-uidNumber')[0].uidNumber
+            max_uid_number = LdapUser.objects.order_by(
+                '-uidNumber')[0].uidNumber
             ldap_user = LdapUser()
             ldap_user.pk = self.username
             ldap_user.uid = self.username
@@ -188,7 +190,7 @@ class Member(CoinLdapSyncMixin, AbstractUser):
 
         ldap_user.last_name = self.last_name
         ldap_user.first_name = self.first_name
-        
+
         # If a password is definied in _password_ldap, change it in LDAP
         if self._password_ldap:
             # Make sure password is hashed
@@ -206,9 +208,9 @@ class Member(CoinLdapSyncMixin, AbstractUser):
         Delete member from the LDAP
         """
         assert self.username, ('Can\'t delete from LDAP because missing '
-                              'username value for the Member : %s' % self)
+                               'username value for the Member : %s' % self)
 
-        #Delete user from LDAP
+        # Delete user from LDAP
         ldap_user = LdapUser.objects.get(pk=self.username)
         ldap_user.delete()
 
@@ -252,7 +254,7 @@ class CryptoKey(models.Model):
 class MembershipFee(models.Model):
     member = models.ForeignKey('Member', related_name='membership_fees',
                                verbose_name='membre')
-    #TODO: config: valeur par défaut à externaliser dans la configuration
+    # TODO: config: valeur par défaut à externaliser dans la configuration
     amount = models.IntegerField(null=False, default='20', help_text='en €',
                                  verbose_name='montant')
     start_date = models.DateField(
@@ -274,7 +276,8 @@ class MembershipFee(models.Model):
 
 
 class LdapUser(ldapdb.models.Model):
-    base_dn = settings.LDAP_USER_BASE_DN #"ou=users,ou=unix,o=ILLYSE,l=Villeurbanne,st=RHA,c=FR"
+    # "ou=users,ou=unix,o=ILLYSE,l=Villeurbanne,st=RHA,c=FR"
+    base_dn = settings.LDAP_USER_BASE_DN
     object_classes = [b'inetOrgPerson', b'organizationalPerson', b'person',
                       b'top', b'posixAccount']
 
@@ -298,19 +301,20 @@ class LdapUser(ldapdb.models.Model):
         managed = False  # Indique à Django de ne pas intégrer ce model en base
 
 
-class LdapGroup(ldapdb.models.Model):
-    base_dn = settings.LDAP_GROUP_BASE_DN #"ou=groups,ou=unix,o=ILLYSE,l=Villeurbanne,st=RHA,c=FR"
-    object_classes = [b'posixGroup']
+# class LdapGroup(ldapdb.models.Model):
+# "ou=groups,ou=unix,o=ILLYSE,l=Villeurbanne,st=RHA,c=FR"
+#     base_dn = settings.LDAP_GROUP_BASE_DN
+#     object_classes = [b'posixGroup']
 
-    gid = IntegerField(db_column=b'gidNumber', unique=True)
-    name = CharField(db_column=b'cn', max_length=200, primary_key=True)
-    members = ListField(db_column=b'memberUid')
+#     gid = IntegerField(db_column=b'gidNumber', unique=True)
+#     name = CharField(db_column=b'cn', max_length=200, primary_key=True)
+#     members = ListField(db_column=b'memberUid')
 
-    def __unicode__(self):
-        return self.name
+#     def __unicode__(self):
+#         return self.name
 
-    class Meta:
-        managed = False  # Indique à Django de ne pas intégrer ce model en base
+#     class Meta:
+# managed = False  # Indique à Django de ne pas intégrer ce model en base
 
 
 @receiver(pre_save, sender=Member)
@@ -322,6 +326,7 @@ def define_username(sender, instance, **kwargs):
     if not instance.username and not instance.pk:
         instance.username = instance.get_automatic_username()
 
+
 @receiver(pre_save, sender=LdapUser)
 def define_display_name(sender, instance, **kwargs):
     """

+ 31 - 32
coin/members/tests.py

@@ -41,7 +41,6 @@ class MemberTests(TestCase):
 
         member.delete()
 
-
     def test_when_modifiying_member_corresponding_ldap_user_is_also_modified_with_same_data(self):
         """
         Test que lorsque l'on modifie un membre, l'utilisateur LDAP
@@ -77,20 +76,20 @@ class MemberTests(TestCase):
     #     Et que lors de la supression d'un membre, l'utilisateur LDAP correspondant
     #     est bien retiré du groupe.
     #     """
-    #     #~ Créé un membre
+    # ~ Créé un membre
     #     username = MemberTestsUtils.get_random_username()
     #     member = Member(first_name='Canard',
     #                     last_name='WC', username=username)
     #     member.save()
 
-    #     #~ Récupère le group "coin" et test que l'utilisateur y est présent
+    # ~ Récupère le group "coin" et test que l'utilisateur y est présent
     #     ldap_group = LdapGroup.objects.get(pk="coin")
     #     self.assertEqual(username in ldap_group.members, True)
 
-    #     #~ Supprime l'utilisateur
+    # ~ Supprime l'utilisateur
     #     member.delete()
 
-    #     #~ Récupère le group "coin" et test que l'utilisateur n'y est plus
+    # ~ Récupère le group "coin" et test que l'utilisateur n'y est plus
     #     ldap_group = LdapGroup.objects.get(pk="coin")
     #     self.assertEqual(username in ldap_group.members, False)
 
@@ -104,7 +103,7 @@ class MemberTests(TestCase):
         username = MemberTestsUtils.get_random_username()
         password = "1234"
 
-         #~ Créé un nouveau membre
+        #~ Créé un nouveau membre
         member = Member(first_name='Passe-partout',
                         last_name='Du fort Boyard', username=username)
         member.save()
@@ -139,7 +138,6 @@ class MemberTests(TestCase):
 
         member.delete()
 
-
     def test_when_creating_member_ldap_display_name_is_well_defined(self):
         """
         Lors de la création d'un membre, le champ "display_name" du LDAP est
@@ -160,7 +158,6 @@ class MemberTests(TestCase):
 
         member.delete()
 
-
     def test_when_creating_member_username_is_well_defined(self):
         """
         Lors de la création d'un membre, le champ "username", s'il n'est pas
@@ -182,7 +179,6 @@ class MemberTests(TestCase):
 
         member.delete()
 
-
     def test_when_saving_member_and_ldap_fail_dont_save(self):
         """
         Test que lors de la sauvegarde d'un membre et que la sauvegarde en LDAP
@@ -193,7 +189,8 @@ class MemberTests(TestCase):
         for dbconnection in db.connections.all():
             if (type(dbconnection) is
                     ldapdb.backends.ldap.base.DatabaseWrapper):
-                dbconnection.settings_dict['PREVIOUSPASSWORD'] = dbconnection.settings_dict['PASSWORD']
+                dbconnection.settings_dict[
+                    'PREVIOUSPASSWORD'] = dbconnection.settings_dict['PASSWORD']
                 dbconnection.settings_dict['PASSWORD'] = 'wrong password test'
 
         # Créé un membre
@@ -215,14 +212,15 @@ class MemberTests(TestCase):
         for dbconnection in db.connections.all():
             if (type(dbconnection) is
                     ldapdb.backends.ldap.base.DatabaseWrapper):
-                dbconnection.settings_dict['PASSWORD'] = dbconnection.settings_dict['PREVIOUSPASSWORD']
+                dbconnection.settings_dict[
+                    'PASSWORD'] = dbconnection.settings_dict['PREVIOUSPASSWORD']
 
     # def test_when_user_login_member_user_field_is_updated(self):
     #     """
     #     Test que lorqu'un utilisateur se connect, le champ user du membre
     #     correspondant est mis à jour convenablement
     #     """
-    #     # Créé un membre
+    # Créé un membre
     #     first_name = 'Du'
     #     last_name = 'Pond'
     #     password = '1234'
@@ -232,14 +230,14 @@ class MemberTests(TestCase):
     #     member.save()
     #     member.change_password(password)
 
-    #     # Vérifie que user non définit
+    # Vérifie que user non définit
     #     self.assertIsNone(member.user)
 
-    #     # Connection
+    # Connection
     #     c = Client()
     #     self.assertEqual(c.login(username=username, password=password), True)
 
-    #     # Vérifie que user définit
+    # Vérifie que user définit
     #     member = Member.objects.get(username=username)
     #     self.assertIsNotNone(member.user)
 
@@ -249,7 +247,7 @@ class MemberTests(TestCase):
         """
         Test que end_date_of_membership d'un membre envoi bien la date de fin d'adhésion
         """
-        #Créer un membre
+        # Créer un membre
         first_name = 'Tin'
         last_name = 'Tin'
         username = MemberTestsUtils.get_random_username()
@@ -260,20 +258,19 @@ class MemberTests(TestCase):
         start_date = datetime.date.today()
         end_date = start_date + datetime.timedelta(365)
 
-        #Créé une cotisation
+        # Créé une cotisation
         membershipfee = MembershipFee(member=member, amount=20,
-            start_date=start_date,
-            end_date=end_date)
+                                      start_date=start_date,
+                                      end_date=end_date)
         membershipfee.save()
 
         self.assertEqual(member.end_date_of_membership(), end_date)
 
-
     def test_member_is_paid_up(self):
         """
         Test que end_date_of_membership d'un membre envoi bien la date de fin d'adhésion
         """
-        #Créé un membre
+        # Créé un membre
         first_name = 'Capitain'
         last_name = 'Haddock'
         username = MemberTestsUtils.get_random_username()
@@ -287,19 +284,21 @@ class MemberTests(TestCase):
         # Test qu'un membre sans cotisation n'est pas à jour
         self.assertEqual(member.is_paid_up(), False)
 
-        #Créé une cotisation passée
+        # Créé une cotisation passée
         membershipfee = MembershipFee(member=member, amount=20,
-            start_date=datetime.date.today() - datetime.timedelta(365),
-            end_date=datetime.date.today() - datetime.timedelta(10))
+                                      start_date=datetime.date.today() -
+                                      datetime.timedelta(365),
+                                      end_date=datetime.date.today() - datetime.timedelta(10))
         membershipfee.save()
         # La cotisation s'étant terminée il y a 10 jours, il ne devrait pas
         # être à jour de cotistion
         self.assertEqual(member.is_paid_up(), False)
 
-        #Créé une cotisation actuelle
+        # Créé une cotisation actuelle
         membershipfee = MembershipFee(member=member, amount=20,
-            start_date=datetime.date.today() - datetime.timedelta(10),
-            end_date=datetime.date.today() + datetime.timedelta(10))
+                                      start_date=datetime.date.today() -
+                                      datetime.timedelta(10),
+                                      end_date=datetime.date.today() + datetime.timedelta(10))
         membershipfee.save()
         # La cotisation se terminant dans 10 jour, il devrait être à jour
         # de cotisation
@@ -314,15 +313,15 @@ class MemberAdminTests(TestCase):
         #~ Créé un superuser
         self.admin_user_password = '1234'
         self.admin_user = Member.objects.create_superuser(
-            username = 'test_admin_user',
-            first_name = 'test',
-            last_name = 'Admin user',
+            username='test_admin_user',
+            first_name='test',
+            last_name='Admin user',
             email='i@mail.com',
             password=self.admin_user_password)
         #~ Connection
         self.assertEqual(self.client.login(
             username=self.admin_user.username, password=self.admin_user_password), True)
-    
+
     def tearDown(self):
         # Supprime le superuser
         self.admin_user.delete()
@@ -342,7 +341,7 @@ class MemberAdminTests(TestCase):
 
         edit_page = self.client.get('/admin/members/member/%i/' % member.id)
         self.assertNotContains(edit_page,
-            '''<input id="id_username" />''',
+                               '''<input id="id_username" />''',
                                html=True)
 
         member.delete()

+ 26 - 26
coin/members/urls.py

@@ -12,43 +12,43 @@ urlpatterns = patterns(
     url(r'^$', views.index, name='index'),
     url(r'^login/$', 'django.contrib.auth.views.login',
         {'template_name': 'members/registration/login.html'},
-        name = 'login'),
+        name='login'),
     url(r'^logout/$', 'django.contrib.auth.views.logout_then_login',
-        name = 'logout'),
-    
-    url(r'^password_change/$', 'django.contrib.auth.views.password_change', 
-        {'post_change_redirect':'members:password_change_done',
-        'template_name':'members/registration/password_change_form.html'},
-        name = 'password_change'),
+        name='logout'),
+
+    url(r'^password_change/$', 'django.contrib.auth.views.password_change',
+        {'post_change_redirect': 'members:password_change_done',
+         'template_name': 'members/registration/password_change_form.html'},
+        name='password_change'),
     url(r'^password_change_done/$', 'django.contrib.auth.views.password_change_done',
-        {'template_name':'members/registration/password_change_done.html'},
-        name = 'password_change_done'),
+        {'template_name': 'members/registration/password_change_done.html'},
+        name='password_change_done'),
 
     url(r'^password_reset/$', 'django.contrib.auth.views.password_reset',
-        {'post_reset_redirect':'members:password_reset_done',
-        'template_name':'members/registration/password_reset_form.html',
-        'email_template_name':'members/registration/password_reset_email.html',
-        'subject_template_name':'members/registration/password_reset_subject.txt'},
-        name = 'password_reset'),
+        {'post_reset_redirect': 'members:password_reset_done',
+         'template_name': 'members/registration/password_reset_form.html',
+         'email_template_name': 'members/registration/password_reset_email.html',
+         'subject_template_name': 'members/registration/password_reset_subject.txt'},
+        name='password_reset'),
     url(r'^password_reset/done/$', 'django.contrib.auth.views.password_reset_done',
-        {'template_name':'members/registration/password_reset_done.html',
-        'current_app':'members'},
-        name = 'password_reset_done'),
+        {'template_name': 'members/registration/password_reset_done.html',
+         'current_app': 'members'},
+        name='password_reset_done'),
     url(r'^password_reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', 'django.contrib.auth.views.password_reset_confirm',
-        {'post_reset_redirect':'members:password_reset_complete',
-        'template_name':'members/registration/password_reset_confirm.html'},
-        name = 'password_reset_confirm'),
+        {'post_reset_redirect': 'members:password_reset_complete',
+         'template_name': 'members/registration/password_reset_confirm.html'},
+        name='password_reset_confirm'),
     url(r'^password_reset/complete/$', 'django.contrib.auth.views.password_reset_complete',
-        {'template_name':'members/registration/password_reset_complete.html'},
-        name = 'password_reset_complete'),
-        
+        {'template_name': 'members/registration/password_reset_complete.html'},
+        name='password_reset_complete'),
+
 
-    url(r'^detail/$',views.detail,
+    url(r'^detail/$', views.detail,
         name='detail'),
 
-    url(r'^subscriptions/', views.subscriptions, name = 'subscriptions'),
+    url(r'^subscriptions/', views.subscriptions, name='subscriptions'),
     # url(r'^subscription/(?P<id>\d+)', views.subscriptions, name = 'subscription'),
 
-    url(r'^invoices/', views.invoices, name = 'invoices'),
+    url(r'^invoices/', views.invoices, name='invoices'),
     url(r'^contact/', views.contact, name='contact')
 )

+ 5 - 2
coin/members/views.py

@@ -18,22 +18,25 @@ def detail(request):
     return render_to_response('members/detail.html',
                               context_instance=RequestContext(request))
 
+
 @login_required
 def subscriptions(request):
     subscriptions = request.user.get_active_subscriptions()
 
     return render_to_response('members/subscriptions.html',
-                              {'subscriptions':subscriptions},
+                              {'subscriptions': subscriptions},
                               context_instance=RequestContext(request))
 
+
 @login_required
 def invoices(request):
     invoices = request.user.invoices.all().order_by('-date')
 
     return render_to_response('members/invoices.html',
-                              {'invoices':invoices},
+                              {'invoices': invoices},
                               context_instance=RequestContext(request))
 
+
 @login_required
 def contact(request):
     return render_to_response('members/contact.html',