Merge branch 'admin' into 'master'

Amélioration de l'administration des groupes

See merge request ae/Sith!148
This commit is contained in:
Antoine Bartuccio 2019-04-23 23:06:39 +02:00
commit e8ee9122f9
7 changed files with 262 additions and 12 deletions

View File

@ -0,0 +1,39 @@
{% extends "core/base.jinja" %}
{% from "core/macros.jinja" import select_all_checkbox %}
{% block title %}
{% trans %}Group detail{% endtrans %}
{% endblock title %}
{% block content %}
<h1>{{ object }}</h1>
<p><a href="{{ url('core:group_list') }}">{% trans %}Back to list{% endtrans %}</a></p>
{% if form.users_removed | length <= 0 %}
<p>{% trans %}No user in this group{% endtrans %}</p>
{% else %}
<form action="{{ url('core:group_detail', object.id) }}" method="post" id="add_users">
{{ select_all_checkbox("add_users") }}
<hr>
{% csrf_token %}
<label for="{{ form.users_removed.id_for_label }}">{{ form.users_removed.label }} :</label>
{{ form.users_removed.errors }}
{% for user in form.users_removed %}
<label for="{{ user.id_for_label }}">
{{ user.tag() }}
<a href="{{ url('core:user_profile', user.data.value) }}">{{ user.choice_label }}</a>
</label>
{% endfor %}
<input type="submit" name="submit" value="{% trans %}Delete{% endtrans %}">
</form>
{% endif %}
<form action="{{ url('core:group_detail', object.id) }}" method="post" id="add_users">
{% csrf_token %}
<p>
{{ form.users_added.errors }}
<label for="{{ form.users_added.id_for_label }}">{{ form.users_added.label }} :</label>
{{ form.users_added }}
<span class="helptext">{{ form.users_added.help_text }}</span>
</p>
<input type="submit" name="submit">
</form>
{% endblock content %}

View File

@ -7,11 +7,25 @@
{% block content %} {% block content %}
<h3>{% trans %}Group list{% endtrans %}</h3> <h3>{% trans %}Group list{% endtrans %}</h3>
<p><a href="{{ url('core:group_new') }}">{% trans %}New group{% endtrans %}</a></p> <p><a href="{{ url('core:group_new') }}">{% trans %}New group{% endtrans %}</a></p>
<ul> <table>
{% for g in realgroup_list %} <thead>
<li><a href="{{ url('core:group_edit', group_id=g.id) }}">{{ g.name }}</a> - {{ g.description }} - <tr>
<a href="{{ url('core:group_delete', group_id=g.id) }}">{% trans %}Delete{% endtrans %}</a></li> <td>{% trans %}ID{% endtrans %}</td>
<td>{% trans %}Group{% endtrans %}</td>
<td>{% trans %}Description{% endtrans %}</td>
</tr>
</thead>
<tbody>
{% for group in object_list %}
<tr>
<td>{{ group.id }}</td>
<td><a href="{{ url('core:group_detail', group.id) }}">{{ group }}</a></td>
<td>{{ group.description }}</td>
<td><a href="{{ url('core:group_edit', group.id) }}">{% trans %}Edit{% endtrans %}</a></td>
<td><a href="{{ url('core:group_delete', group.id) }}">{% trans %}Delete{% endtrans %}</a></td>
</tr>
{% endfor %} {% endfor %}
</ul> </tbody>
</table>
{% endblock %} {% endblock %}

View File

@ -132,3 +132,18 @@
<span class="disabled">{% trans %}Next{% endtrans %}</span> <span class="disabled">{% trans %}Next{% endtrans %}</span>
{% endif %} {% endif %}
{% endmacro %} {% endmacro %}
{% macro select_all_checkbox(form_id) %}
<script type="text/javascript">
function checkbox_{{form_id}}(value) {
list = document.getElementById("{{ form_id }}").getElementsByTagName("input");
for (let element of list){
if (element.type == "checkbox"){
element.checked = value;
}
}
}
</script>
<button type="button" onclick="checkbox_{{form_id}}(true);">{% trans %}Select All{% endtrans %}</button>
<button type="button" onclick="checkbox_{{form_id}}(false);">{% trans %}Unselect All{% endtrans %}</button>
{% endmacro %}

View File

