mirror of
https://github.com/ae-utbm/sith.git
synced 2024-11-26 11:04:20 +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:
commit
142299c0cd
@ -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"
|
||||||
|
Loading…
Reference in New Issue
Block a user