mirror of
				https://github.com/ae-utbm/sith.git
				synced 2025-11-04 02:53:06 +00:00 
			
		
		
		
	Merge branch 'clubs' into 'master'
Améliore la gestion de membres de clubs See merge request ae/Sith!196
This commit is contained in:
		@@ -276,18 +276,6 @@ class Membership(models.Model):
 | 
				
			|||||||
        _("description"), max_length=128, null=False, blank=True
 | 
					        _("description"), max_length=128, null=False, blank=True
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def clean(self):
 | 
					 | 
				
			||||||
        sub = User.objects.filter(pk=self.user.pk).first()
 | 
					 | 
				
			||||||
        if sub is None or not sub.is_subscribed:
 | 
					 | 
				
			||||||
            raise ValidationError(_("User must be subscriber to take part to a club"))
 | 
					 | 
				
			||||||
        if (
 | 
					 | 
				
			||||||
            Membership.objects.filter(user=self.user)
 | 
					 | 
				
			||||||
            .filter(club=self.club)
 | 
					 | 
				
			||||||
            .filter(end_date=None)
 | 
					 | 
				
			||||||
            .exists()
 | 
					 | 
				
			||||||
        ):
 | 
					 | 
				
			||||||
            raise ValidationError(_("User is already member of that club"))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __str__(self):
 | 
					    def __str__(self):
 | 
				
			||||||
        return (
 | 
					        return (
 | 
				
			||||||
            self.club.name
 | 
					            self.club.name
 | 
				
			||||||
@@ -304,12 +292,15 @@ class Membership(models.Model):
 | 
				
			|||||||
        """
 | 
					        """
 | 
				
			||||||
        return user.is_in_group(settings.SITH_MAIN_BOARD_GROUP)
 | 
					        return user.is_in_group(settings.SITH_MAIN_BOARD_GROUP)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def can_be_edited_by(self, user):
 | 
					    def can_be_edited_by(self, user, membership=None):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Method to see if that object can be edited by the given user
 | 
					        Method to see if that object can be edited by the given user
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        if user.memberships:
 | 
					        if user.memberships:
 | 
				
			||||||
            ms = user.memberships.filter(club=self.club, end_date=None).first()
 | 
					            if membership:  # This is for optimisation purpose
 | 
				
			||||||
 | 
					                ms = membership
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                ms = user.memberships.filter(club=self.club, end_date=None).first()
 | 
				
			||||||
            return (ms and ms.role >= self.role) or user.is_in_group(
 | 
					            return (ms and ms.role >= self.role) or user.is_in_group(
 | 
				
			||||||
                settings.SITH_MAIN_BOARD_GROUP
 | 
					                settings.SITH_MAIN_BOARD_GROUP
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,35 +1,80 @@
 | 
				
			|||||||
{% extends "core/base.jinja" %}
 | 
					{% extends "core/base.jinja" %}
 | 
				
			||||||
{% from 'core/macros.jinja' import user_profile_link %}
 | 
					{% from 'core/macros.jinja' import user_profile_link, select_all_checkbox %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block content %}
 | 
					{% block content %}
 | 
				
			||||||
    <h2>{% trans %}Club members{% endtrans %}</h2>
 | 
					    <h2>{% trans %}Club members{% endtrans %}</h2>
 | 
				
			||||||
    <table>
 | 
					    {% if members %}
 | 
				
			||||||
        <thead>
 | 
					    <form action="{{ url('club:club_members', club_id=club.id) }}" id="users_old" method="post">
 | 
				
			||||||
            <td>{% trans %}User{% endtrans %}</td>
 | 
					 | 
				
			||||||
            <td>{% trans %}Role{% endtrans %}</td>
 | 
					 | 
				
			||||||
            <td>{% trans %}Description{% endtrans %}</td>
 | 
					 | 
				
			||||||
            <td>{% trans %}Since{% endtrans %}</td>
 | 
					 | 
				
			||||||
        </thead>
 | 
					 | 
				
			||||||
        <tbody>
 | 
					 | 
				
			||||||
        {% for m in club.members.filter(end_date=None).order_by('-role').all() %}
 | 
					 | 
				
			||||||
            <tr>
 | 
					 | 
				
			||||||
                <td>{{ user_profile_link(m.user) }}</td>
 | 
					 | 
				
			||||||
                <td>{{ settings.SITH_CLUB_ROLES[m.role] }}</td>
 | 
					 | 
				
			||||||
                <td>{{ m.description }}</td>
 | 
					 | 
				
			||||||
                <td>{{ m.start_date }}</td>
 | 
					 | 
				
			||||||
                {% if m.can_be_edited_by(user) %}
 | 
					 | 
				
			||||||
                <td><a href="{{ url('club:membership_set_old', membership_id=m.id) }}">{% trans %}Mark as old{% endtrans %}</a></td>
 | 
					 | 
				
			||||||
                {% endif %}
 | 
					 | 
				
			||||||
            </tr>
 | 
					 | 
				
			||||||
        {% endfor %}
 | 
					 | 
				
			||||||
        </tbody>
 | 
					 | 
				
			||||||
    </table>
 | 
					 | 
				
			||||||
    <form action="{{ url('club:club_members', club_id=club.id) }}" method="post">
 | 
					 | 
				
			||||||
        {% csrf_token %}
 | 
					        {% csrf_token %}
 | 
				
			||||||
        {{ form.as_p() }}
 | 
					        {% set users_old = dict(form.users_old | groupby("choice_label")) %}
 | 
				
			||||||
 | 
					        {% if users_old %}
 | 
				
			||||||
 | 
					            {{ select_all_checkbox("users_old") }}
 | 
				
			||||||
 | 
					            <p></p>
 | 
				
			||||||
 | 
					        {% endif %}
 | 
				
			||||||
 | 
					        <table>
 | 
				
			||||||
 | 
					            <thead>
 | 
				
			||||||
 | 
					                <td>{% trans %}User{% endtrans %}</td>
 | 
				
			||||||
 | 
					                <td>{% trans %}Role{% endtrans %}</td>
 | 
				
			||||||
 | 
					                <td>{% trans %}Description{% endtrans %}</td>
 | 
				
			||||||
 | 
					                <td>{% trans %}Since{% endtrans %}</td>
 | 
				
			||||||
 | 
					                {% if users_old %}
 | 
				
			||||||
 | 
					                    <td>{% trans %}Mark as old{% endtrans %}</td>
 | 
				
			||||||
 | 
					                {% endif %}
 | 
				
			||||||
 | 
					            </thead>
 | 
				
			||||||
 | 
					            <tbody>
 | 
				
			||||||
 | 
					            {% for m in members %}
 | 
				
			||||||
 | 
					                <tr>
 | 
				
			||||||
 | 
					                    <td>{{ user_profile_link(m.user) }}</td>
 | 
				
			||||||
 | 
					                    <td>{{ settings.SITH_CLUB_ROLES[m.role] }}</td>
 | 
				
			||||||
 | 
					                    <td>{{ m.description }}</td>
 | 
				
			||||||
 | 
					                    <td>{{ m.start_date }}</td>
 | 
				
			||||||
 | 
					                    {% if users_old %}
 | 
				
			||||||
 | 
					                        <td>
 | 
				
			||||||
 | 
					                        {% set user_old = users_old[m.user.get_display_name()] %}
 | 
				
			||||||
 | 
					                        {% if user_old %}
 | 
				
			||||||
 | 
					                            {{ user_old[0].tag() }}
 | 
				
			||||||
 | 
					                        {% endif %}
 | 
				
			||||||
 | 
					                        </td>
 | 
				
			||||||
 | 
					                    {% endif %}
 | 
				
			||||||
 | 
					                </tr>
 | 
				
			||||||
 | 
					            {% endfor %}
 | 
				
			||||||
 | 
					            </tbody>
 | 
				
			||||||
 | 
					        </table>
 | 
				
			||||||
 | 
					        {{ form.users_old.errors }}
 | 
				
			||||||
 | 
					        {% if users_old %}
 | 
				
			||||||
 | 
					            <p></p>
 | 
				
			||||||
 | 
					            <input type="submit" name="submit" value="{% trans %}Mark as old{% endtrans %}">
 | 
				
			||||||
 | 
					        {% endif %}
 | 
				
			||||||
 | 
					    </form>
 | 
				
			||||||
 | 
					    {% else %}
 | 
				
			||||||
 | 
					    <p>{% trans %}There are no members in this club.{% endtrans %}</p>
 | 
				
			||||||
 | 
					    {% endif %}
 | 
				
			||||||
 | 
					    <form action="{{ url('club:club_members', club_id=club.id) }}" id="add_users" method="post">
 | 
				
			||||||
 | 
					        {% csrf_token %}
 | 
				
			||||||
 | 
					        {{ form.non_field_errors() }}
 | 
				
			||||||
 | 
					        <p>
 | 
				
			||||||
 | 
					            {{ form.users.errors }}
 | 
				
			||||||
 | 
					            <label for="{{ form.users.id_for_label }}">{{ form.users.label }} :</label>
 | 
				
			||||||
 | 
					            {{ form.users }}
 | 
				
			||||||
 | 
					            <span class="helptext">{{ form.users.help_text }}</span>
 | 
				
			||||||
 | 
					        </p>
 | 
				
			||||||
 | 
					        <p>
 | 
				
			||||||
 | 
					            {{ form.role.errors }}
 | 
				
			||||||
 | 
					            <label for="{{ form.role.id_for_label }}">{{ form.role.label }} :</label>
 | 
				
			||||||
 | 
					            {{ form.role }}
 | 
				
			||||||
 | 
					        </p>
 | 
				
			||||||
 | 
					        {% if form.start_date %}
 | 
				
			||||||
 | 
					        <p>
 | 
				
			||||||
 | 
					            {{ form.start_date.errors }}
 | 
				
			||||||
 | 
					            <label for="{{ form.start_date.id_for_label }}">{{ form.start_date.label }} :</label>
 | 
				
			||||||
 | 
					            {{ form.start_date }}
 | 
				
			||||||
 | 
					        </p>
 | 
				
			||||||
 | 
					        {% endif %}
 | 
				
			||||||
 | 
					        <p>
 | 
				
			||||||
 | 
					            {{ form.description.errors }}
 | 
				
			||||||
 | 
					            <label for="{{ form.description.id_for_label }}">{{ form.description.label }} :</label>
 | 
				
			||||||
 | 
					            {{ form.description }}
 | 
				
			||||||
 | 
					        </p>
 | 
				
			||||||
        <p><input type="submit" value="{% trans %}Add{% endtrans %}" /></p>
 | 
					        <p><input type="submit" value="{% trans %}Add{% endtrans %}" /></p>
 | 
				
			||||||
    </form>
 | 
					    </form>
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										269
									
								
								club/tests.py
									
									
									
									
									
								
							
							
						
						
									
										269
									
								
								club/tests.py
									
									
									
									
									
								
							@@ -44,30 +44,54 @@ class ClubTest(TestCase):
 | 
				
			|||||||
        self.client.login(username="root", password="plop")
 | 
					        self.client.login(username="root", password="plop")
 | 
				
			||||||
        self.client.post(
 | 
					        self.client.post(
 | 
				
			||||||
            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
            {"user": self.skia.id, "start_date": "12/06/2016", "role": 3},
 | 
					            {"users": self.skia.id, "start_date": "12/06/2016", "role": 3},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        response = self.client.get(
 | 
					        response = self.client.get(
 | 
				
			||||||
            reverse("club:club_members", kwargs={"club_id": self.bdf.id})
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id})
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        self.assertTrue(response.status_code == 200)
 | 
					        self.assertTrue(response.status_code == 200)
 | 
				
			||||||
        self.assertTrue(
 | 
					        self.assertTrue(
 | 
				
			||||||
            "S' Kia</a></td>\\n                <td>Responsable info</td>"
 | 
					            "S' Kia</a></td>\\n                    <td>Responsable info</td>"
 | 
				
			||||||
            in str(response.content)
 | 
					            in str(response.content)
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_create_add_multiple_user_to_club_from_root_ok(self):
 | 
				
			||||||
 | 
					        self.client.login(username="root", password="plop")
 | 
				
			||||||
 | 
					        self.client.post(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "users": "|%d|%d|" % (self.skia.id, self.rbatsbak.id),
 | 
				
			||||||
 | 
					                "start_date": "12/06/2016",
 | 
				
			||||||
 | 
					                "role": 3,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        response = self.client.get(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id})
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertTrue(response.status_code == 200)
 | 
				
			||||||
 | 
					        content = str(response.content)
 | 
				
			||||||
 | 
					        self.assertTrue(
 | 
				
			||||||
 | 
					            "S' Kia</a></td>\\n                    <td>Responsable info</td>"
 | 
				
			||||||
 | 
					            in content
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertTrue(
 | 
				
			||||||
 | 
					            "Richard Batsbak</a></td>\\n                    <td>Responsable info</td>"
 | 
				
			||||||
 | 
					            in content
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_create_add_user_to_club_from_root_fail_not_subscriber(self):
 | 
					    def test_create_add_user_to_club_from_root_fail_not_subscriber(self):
 | 
				
			||||||
        self.client.login(username="root", password="plop")
 | 
					        self.client.login(username="root", password="plop")
 | 
				
			||||||
        response = self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
            {"user": self.guy.id, "start_date": "12/06/2016", "role": 3},
 | 
					            {"users": self.guy.id, "start_date": "12/06/2016", "role": 3},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        self.assertTrue(response.status_code == 200)
 | 
					        self.assertTrue(response.status_code == 200)
 | 
				
			||||||
        self.assertTrue('<ul class="errorlist nonfield"><li>' in str(response.content))
 | 
					        self.assertTrue('<ul class="errorlist"><li>' in str(response.content))
 | 
				
			||||||
        response = self.client.get(
 | 
					        response = self.client.get(
 | 
				
			||||||
            reverse("club:club_members", kwargs={"club_id": self.bdf.id})
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id})
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        self.assertFalse(
 | 
					        self.assertFalse(
 | 
				
			||||||
            "Guy Carlier</a></td>\\n                <td>Responsable info</td>"
 | 
					            "Guy Carlier</a></td>\\n                    <td>Responsable info</td>"
 | 
				
			||||||
            in str(response.content)
 | 
					            in str(response.content)
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -75,18 +99,18 @@ class ClubTest(TestCase):
 | 
				
			|||||||
        self.client.login(username="root", password="plop")
 | 
					        self.client.login(username="root", password="plop")
 | 
				
			||||||
        self.client.post(
 | 
					        self.client.post(
 | 
				
			||||||
            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
            {"user": self.skia.id, "start_date": "12/06/2016", "role": 3},
 | 
					            {"users": self.skia.id, "start_date": "12/06/2016", "role": 3},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        response = self.client.get(
 | 
					        response = self.client.get(
 | 
				
			||||||
            reverse("club:club_members", kwargs={"club_id": self.bdf.id})
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id})
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        self.assertTrue(
 | 
					        self.assertTrue(
 | 
				
			||||||
            "S' Kia</a></td>\\n                <td>Responsable info</td>"
 | 
					            "S' Kia</a></td>\\n                    <td>Responsable info</td>"
 | 
				
			||||||
            in str(response.content)
 | 
					            in str(response.content)
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        response = self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
            {"user": self.skia.id, "start_date": "12/06/2016", "role": 4},
 | 
					            {"users": self.skia.id, "start_date": "12/06/2016", "role": 4},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        self.assertTrue(response.status_code == 200)
 | 
					        self.assertTrue(response.status_code == 200)
 | 
				
			||||||
        self.assertFalse(
 | 
					        self.assertFalse(
 | 
				
			||||||
@@ -94,23 +118,47 @@ class ClubTest(TestCase):
 | 
				
			|||||||
            in str(response.content)
 | 
					            in str(response.content)
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_create_add_user_non_existent_to_club_from_root_fail(self):
 | 
				
			||||||
 | 
					        self.client.login(username="root", password="plop")
 | 
				
			||||||
 | 
					        response = self.client.post(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
 | 
					            {"users": [9999], "start_date": "12/06/2016", "role": 3},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertTrue(response.status_code == 200)
 | 
				
			||||||
 | 
					        content = str(response.content)
 | 
				
			||||||
 | 
					        self.assertTrue('<ul class="errorlist"><li>' in content)
 | 
				
			||||||
 | 
					        self.assertFalse("<td>Responsable info</td>" in content)
 | 
				
			||||||
 | 
					        self.client.login(username="root", password="plop")
 | 
				
			||||||
 | 
					        response = self.client.post(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "users": "|%d|%d|" % (self.skia.id, 9999),
 | 
				
			||||||
 | 
					                "start_date": "12/06/2016",
 | 
				
			||||||
 | 
					                "role": 3,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertTrue(response.status_code == 200)
 | 
				
			||||||
 | 
					        content = str(response.content)
 | 
				
			||||||
 | 
					        self.assertTrue('<ul class="errorlist"><li>' in content)
 | 
				
			||||||
 | 
					        self.assertFalse("<td>Responsable info</td>" in content)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_create_add_user_to_club_from_skia_ok(self):
 | 
					    def test_create_add_user_to_club_from_skia_ok(self):
 | 
				
			||||||
        self.client.login(username="root", password="plop")
 | 
					        self.client.login(username="root", password="plop")
 | 
				
			||||||
        self.client.post(
 | 
					        self.client.post(
 | 
				
			||||||
            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
            {"user": self.skia.id, "start_date": "12/06/2016", "role": 10},
 | 
					            {"users": self.skia.id, "start_date": "12/06/2016", "role": 10},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        self.client.login(username="skia", password="plop")
 | 
					        self.client.login(username="skia", password="plop")
 | 
				
			||||||
        self.client.post(
 | 
					        self.client.post(
 | 
				
			||||||
            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
            {"user": self.rbatsbak.id, "start_date": "12/06/2016", "role": 9},
 | 
					            {"users": self.rbatsbak.id, "start_date": "12/06/2016", "role": 9},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        response = self.client.get(
 | 
					        response = self.client.get(
 | 
				
			||||||
            reverse("club:club_members", kwargs={"club_id": self.bdf.id})
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id})
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        self.assertTrue(response.status_code == 200)
 | 
					        self.assertTrue(response.status_code == 200)
 | 
				
			||||||
        self.assertTrue(
 | 
					        self.assertTrue(
 | 
				
			||||||
            """Richard Batsbak</a></td>\\n                <td>Vice-Pr\\xc3\\xa9sident</td>"""
 | 
					            """Richard Batsbak</a></td>\\n                    <td>Vice-Pr\\xc3\\xa9sident</td>"""
 | 
				
			||||||
            in str(response.content)
 | 
					            in str(response.content)
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -118,15 +166,210 @@ class ClubTest(TestCase):
 | 
				
			|||||||
        self.client.login(username="root", password="plop")
 | 
					        self.client.login(username="root", password="plop")
 | 
				
			||||||
        self.client.post(
 | 
					        self.client.post(
 | 
				
			||||||
            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
            {"user": self.rbatsbak.id, "start_date": "12/06/2016", "role": 3},
 | 
					            {"users": self.rbatsbak.id, "start_date": "12/06/2016", "role": 3},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        self.client.login(username="rbatsbak", password="plop")
 | 
					        self.client.login(username="rbatsbak", password="plop")
 | 
				
			||||||
        response = self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
            {"user": self.skia.id, "start_date": "12/06/2016", "role": 10},
 | 
					            {"users": self.skia.id, "start_date": "12/06/2016", "role": 10},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        self.assertTrue(response.status_code == 200)
 | 
					        self.assertTrue(response.status_code == 200)
 | 
				
			||||||
        self.assertTrue(
 | 
					        self.assertTrue(
 | 
				
			||||||
            "<li>Vous n'avez pas la permission de faire cela</li>"
 | 
					            "<li>Vous n'avez pas la permission de faire cela</li>"
 | 
				
			||||||
            in str(response.content)
 | 
					            in str(response.content)
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_role_required_if_users_specified(self):
 | 
				
			||||||
 | 
					        self.client.login(username="root", password="plop")
 | 
				
			||||||
 | 
					        response = self.client.post(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
 | 
					            {"users": self.rbatsbak.id, "start_date": "12/06/2016"},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertTrue(
 | 
				
			||||||
 | 
					            '<ul class="errorlist"><li>Vous devez choisir un r' in str(response.content)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_mark_old_user_to_club_from_skia_ok(self):
 | 
				
			||||||
 | 
					        self.client.login(username="root", password="plop")
 | 
				
			||||||
 | 
					        self.client.post(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "users": "|%d|%d|" % (self.skia.id, self.rbatsbak.id),
 | 
				
			||||||
 | 
					                "start_date": "12/06/2016",
 | 
				
			||||||
 | 
					                "role": 3,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.client.login(username="skia", password="plop")
 | 
				
			||||||
 | 
					        response = self.client.post(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
 | 
					            {"users_old": self.rbatsbak.id},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertTrue(response.status_code == 302)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        response = self.client.get(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id})
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertTrue(response.status_code == 200)
 | 
				
			||||||
 | 
					        content = str(response.content)
 | 
				
			||||||
 | 
					        self.assertFalse(
 | 
				
			||||||
 | 
					            "Richard Batsbak</a></td>\\n                    <td>Responsable info</td>"
 | 
				
			||||||
 | 
					            in content
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertTrue(
 | 
				
			||||||
 | 
					            "S' Kia</a></td>\\n                    <td>Responsable info</td>"
 | 
				
			||||||
 | 
					            in content
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Skia is board member so he should be able to mark as old even without being in the club
 | 
				
			||||||
 | 
					        response = self.client.post(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
 | 
					            {"users_old": self.skia.id},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.client.login(username="root", password="plop")
 | 
				
			||||||
 | 
					        self.client.post(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
 | 
					            {"users": self.rbatsbak.id, "start_date": "12/06/2016", "role": 3},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.client.login(username="skia", password="plop")
 | 
				
			||||||
 | 
					        response = self.client.post(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
 | 
					            {"users_old": self.rbatsbak.id},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertFalse(
 | 
				
			||||||
 | 
					            "Richard Batsbak</a></td>\\n                    <td>Responsable info</td>"
 | 
				
			||||||
 | 
					            in str(response.content)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_mark_old_multiple_users_from_skia_ok(self):
 | 
				
			||||||
 | 
					        self.client.login(username="root", password="plop")
 | 
				
			||||||
 | 
					        self.client.post(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "users": "|%d|%d|" % (self.skia.id, self.rbatsbak.id),
 | 
				
			||||||
 | 
					                "start_date": "12/06/2016",
 | 
				
			||||||
 | 
					                "role": 3,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.client.login(username="skia", password="plop")
 | 
				
			||||||
 | 
					        response = self.client.post(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
 | 
					            {"users_old": [self.rbatsbak.id, self.skia.id]},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertTrue(response.status_code == 302)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        response = self.client.get(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id})
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertTrue(response.status_code == 200)
 | 
				
			||||||
 | 
					        content = str(response.content)
 | 
				
			||||||
 | 
					        self.assertFalse(
 | 
				
			||||||
 | 
					            "Richard Batsbak</a></td>\\n                    <td>Responsable info</td>"
 | 
				
			||||||
 | 
					            in content
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertFalse(
 | 
				
			||||||
 | 
					            "S' Kia</a></td>\\n                    <td>Responsable info</td>"
 | 
				
			||||||
 | 
					            in content
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_mark_old_user_to_club_from_richard_ok(self):
 | 
				
			||||||
 | 
					        self.client.login(username="root", password="plop")
 | 
				
			||||||
 | 
					        self.client.post(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "users": "|%d|%d|" % (self.skia.id, self.rbatsbak.id),
 | 
				
			||||||
 | 
					                "start_date": "12/06/2016",
 | 
				
			||||||
 | 
					                "role": 3,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Test with equal rights
 | 
				
			||||||
 | 
					        self.client.login(username="rbatsbak", password="plop")
 | 
				
			||||||
 | 
					        response = self.client.post(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
 | 
					            {"users_old": self.skia.id},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertTrue(response.status_code == 302)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        response = self.client.get(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id})
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertTrue(response.status_code == 200)
 | 
				
			||||||
 | 
					        content = str(response.content)
 | 
				
			||||||
 | 
					        self.assertTrue(
 | 
				
			||||||
 | 
					            "Richard Batsbak</a></td>\\n                    <td>Responsable info</td>"
 | 
				
			||||||
 | 
					            in content
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertFalse(
 | 
				
			||||||
 | 
					            "S' Kia</a></td>\\n                    <td>Responsable info</td>"
 | 
				
			||||||
 | 
					            in content
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Test with lower rights
 | 
				
			||||||
 | 
					        self.client.post(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
 | 
					            {"users": self.skia.id, "start_date": "12/06/2016", "role": 0},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.client.post(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
 | 
					            {"users_old": self.skia.id},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        response = self.client.get(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id})
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertTrue(response.status_code == 200)
 | 
				
			||||||
 | 
					        content = str(response.content)
 | 
				
			||||||
 | 
					        self.assertTrue(
 | 
				
			||||||
 | 
					            "Richard Batsbak</a></td>\\n                    <td>Responsable info</td>"
 | 
				
			||||||
 | 
					            in content
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertFalse(
 | 
				
			||||||
 | 
					            "S' Kia</a></td>\\n                    <td>Curieux</td>" in content
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_mark_old_user_to_club_from_richard_fail(self):
 | 
				
			||||||
 | 
					        self.client.login(username="root", password="plop")
 | 
				
			||||||
 | 
					        self.client.post(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
 | 
					            {"users": self.skia.id, "start_date": "12/06/2016", "role": 3},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Test with richard outside of the club
 | 
				
			||||||
 | 
					        self.client.login(username="rbatsbak", password="plop")
 | 
				
			||||||
 | 
					        response = self.client.post(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
 | 
					            {"users_old": self.skia.id},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertTrue(response.status_code == 200)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        response = self.client.get(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id})
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertTrue(response.status_code == 200)
 | 
				
			||||||
 | 
					        self.assertTrue(
 | 
				
			||||||
 | 
					            "S' Kia</a></td>\\n                    <td>Responsable info</td>"
 | 
				
			||||||
 | 
					            in str(response.content)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Test with lower rights
 | 
				
			||||||
 | 
					        self.client.post(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
 | 
					            {"users": self.rbatsbak.id, "start_date": "12/06/2016", "role": 0},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.client.post(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
 | 
				
			||||||
 | 
					            {"users_old": self.skia.id},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        response = self.client.get(
 | 
				
			||||||
 | 
					            reverse("club:club_members", kwargs={"club_id": self.bdf.id})
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertTrue(response.status_code == 200)
 | 
				
			||||||
 | 
					        content = str(response.content)
 | 
				
			||||||
 | 
					        self.assertTrue(
 | 
				
			||||||
 | 
					            "Richard Batsbak</a></td>\\n                    <td>Curieux</td>" in content
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertTrue(
 | 
				
			||||||
 | 
					            "S' Kia</a></td>\\n                    <td>Responsable info</td>"
 | 
				
			||||||
 | 
					            in content
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										185
									
								
								club/views.py
									
									
									
									
									
								
							
							
						
						
									
										185
									
								
								club/views.py
									
									
									
									
									
								
							@@ -33,7 +33,7 @@ from django.core.urlresolvers import reverse, reverse_lazy
 | 
				
			|||||||
from django.utils import timezone
 | 
					from django.utils import timezone
 | 
				
			||||||
from django.utils.translation import ugettext_lazy as _
 | 
					from django.utils.translation import ugettext_lazy as _
 | 
				
			||||||
from django.utils.translation import ugettext as _t
 | 
					from django.utils.translation import ugettext as _t
 | 
				
			||||||
from ajax_select.fields import AutoCompleteSelectField
 | 
					from ajax_select.fields import AutoCompleteSelectField, AutoCompleteSelectMultipleField
 | 
				
			||||||
from django.core.exceptions import PermissionDenied
 | 
					from django.core.exceptions import PermissionDenied
 | 
				
			||||||
from django.shortcuts import get_object_or_404, redirect
 | 
					from django.shortcuts import get_object_or_404, redirect
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -44,6 +44,7 @@ from core.views import (
 | 
				
			|||||||
    CanEditPropMixin,
 | 
					    CanEditPropMixin,
 | 
				
			||||||
    TabedViewMixin,
 | 
					    TabedViewMixin,
 | 
				
			||||||
    PageEditViewBase,
 | 
					    PageEditViewBase,
 | 
				
			||||||
 | 
					    DetailFormView,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from core.views.forms import SelectDate, SelectDateTime
 | 
					from core.views.forms import SelectDate, SelectDateTime
 | 
				
			||||||
from club.models import Club, Membership, Mailing, MailingSubscription
 | 
					from club.models import Club, Membership, Mailing, MailingSubscription
 | 
				
			||||||
@@ -305,7 +306,7 @@ class ClubToolsView(ClubTabsMixin, CanEditMixin, DetailView):
 | 
				
			|||||||
    current_tab = "tools"
 | 
					    current_tab = "tools"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClubMemberForm(forms.ModelForm):
 | 
					class ClubMemberForm(forms.Form):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Form handling the members of a club
 | 
					    Form handling the members of a club
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@@ -313,24 +314,115 @@ class ClubMemberForm(forms.ModelForm):
 | 
				
			|||||||
    error_css_class = "error"
 | 
					    error_css_class = "error"
 | 
				
			||||||
    required_css_class = "required"
 | 
					    required_css_class = "required"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Meta:
 | 
					    users = AutoCompleteSelectMultipleField(
 | 
				
			||||||
        model = Membership
 | 
					        "users",
 | 
				
			||||||
        fields = ["user", "role", "start_date", "description"]
 | 
					        label=_("Users to add"),
 | 
				
			||||||
        widgets = {"start_date": SelectDate}
 | 
					        help_text=_("Search users to add (one or more)."),
 | 
				
			||||||
 | 
					        required=False,
 | 
				
			||||||
    user = AutoCompleteSelectField(
 | 
					 | 
				
			||||||
        "users", required=True, label=_("Select user"), help_text=None
 | 
					 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def save(self, *args, **kwargs):
 | 
					    def __init__(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        self.club = kwargs.pop("club")
 | 
				
			||||||
 | 
					        self.request_user = kwargs.pop("request_user")
 | 
				
			||||||
 | 
					        self.club_members = kwargs.pop("club_members", None)
 | 
				
			||||||
 | 
					        if not self.club_members:
 | 
				
			||||||
 | 
					            self.club_members = (
 | 
				
			||||||
 | 
					                self.club.members.filter(end_date=None).order_by("-role").all()
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        self.request_user_membership = self.club.get_membership_for(self.request_user)
 | 
				
			||||||
 | 
					        super(ClubMemberForm, self).__init__(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Using a ModelForm binds too much the form with the model and we don't want that
 | 
				
			||||||
 | 
					        # We want the view to process the model creation since they are multiple users
 | 
				
			||||||
 | 
					        # We also want the form to handle bulk deletion
 | 
				
			||||||
 | 
					        self.fields.update(
 | 
				
			||||||
 | 
					            forms.fields_for_model(
 | 
				
			||||||
 | 
					                Membership,
 | 
				
			||||||
 | 
					                fields=("role", "start_date", "description"),
 | 
				
			||||||
 | 
					                widgets={"start_date": SelectDate},
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Role is required only if users is specified
 | 
				
			||||||
 | 
					        self.fields["role"].required = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Start date and description are never really required
 | 
				
			||||||
 | 
					        self.fields["start_date"].required = False
 | 
				
			||||||
 | 
					        self.fields["description"].required = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.fields["users_old"] = forms.ModelMultipleChoiceField(
 | 
				
			||||||
 | 
					            User.objects.filter(
 | 
				
			||||||
 | 
					                id__in=[
 | 
				
			||||||
 | 
					                    ms.user.id
 | 
				
			||||||
 | 
					                    for ms in self.club_members
 | 
				
			||||||
 | 
					                    if ms.can_be_edited_by(
 | 
				
			||||||
 | 
					                        self.request_user, self.request_user_membership
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                ]
 | 
				
			||||||
 | 
					            ).all(),
 | 
				
			||||||
 | 
					            label=_("Mark as old"),
 | 
				
			||||||
 | 
					            required=False,
 | 
				
			||||||
 | 
					            widget=forms.CheckboxSelectMultiple,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        if not self.request_user.is_root:
 | 
				
			||||||
 | 
					            self.fields.pop("start_date")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def clean_users(self):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Overloaded to return the club, and not to a Membership object that has no view
 | 
					            Check that the user is not trying to add an user already in the club
 | 
				
			||||||
 | 
					            Also check that the user is valid and has a valid subscription
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        super(ClubMemberForm, self).save(*args, **kwargs)
 | 
					        cleaned_data = super(ClubMemberForm, self).clean()
 | 
				
			||||||
        return self.instance.club
 | 
					        users = []
 | 
				
			||||||
 | 
					        for user_id in cleaned_data["users"]:
 | 
				
			||||||
 | 
					            user = User.objects.filter(id=user_id).first()
 | 
				
			||||||
 | 
					            if not user:
 | 
				
			||||||
 | 
					                raise forms.ValidationError(
 | 
				
			||||||
 | 
					                    _("One of the selected users doesn't exist"), code="invalid"
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            if not user.is_subscribed:
 | 
				
			||||||
 | 
					                raise forms.ValidationError(
 | 
				
			||||||
 | 
					                    _("User must be subscriber to take part to a club"), code="invalid"
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            if self.club.get_membership_for(user):
 | 
				
			||||||
 | 
					                raise forms.ValidationError(
 | 
				
			||||||
 | 
					                    _("You can not add the same user twice"), code="invalid"
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            users.append(user)
 | 
				
			||||||
 | 
					        return users
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def clean(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					            Check user rights for adding an user
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        cleaned_data = super(ClubMemberForm, self).clean()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if "start_date" in cleaned_data and not cleaned_data["start_date"]:
 | 
				
			||||||
 | 
					            # Drop start_date if allowed to edition but not specified
 | 
				
			||||||
 | 
					            cleaned_data.pop("start_date")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not cleaned_data.get("users"):
 | 
				
			||||||
 | 
					            # No user to add equals no check needed
 | 
				
			||||||
 | 
					            return cleaned_data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if cleaned_data.get("role", "") == "":
 | 
				
			||||||
 | 
					            # Role is required if users exists
 | 
				
			||||||
 | 
					            self.add_error("role", _("You should specify a role"))
 | 
				
			||||||
 | 
					            return cleaned_data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        request_user = self.request_user
 | 
				
			||||||
 | 
					        membership = self.request_user_membership
 | 
				
			||||||
 | 
					        if not (
 | 
				
			||||||
 | 
					            cleaned_data["role"] <= SITH_MAXIMUM_FREE_ROLE
 | 
				
			||||||
 | 
					            or (membership is not None and membership.role >= cleaned_data["role"])
 | 
				
			||||||
 | 
					            or request_user.is_board_member
 | 
				
			||||||
 | 
					            or request_user.is_root
 | 
				
			||||||
 | 
					        ):
 | 
				
			||||||
 | 
					            raise forms.ValidationError(_("You do not have the permission to do that"))
 | 
				
			||||||
 | 
					        return cleaned_data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClubMembersView(ClubTabsMixin, CanViewMixin, UpdateView):
 | 
					class ClubMembersView(ClubTabsMixin, CanViewMixin, DetailFormView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    View of a club's members
 | 
					    View of a club's members
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@@ -341,52 +433,45 @@ class ClubMembersView(ClubTabsMixin, CanViewMixin, UpdateView):
 | 
				
			|||||||
    template_name = "club/club_members.jinja"
 | 
					    template_name = "club/club_members.jinja"
 | 
				
			||||||
    current_tab = "members"
 | 
					    current_tab = "members"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_form(self):
 | 
					    def get_form_kwargs(self):
 | 
				
			||||||
        """
 | 
					        kwargs = super(ClubMembersView, self).get_form_kwargs()
 | 
				
			||||||
        Here we get a Membership object, but the view handles Club object.
 | 
					        kwargs["request_user"] = self.request.user
 | 
				
			||||||
        That's why the save method of ClubMemberForm is overridden.
 | 
					        kwargs["club"] = self.get_object()
 | 
				
			||||||
        """
 | 
					        kwargs["club_members"] = self.members
 | 
				
			||||||
        form = super(ClubMembersView, self).get_form()
 | 
					        return kwargs
 | 
				
			||||||
        if (
 | 
					
 | 
				
			||||||
            "user" in form.data and form.data.get("user") != ""
 | 
					    def get_context_data(self, *args, **kwargs):
 | 
				
			||||||
        ):  # Load an existing membership if possible
 | 
					        kwargs = super(ClubMembersView, self).get_context_data(*args, **kwargs)
 | 
				
			||||||
            form.instance = (
 | 
					        kwargs["members"] = self.members
 | 
				
			||||||
                Membership.objects.filter(club=self.object)
 | 
					        return kwargs
 | 
				
			||||||
                .filter(user=form.data.get("user"))
 | 
					 | 
				
			||||||
                .filter(end_date=None)
 | 
					 | 
				
			||||||
                .first()
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        if form.instance is None:  # Instanciate a new membership
 | 
					 | 
				
			||||||
            form.instance = Membership(club=self.object, user=self.request.user)
 | 
					 | 
				
			||||||
        if not self.request.user.is_root:
 | 
					 | 
				
			||||||
            form.fields.pop("start_date", None)
 | 
					 | 
				
			||||||
        return form
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def form_valid(self, form):
 | 
					    def form_valid(self, form):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
            Check user rights
 | 
					            Check user rights
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        user = self.request.user
 | 
					        resp = super(ClubMembersView, self).form_valid(form)
 | 
				
			||||||
        ms = self.object.get_membership_for(user)
 | 
					
 | 
				
			||||||
        if (
 | 
					        data = form.clean()
 | 
				
			||||||
            form.cleaned_data["role"] <= SITH_MAXIMUM_FREE_ROLE
 | 
					        users = data.pop("users", [])
 | 
				
			||||||
            or (ms is not None and ms.role >= form.cleaned_data["role"])
 | 
					        users_old = data.pop("users_old", [])
 | 
				
			||||||
            or user.is_board_member
 | 
					        for user in users:
 | 
				
			||||||
            or user.is_root
 | 
					            Membership(club=self.get_object(), user=user, **data).save()
 | 
				
			||||||
        ):
 | 
					        for user in users_old:
 | 
				
			||||||
            form.save()
 | 
					            membership = self.get_object().get_membership_for(user)
 | 
				
			||||||
            form = self.form_class()
 | 
					            membership.end_date = timezone.now()
 | 
				
			||||||
            return super(ModelFormMixin, self).form_valid(form)
 | 
					            membership.save()
 | 
				
			||||||
        else:
 | 
					        return resp
 | 
				
			||||||
            form.add_error(None, _("You do not have the permission to do that"))
 | 
					 | 
				
			||||||
            return self.form_invalid(form)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def dispatch(self, request, *args, **kwargs):
 | 
					    def dispatch(self, request, *args, **kwargs):
 | 
				
			||||||
        self.request = request
 | 
					        self.members = (
 | 
				
			||||||
 | 
					            self.get_object().members.filter(end_date=None).order_by("-role").all()
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        return super(ClubMembersView, self).dispatch(request, *args, **kwargs)
 | 
					        return super(ClubMembersView, self).dispatch(request, *args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_success_url(self, **kwargs):
 | 
					    def get_success_url(self, **kwargs):
 | 
				
			||||||
        return reverse_lazy("club:club_members", kwargs={"club_id": self.club.id})
 | 
					        return reverse_lazy(
 | 
				
			||||||
 | 
					            "club:club_members", kwargs={"club_id": self.get_object().id}
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClubOldMembersView(ClubTabsMixin, CanViewMixin, DetailView):
 | 
					class ClubOldMembersView(ClubTabsMixin, CanViewMixin, DetailView):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Report-Msgid-Bugs-To: \n"
 | 
					"Report-Msgid-Bugs-To: \n"
 | 
				
			||||||
"POT-Creation-Date: 2019-04-22 14:57+0200\n"
 | 
					"POT-Creation-Date: 2019-04-25 17:35+0200\n"
 | 
				
			||||||
"PO-Revision-Date: 2016-07-18\n"
 | 
					"PO-Revision-Date: 2016-07-18\n"
 | 
				
			||||||
"Last-Translator: Skia <skia@libskia.so>\n"
 | 
					"Last-Translator: Skia <skia@libskia.so>\n"
 | 
				
			||||||
"Language-Team: AE info <ae.info@utbm.fr>\n"
 | 
					"Language-Team: AE info <ae.info@utbm.fr>\n"
 | 
				
			||||||
@@ -174,10 +174,10 @@ msgstr "étiquette"
 | 
				
			|||||||
msgid "target type"
 | 
					msgid "target type"
 | 
				
			||||||
msgstr "type de cible"
 | 
					msgstr "type de cible"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: accounting/models.py:313 club/models.py:422
 | 
					#: accounting/models.py:313 club/models.py:413
 | 
				
			||||||
#: club/templates/club/club_members.jinja:8
 | 
					#: club/templates/club/club_members.jinja:16
 | 
				
			||||||
#: club/templates/club/club_old_members.jinja:8
 | 
					#: club/templates/club/club_old_members.jinja:8
 | 
				
			||||||
#: club/templates/club/mailing.jinja:28 club/views.py:111
 | 
					#: club/templates/club/mailing.jinja:28 club/views.py:112
 | 
				
			||||||
#: counter/templates/counter/cash_summary_list.jinja:32
 | 
					#: counter/templates/counter/cash_summary_list.jinja:32
 | 
				
			||||||
#: counter/templates/counter/stats.jinja:15
 | 
					#: counter/templates/counter/stats.jinja:15
 | 
				
			||||||
#: counter/templates/counter/stats.jinja:52
 | 
					#: counter/templates/counter/stats.jinja:52
 | 
				
			||||||
@@ -186,7 +186,7 @@ msgstr "type de cible"
 | 
				
			|||||||
msgid "User"
 | 
					msgid "User"
 | 
				
			||||||
msgstr "Utilisateur"
 | 
					msgstr "Utilisateur"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: accounting/models.py:314 club/models.py:329
 | 
					#: accounting/models.py:314 club/models.py:320
 | 
				
			||||||
#: club/templates/club/club_detail.jinja:12
 | 
					#: club/templates/club/club_detail.jinja:12
 | 
				
			||||||
#: com/templates/com/mailing_admin.jinja:11
 | 
					#: com/templates/com/mailing_admin.jinja:11
 | 
				
			||||||
#: com/templates/com/news_admin_list.jinja:23
 | 
					#: com/templates/com/news_admin_list.jinja:23
 | 
				
			||||||
@@ -386,7 +386,7 @@ msgid "Delete"
 | 
				
			|||||||
msgstr "Supprimer"
 | 
					msgstr "Supprimer"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: accounting/templates/accounting/bank_account_details.jinja:18
 | 
					#: accounting/templates/accounting/bank_account_details.jinja:18
 | 
				
			||||||
#: club/views.py:128 core/views/user.py:205 sas/templates/sas/picture.jinja:86
 | 
					#: club/views.py:129 core/views/user.py:205 sas/templates/sas/picture.jinja:86
 | 
				
			||||||
msgid "Infos"
 | 
					msgid "Infos"
 | 
				
			||||||
msgstr "Infos"
 | 
					msgstr "Infos"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -405,7 +405,7 @@ msgstr "Nouveau compte club"
 | 
				
			|||||||
#: accounting/templates/accounting/bank_account_details.jinja:27
 | 
					#: accounting/templates/accounting/bank_account_details.jinja:27
 | 
				
			||||||
#: accounting/templates/accounting/bank_account_list.jinja:22
 | 
					#: accounting/templates/accounting/bank_account_list.jinja:22
 | 
				
			||||||
#: accounting/templates/accounting/club_account_details.jinja:58
 | 
					#: accounting/templates/accounting/club_account_details.jinja:58
 | 
				
			||||||
#: accounting/templates/accounting/journal_details.jinja:89 club/views.py:174
 | 
					#: accounting/templates/accounting/journal_details.jinja:89 club/views.py:175
 | 
				
			||||||
#: com/templates/com/news_admin_list.jinja:39
 | 
					#: com/templates/com/news_admin_list.jinja:39
 | 
				
			||||||
#: com/templates/com/news_admin_list.jinja:68
 | 
					#: com/templates/com/news_admin_list.jinja:68
 | 
				
			||||||
#: com/templates/com/news_admin_list.jinja:115
 | 
					#: com/templates/com/news_admin_list.jinja:115
 | 
				
			||||||
@@ -955,48 +955,40 @@ msgstr "rôle"
 | 
				
			|||||||
msgid "description"
 | 
					msgid "description"
 | 
				
			||||||
msgstr "description"
 | 
					msgstr "description"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/models.py:282
 | 
					#: club/models.py:286
 | 
				
			||||||
msgid "User must be subscriber to take part to a club"
 | 
					 | 
				
			||||||
msgstr "L'utilisateur doit être cotisant pour faire partie d'un club"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: club/models.py:289
 | 
					 | 
				
			||||||
msgid "User is already member of that club"
 | 
					 | 
				
			||||||
msgstr "L'utilisateur est déjà membre de ce club"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: club/models.py:298
 | 
					 | 
				
			||||||
msgid "past member"
 | 
					msgid "past member"
 | 
				
			||||||
msgstr "Anciens membres"
 | 
					msgstr "Anciens membres"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/models.py:332 club/models.py:427
 | 
					#: club/models.py:323 club/models.py:418
 | 
				
			||||||
msgid "Email address"
 | 
					msgid "Email address"
 | 
				
			||||||
msgstr "Adresse email"
 | 
					msgstr "Adresse email"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/models.py:340
 | 
					#: club/models.py:331
 | 
				
			||||||
msgid "Enter a valid address. Only the root of the address is needed."
 | 
					msgid "Enter a valid address. Only the root of the address is needed."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Entrez une adresse valide. Seule la racine de l'adresse est nécessaire."
 | 
					"Entrez une adresse valide. Seule la racine de l'adresse est nécessaire."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/models.py:344 com/models.py:79 com/models.py:260 core/models.py:810
 | 
					#: club/models.py:335 com/models.py:79 com/models.py:260 core/models.py:810
 | 
				
			||||||
msgid "is moderated"
 | 
					msgid "is moderated"
 | 
				
			||||||
msgstr "est modéré"
 | 
					msgstr "est modéré"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/models.py:346 com/models.py:81 com/models.py:264
 | 
					#: club/models.py:337 com/models.py:81 com/models.py:264
 | 
				
			||||||
msgid "moderator"
 | 
					msgid "moderator"
 | 
				
			||||||
msgstr "modérateur"
 | 
					msgstr "modérateur"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/models.py:415 club/templates/club/mailing.jinja:14
 | 
					#: club/models.py:406 club/templates/club/mailing.jinja:14
 | 
				
			||||||
msgid "Mailing"
 | 
					msgid "Mailing"
 | 
				
			||||||
msgstr "Liste de diffusion"
 | 
					msgstr "Liste de diffusion"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/models.py:434
 | 
					#: club/models.py:425
 | 
				
			||||||
msgid "At least user or email is required"
 | 
					msgid "At least user or email is required"
 | 
				
			||||||
msgstr "Au moins un utilisateur ou un email est nécessaire"
 | 
					msgstr "Au moins un utilisateur ou un email est nécessaire"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/models.py:442
 | 
					#: club/models.py:433
 | 
				
			||||||
msgid "This email is already suscribed in this mailing"
 | 
					msgid "This email is already suscribed in this mailing"
 | 
				
			||||||
msgstr "Cet email est déjà abonné à cette mailing"
 | 
					msgstr "Cet email est déjà abonné à cette mailing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/models.py:471 club/templates/club/mailing.jinja:36
 | 
					#: club/models.py:462 club/templates/club/mailing.jinja:36
 | 
				
			||||||
msgid "Unregistered user"
 | 
					msgid "Unregistered user"
 | 
				
			||||||
msgstr "Désabonner un utilisateur"
 | 
					msgstr "Désabonner un utilisateur"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1021,7 +1013,7 @@ msgstr "Il n'y a pas de club dans ce site web."
 | 
				
			|||||||
msgid "Club members"
 | 
					msgid "Club members"
 | 
				
			||||||
msgstr "Membres du club"
 | 
					msgstr "Membres du club"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/templates/club/club_members.jinja:9
 | 
					#: club/templates/club/club_members.jinja:17
 | 
				
			||||||
#: club/templates/club/club_old_members.jinja:9
 | 
					#: club/templates/club/club_old_members.jinja:9
 | 
				
			||||||
#: core/templates/core/user_clubs.jinja:16
 | 
					#: core/templates/core/user_clubs.jinja:16
 | 
				
			||||||
#: core/templates/core/user_clubs.jinja:42
 | 
					#: core/templates/core/user_clubs.jinja:42
 | 
				
			||||||
@@ -1031,7 +1023,7 @@ msgstr "Membres du club"
 | 
				
			|||||||
msgid "Role"
 | 
					msgid "Role"
 | 
				
			||||||
msgstr "Rôle"
 | 
					msgstr "Rôle"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/templates/club/club_members.jinja:10
 | 
					#: club/templates/club/club_members.jinja:18
 | 
				
			||||||
#: club/templates/club/club_old_members.jinja:10
 | 
					#: club/templates/club/club_old_members.jinja:10
 | 
				
			||||||
#: core/templates/core/group_list.jinja:15
 | 
					#: core/templates/core/group_list.jinja:15
 | 
				
			||||||
#: core/templates/core/user_clubs.jinja:17
 | 
					#: core/templates/core/user_clubs.jinja:17
 | 
				
			||||||
@@ -1039,18 +1031,23 @@ msgstr "Rôle"
 | 
				
			|||||||
msgid "Description"
 | 
					msgid "Description"
 | 
				
			||||||
msgstr "Description"
 | 
					msgstr "Description"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/templates/club/club_members.jinja:11
 | 
					#: club/templates/club/club_members.jinja:19
 | 
				
			||||||
#: core/templates/core/user_clubs.jinja:18
 | 
					#: core/templates/core/user_clubs.jinja:18
 | 
				
			||||||
#: launderette/templates/launderette/launderette_admin.jinja:45
 | 
					#: launderette/templates/launderette/launderette_admin.jinja:45
 | 
				
			||||||
msgid "Since"
 | 
					msgid "Since"
 | 
				
			||||||
msgstr "Depuis"
 | 
					msgstr "Depuis"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/templates/club/club_members.jinja:21
 | 
					#: club/templates/club/club_members.jinja:21
 | 
				
			||||||
 | 
					#: club/templates/club/club_members.jinja:46 club/views.py:363
 | 
				
			||||||
#: core/templates/core/user_clubs.jinja:29
 | 
					#: core/templates/core/user_clubs.jinja:29
 | 
				
			||||||
msgid "Mark as old"
 | 
					msgid "Mark as old"
 | 
				
			||||||
msgstr "Marquer comme ancien"
 | 
					msgstr "Marquer comme ancien"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/templates/club/club_members.jinja:30
 | 
					#: club/templates/club/club_members.jinja:50
 | 
				
			||||||
 | 
					msgid "There are no members in this club."
 | 
				
			||||||
 | 
					msgstr "Il n'y a pas de membres dans ce club."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: club/templates/club/club_members.jinja:78
 | 
				
			||||||
#: core/templates/core/file_detail.jinja:19 core/views/forms.py:355
 | 
					#: core/templates/core/file_detail.jinja:19 core/views/forms.py:355
 | 
				
			||||||
#: launderette/views.py:226 trombi/templates/trombi/detail.jinja:19
 | 
					#: launderette/views.py:226 trombi/templates/trombi/detail.jinja:19
 | 
				
			||||||
msgid "Add"
 | 
					msgid "Add"
 | 
				
			||||||
@@ -1070,8 +1067,8 @@ msgstr "Du"
 | 
				
			|||||||
msgid "To"
 | 
					msgid "To"
 | 
				
			||||||
msgstr "Au"
 | 
					msgstr "Au"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/templates/club/club_sellings.jinja:5 club/views.py:194
 | 
					#: club/templates/club/club_sellings.jinja:5 club/views.py:195
 | 
				
			||||||
#: club/views.py:478 counter/templates/counter/counter_main.jinja:19
 | 
					#: club/views.py:564 counter/templates/counter/counter_main.jinja:19
 | 
				
			||||||
#: counter/templates/counter/last_ops.jinja:35
 | 
					#: counter/templates/counter/last_ops.jinja:35
 | 
				
			||||||
msgid "Sellings"
 | 
					msgid "Sellings"
 | 
				
			||||||
msgstr "Ventes"
 | 
					msgstr "Ventes"
 | 
				
			||||||
@@ -1097,7 +1094,7 @@ msgstr "unités"
 | 
				
			|||||||
msgid "Benefit: "
 | 
					msgid "Benefit: "
 | 
				
			||||||
msgstr "Bénéfice : "
 | 
					msgstr "Bénéfice : "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/templates/club/club_sellings.jinja:21 club/views.py:417
 | 
					#: club/templates/club/club_sellings.jinja:21 club/views.py:503
 | 
				
			||||||
#: core/templates/core/user_account_detail.jinja:18
 | 
					#: core/templates/core/user_account_detail.jinja:18
 | 
				
			||||||
#: core/templates/core/user_account_detail.jinja:51
 | 
					#: core/templates/core/user_account_detail.jinja:51
 | 
				
			||||||
#: counter/templates/counter/cash_summary_list.jinja:33 counter/views.py:168
 | 
					#: counter/templates/counter/cash_summary_list.jinja:33 counter/views.py:168
 | 
				
			||||||
@@ -1246,60 +1243,79 @@ msgstr "Aucune page n'existe pour ce club"
 | 
				
			|||||||
msgid "Club stats"
 | 
					msgid "Club stats"
 | 
				
			||||||
msgstr "Statistiques du club"
 | 
					msgstr "Statistiques du club"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/views.py:138
 | 
					#: club/views.py:139
 | 
				
			||||||
msgid "Members"
 | 
					msgid "Members"
 | 
				
			||||||
msgstr "Membres"
 | 
					msgstr "Membres"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/views.py:147
 | 
					#: club/views.py:148
 | 
				
			||||||
msgid "Old members"
 | 
					msgid "Old members"
 | 
				
			||||||
msgstr "Anciens membres"
 | 
					msgstr "Anciens membres"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/views.py:157 core/templates/core/page.jinja:33
 | 
					#: club/views.py:158 core/templates/core/page.jinja:33
 | 
				
			||||||
msgid "History"
 | 
					msgid "History"
 | 
				
			||||||
msgstr "Historique"
 | 
					msgstr "Historique"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/views.py:165 core/templates/core/base.jinja:121 core/views/user.py:228
 | 
					#: club/views.py:166 core/templates/core/base.jinja:121 core/views/user.py:228
 | 
				
			||||||
#: sas/templates/sas/picture.jinja:95 trombi/views.py:60
 | 
					#: sas/templates/sas/picture.jinja:95 trombi/views.py:60
 | 
				
			||||||
msgid "Tools"
 | 
					msgid "Tools"
 | 
				
			||||||
msgstr "Outils"
 | 
					msgstr "Outils"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/views.py:185
 | 
					#: club/views.py:186
 | 
				
			||||||
msgid "Edit club page"
 | 
					msgid "Edit club page"
 | 
				
			||||||
msgstr "Éditer la page de club"
 | 
					msgstr "Éditer la page de club"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/views.py:201
 | 
					#: club/views.py:202
 | 
				
			||||||
msgid "Mailing list"
 | 
					msgid "Mailing list"
 | 
				
			||||||
msgstr "Listes de diffusion"
 | 
					msgstr "Listes de diffusion"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/views.py:210 com/views.py:141
 | 
					#: club/views.py:211 com/views.py:141
 | 
				
			||||||
msgid "Posters list"
 | 
					msgid "Posters list"
 | 
				
			||||||
msgstr "Liste d'affiches"
 | 
					msgstr "Liste d'affiches"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/views.py:220 counter/templates/counter/counter_list.jinja:21
 | 
					#: club/views.py:221 counter/templates/counter/counter_list.jinja:21
 | 
				
			||||||
#: counter/templates/counter/counter_list.jinja:43
 | 
					#: counter/templates/counter/counter_list.jinja:43
 | 
				
			||||||
#: counter/templates/counter/counter_list.jinja:59
 | 
					#: counter/templates/counter/counter_list.jinja:59
 | 
				
			||||||
msgid "Props"
 | 
					msgid "Props"
 | 
				
			||||||
msgstr "Propriétés"
 | 
					msgstr "Propriétés"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/views.py:322 core/views/forms.py:358 counter/views.py:113
 | 
					#: club/views.py:319
 | 
				
			||||||
#: trombi/views.py:141
 | 
					msgid "Users to add"
 | 
				
			||||||
msgid "Select user"
 | 
					msgstr "Utilisateurs à ajouter"
 | 
				
			||||||
msgstr "Choisir un utilisateur"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/views.py:381 sas/views.py:129 sas/views.py:195 sas/views.py:286
 | 
					#: club/views.py:320 core/views/group.py:63
 | 
				
			||||||
 | 
					msgid "Search users to add (one or more)."
 | 
				
			||||||
 | 
					msgstr "Recherche les utilisateurs à ajouter (un ou plus)."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: club/views.py:381
 | 
				
			||||||
 | 
					msgid "One of the selected users doesn't exist"
 | 
				
			||||||
 | 
					msgstr "Un des utilisateurs sélectionné n'existe pas"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: club/views.py:385
 | 
				
			||||||
 | 
					msgid "User must be subscriber to take part to a club"
 | 
				
			||||||
 | 
					msgstr "L'utilisateur doit être cotisant pour faire partie d'un club"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: club/views.py:389 core/views/group.py:82
 | 
				
			||||||
 | 
					msgid "You can not add the same user twice"
 | 
				
			||||||
 | 
					msgstr "Vous ne pouvez pas ajouter deux fois le même utilisateur"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: club/views.py:410
 | 
				
			||||||
 | 
					msgid "You should specify a role"
 | 
				
			||||||
 | 
					msgstr "Vous devez choisir un rôle"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: club/views.py:421 sas/views.py:129 sas/views.py:195 sas/views.py:286
 | 
				
			||||||
msgid "You do not have the permission to do that"
 | 
					msgid "You do not have the permission to do that"
 | 
				
			||||||
msgstr "Vous n'avez pas la permission de faire cela"
 | 
					msgstr "Vous n'avez pas la permission de faire cela"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/views.py:406 counter/views.py:1481
 | 
					#: club/views.py:492 counter/views.py:1481
 | 
				
			||||||
msgid "Begin date"
 | 
					msgid "Begin date"
 | 
				
			||||||
msgstr "Date de début"
 | 
					msgstr "Date de début"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/views.py:412 com/views.py:85 com/views.py:221 counter/views.py:1487
 | 
					#: club/views.py:498 com/views.py:85 com/views.py:221 counter/views.py:1487
 | 
				
			||||||
#: election/views.py:190 subscription/views.py:52
 | 
					#: election/views.py:190 subscription/views.py:52
 | 
				
			||||||
msgid "End date"
 | 
					msgid "End date"
 | 
				
			||||||
msgstr "Date de fin"
 | 
					msgstr "Date de fin"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/views.py:435 core/templates/core/user_stats.jinja:27
 | 
					#: club/views.py:521 core/templates/core/user_stats.jinja:27
 | 
				
			||||||
#: counter/views.py:1635
 | 
					#: counter/views.py:1635
 | 
				
			||||||
msgid "Product"
 | 
					msgid "Product"
 | 
				
			||||||
msgstr "Produit"
 | 
					msgstr "Produit"
 | 
				
			||||||
@@ -3507,6 +3523,10 @@ msgstr "Parrain"
 | 
				
			|||||||
msgid "Godchild"
 | 
					msgid "Godchild"
 | 
				
			||||||
msgstr "Fillot"
 | 
					msgstr "Fillot"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: core/views/forms.py:358 counter/views.py:113 trombi/views.py:141
 | 
				
			||||||
 | 
					msgid "Select user"
 | 
				
			||||||
 | 
					msgstr "Choisir un utilisateur"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: core/views/forms.py:371 core/views/forms.py:389 election/models.py:24
 | 
					#: core/views/forms.py:371 core/views/forms.py:389 election/models.py:24
 | 
				
			||||||
#: election/views.py:167
 | 
					#: election/views.py:167
 | 
				
			||||||
msgid "edit groups"
 | 
					msgid "edit groups"
 | 
				
			||||||
@@ -3525,14 +3545,6 @@ msgstr "Utilisateurs à retirer du groupe"
 | 
				
			|||||||
msgid "Users to add to group"
 | 
					msgid "Users to add to group"
 | 
				
			||||||
msgstr "Utilisateurs à ajouter au groupe"
 | 
					msgstr "Utilisateurs à ajouter au groupe"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: core/views/group.py:63
 | 
					 | 
				
			||||||
msgid "Search users to add (one or more)."
 | 
					 | 
				
			||||||
msgstr "Recherche les utilisateurs à ajouter (un ou plus)."
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: core/views/group.py:82
 | 
					 | 
				
			||||||
msgid "You can not add the same user twice"
 | 
					 | 
				
			||||||
msgstr "Vous ne pouvez pas ajouter deux fois le même utilisateur"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: core/views/user.py:223 trombi/templates/trombi/export.jinja:25
 | 
					#: core/views/user.py:223 trombi/templates/trombi/export.jinja:25
 | 
				
			||||||
#: trombi/templates/trombi/user_profile.jinja:11
 | 
					#: trombi/templates/trombi/user_profile.jinja:11
 | 
				
			||||||
msgid "Pictures"
 | 
					msgid "Pictures"
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user