@ -64,6 +64,11 @@ urlpatterns = [
GroupDeleteView.as_view(), GroupDeleteView.as_view(),
name="group_delete", name="group_delete",
), ),
url(
r"^group/(?P<group_id>[0-9]+)/detail$",
GroupTemplateView.as_view(),
name="group_detail",
),
# User views # User views
url(r"^user/$", UserListView.as_view(), name="user_list"), url(r"^user/$", UserListView.as_view(), name="user_list"),
url( url(

View File

@ -39,6 +39,9 @@ from django.core.exceptions import (
ImproperlyConfigured, ImproperlyConfigured,
) )
from django.views.generic.base import View from django.views.generic.base import View
from django.views.generic.edit import FormView
from django.views.generic.detail import SingleObjectMixin
from django.utils.functional import cached_property
from django.db.models import Count from django.db.models import Count
from core.models import Group from core.models import Group
@ -275,6 +278,30 @@ class QuickNotifMixin:
return kwargs return kwargs
class DetailFormView(SingleObjectMixin, FormView):
"""
Class that allow both a detail view and a form view
"""
def get_object(self):
"""
Get current group from id in url
"""
return self.cached_object
@cached_property
def cached_object(self):
"""
Optimisation on group retrieval
"""
return super(DetailFormView, self).get_object()
def get_context_data(self, *args, **kwargs):
kwargs = super(DetailFormView, self).get_context_data()
kwargs["object"] = self.get_object()
return kwargs
from .user import * from .user import *
from .page import * from .page import *
from .files import * from .files import *

View File

@ -22,24 +22,87 @@
# #
# #
"""
This module contains views to manage Groups
"""
from django.views.generic.edit import UpdateView, CreateView, DeleteView from django.views.generic.edit import UpdateView, CreateView, DeleteView
from django.views.generic import ListView from django.views.generic import ListView
from django.views.generic.edit import FormView
from django.core.urlresolvers import reverse_lazy from django.core.urlresolvers import reverse_lazy
from django.shortcuts import get_object_or_404
from django.utils.translation import ugettext_lazy as _
from django import forms
from core.models import RealGroup from ajax_select.fields import AutoCompleteSelectMultipleField
from core.views import CanEditMixin
from core.models import RealGroup, User
from core.views import CanEditMixin, DetailFormView
# Forms
class EditMembersForm(forms.Form):
"""
Add and remove members from a Group
"""
def __init__(self, *args, **kwargs):
self.current_users = kwargs.pop("users", [])
super(EditMembersForm, self).__init__(*args, **kwargs)
self.fields["users_removed"] = forms.ModelMultipleChoiceField(
User.objects.filter(id__in=self.current_users).all(),
label=_("Users to remove from group"),
required=False,
widget=forms.CheckboxSelectMultiple,
)
users_added = AutoCompleteSelectMultipleField(
"users",
label=_("Users to add to group"),
help_text=_("Search users to add (one or more)."),
required=False,
)
def clean_users_added(self):
"""
Check that the user is not trying to add an user already in the group
"""
cleaned_data = super(EditMembersForm, self).clean()
users_added = cleaned_data.get("users_added", None)
if not users_added:
return users_added
current_users = [
str(id_) for id_ in self.current_users.values_list("id", flat=True)
]
for user in users_added:
if user in current_users:
raise forms.ValidationError(
_("You can not add the same user twice"), code="invalid"
)
return users_added
# Views
class GroupListView(CanEditMixin, ListView): class GroupListView(CanEditMixin, ListView):
""" """
Displays the group list Displays the Group list
""" """
model = RealGroup model = RealGroup
ordering = ["name"]
template_name = "core/group_list.jinja" template_name = "core/group_list.jinja"
class GroupEditView(CanEditMixin, UpdateView): class GroupEditView(CanEditMixin, UpdateView):
"""
Edit infos of a Group
"""
model = RealGroup model = RealGroup
pk_url_kwarg = "group_id" pk_url_kwarg = "group_id"
template_name = "core/group_edit.jinja" template_name = "core/group_edit.jinja"
@ -47,12 +110,55 @@ class GroupEditView(CanEditMixin, UpdateView):
class GroupCreateView(CanEditMixin, CreateView): class GroupCreateView(CanEditMixin, CreateView):
"""
Add a new Group
"""
model = RealGroup model = RealGroup
template_name = "core/group_edit.jinja" template_name = "core/group_edit.jinja"
fields = ["name", "description"] fields = ["name", "description"]
class GroupTemplateView(CanEditMixin, DetailFormView):
"""
Display all users in a given Group
Allow adding and removing users from it
"""
model = RealGroup
form_class = EditMembersForm
pk_url_kwarg = "group_id"
template_name = "core/group_detail.jinja"
def form_valid(self, form):
resp = super(GroupTemplateView, self).form_valid(form)
data = form.clean()
group = self.get_object()
for user in data["users_removed"]:
group.users.remove(user)
for user in data["users_added"]:
group.users.add(user)
group.save()
return resp
def get_success_url(self):
return reverse_lazy(
"core:group_detail", kwargs={"group_id": self.get_object().id}
)
def get_form_kwargs(self):
kwargs = super(GroupTemplateView, self).get_form_kwargs()
kwargs["users"] = self.get_object().users.all()
return kwargs
class GroupDeleteView(CanEditMixin, DeleteView): class GroupDeleteView(CanEditMixin, DeleteView):
"""
Delete a Group
"""
model = RealGroup model = RealGroup
pk_url_kwarg = "group_id" pk_url_kwarg = "group_id"
template_name = "core/delete_confirm.jinja" template_name = "core/delete_confirm.jinja"

View File

@ -6,7 +6,7 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-03-19 17:16+0100\n" "POT-Creation-Date: 2019-04-22 14:57+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"
@ -361,7 +361,8 @@ msgstr "Compte en banque : "
#: com/templates/com/weekmail.jinja:62 core/templates/core/file_detail.jinja:25 #: com/templates/com/weekmail.jinja:62 core/templates/core/file_detail.jinja:25
#: core/templates/core/file_detail.jinja:62 #: core/templates/core/file_detail.jinja:62
#: core/templates/core/file_moderation.jinja:24 #: core/templates/core/file_moderation.jinja:24
#: core/templates/core/group_list.jinja:13 core/templates/core/macros.jinja:93 #: core/templates/core/group_detail.jinja:26
#: core/templates/core/group_list.jinja:25 core/templates/core/macros.jinja:93
#: core/templates/core/macros.jinja:112 core/templates/core/page_prop.jinja:14 #: core/templates/core/macros.jinja:112 core/templates/core/page_prop.jinja:14
#: core/templates/core/user_account_detail.jinja:38 #: core/templates/core/user_account_detail.jinja:38
#: core/templates/core/user_detail.jinja:178 #: core/templates/core/user_detail.jinja:178
@ -417,7 +418,8 @@ msgstr "Nouveau compte club"
#: com/templates/com/poster_list.jinja:45 #: com/templates/com/poster_list.jinja:45
#: com/templates/com/screen_list.jinja:26 com/templates/com/weekmail.jinja:32 #: com/templates/com/screen_list.jinja:26 com/templates/com/weekmail.jinja:32
#: com/templates/com/weekmail.jinja:61 core/templates/core/file.jinja:38 #: com/templates/com/weekmail.jinja:61 core/templates/core/file.jinja:38
#: core/templates/core/page.jinja:35 core/templates/core/poster_list.jinja:40 #: core/templates/core/group_list.jinja:24 core/templates/core/page.jinja:35
#: core/templates/core/poster_list.jinja:40
#: core/templates/core/user_tools.jinja:42 core/views/user.py:237 #: core/templates/core/user_tools.jinja:42 core/views/user.py:237
#: counter/templates/counter/cash_summary_list.jinja:53 #: counter/templates/counter/cash_summary_list.jinja:53
#: counter/templates/counter/counter_list.jinja:17 #: counter/templates/counter/counter_list.jinja:17
@ -1031,6 +1033,7 @@ msgstr "Rôle"
#: club/templates/club/club_members.jinja:10 #: club/templates/club/club_members.jinja:10
#: 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/user_clubs.jinja:17 #: core/templates/core/user_clubs.jinja:17
#: core/templates/core/user_clubs.jinja:43 #: core/templates/core/user_clubs.jinja:43
msgid "Description" msgid "Description"
@ -2572,10 +2575,19 @@ msgstr "Modération des fichiers"
msgid "Full name: " msgid "Full name: "
msgstr "Nom complet : " msgstr "Nom complet : "
#: core/templates/core/group_detail.jinja:5
msgid "Group detail"
msgstr "Détail du groupe"
#: core/templates/core/group_detail.jinja:10
#: core/templates/core/group_edit.jinja:4 #: core/templates/core/group_edit.jinja:4
msgid "Back to list" msgid "Back to list"
msgstr "Retour à la liste" msgstr "Retour à la liste"
#: core/templates/core/group_detail.jinja:12
msgid "No user in this group"
msgstr "Aucun utilisateur dans ce groupe"
#: core/templates/core/group_edit.jinja:5 #: core/templates/core/group_edit.jinja:5
msgid "Edit group" msgid "Edit group"
msgstr "Éditer le groupe" msgstr "Éditer le groupe"
@ -2595,6 +2607,14 @@ msgstr "Liste des groupes"
msgid "New group" msgid "New group"
msgstr "Nouveau groupe" msgstr "Nouveau groupe"
#: core/templates/core/group_list.jinja:13
msgid "ID"
msgstr "ID"
#: core/templates/core/group_list.jinja:14
msgid "Group"
msgstr "Groupe"
#: core/templates/core/login.jinja:10 #: core/templates/core/login.jinja:10
msgid "Your username and password didn't match. Please try again." msgid "Your username and password didn't match. Please try again."
msgstr "" msgstr ""
@ -2660,6 +2680,14 @@ msgstr "actuel"
msgid "Next" msgid "Next"
msgstr "Suivant" msgstr "Suivant"
#: core/templates/core/macros.jinja:147
msgid "Select All"
msgstr "Tout sélectionner"
#: core/templates/core/macros.jinja:148
msgid "Unselect All"
msgstr "Tout désélectionner"
#: core/templates/core/macros_pages.jinja:4 #: core/templates/core/macros_pages.jinja:4
#, python-format #, python-format
msgid "You're seeing the history of page \"%(page_name)s\"" msgid "You're seeing the history of page \"%(page_name)s\""
@ -3489,6 +3517,22 @@ msgstr "groupe d'édition"
msgid "view groups" msgid "view groups"
msgstr "groupe de vue" msgstr "groupe de vue"
#: core/views/group.py:55
msgid "Users to remove from group"
msgstr "Utilisateurs à retirer du groupe"
#: core/views/group.py:62
msgid "Users to add to group"
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"