From f6553a8f52b1cb2acd36a55708aa0b3e5c545805 Mon Sep 17 00:00:00 2001 From: klmp200 Date: Thu, 26 Apr 2018 18:33:10 +0200 Subject: [PATCH 01/11] Group management enhacement --- core/templates/core/group_detail.jinja | 18 ++++++++++++++++++ core/templates/core/group_list.jinja | 22 ++++++++++++++++------ core/urls.py | 5 +++++ core/views/group.py | 9 ++++++++- 4 files changed, 47 insertions(+), 7 deletions(-) create mode 100644 core/templates/core/group_detail.jinja diff --git a/core/templates/core/group_detail.jinja b/core/templates/core/group_detail.jinja new file mode 100644 index 00000000..58ec1f89 --- /dev/null +++ b/core/templates/core/group_detail.jinja @@ -0,0 +1,18 @@ +{% extends "core/base.jinja" %} + +{% block title %} + {% trans %}Group detail{% endtrans %} +{% endblock title %} + +{% block content %} +

{% trans %}Back to list{% endtrans %}

+ {% if not object.users.exists() %} +

{% trans %}No user in this group{% endtrans %}

+ {% else %} + + {% endif %} +{% endblock content %} \ No newline at end of file diff --git a/core/templates/core/group_list.jinja b/core/templates/core/group_list.jinja index 79bb5de4..e1e926bb 100644 --- a/core/templates/core/group_list.jinja +++ b/core/templates/core/group_list.jinja @@ -7,11 +7,21 @@ {% block content %}

{% trans %}Group list{% endtrans %}

{% trans %}New group{% endtrans %}

- + + + + + + + {% for group in object_list %} + + + + + + + + {% endfor %} +
{% trans %}ID{% endtrans %}{% trans %}Group{% endtrans %}{% trans %}Description{% endtrans %}
{{ group.id }}{{ group }}{{ group.description }}{% trans %}Edit{% endtrans %}{% trans %}Delete{% endtrans %}
{% endblock %} diff --git a/core/urls.py b/core/urls.py index be18ff8e..21398841 100644 --- a/core/urls.py +++ b/core/urls.py @@ -64,6 +64,11 @@ urlpatterns = [ GroupDeleteView.as_view(), name="group_delete", ), + url( + r"^group/(?P[0-9]+)/detail$", + GroupDetailView.as_view(), + name="group_detail", + ), # User views url(r"^user/$", UserListView.as_view(), name="user_list"), url( diff --git a/core/views/group.py b/core/views/group.py index 29864dbc..fb1f7996 100644 --- a/core/views/group.py +++ b/core/views/group.py @@ -23,7 +23,7 @@ # from django.views.generic.edit import UpdateView, CreateView, DeleteView -from django.views.generic import ListView +from django.views.generic import ListView, DetailView from django.core.urlresolvers import reverse_lazy from core.models import RealGroup @@ -36,6 +36,7 @@ class GroupListView(CanEditMixin, ListView): """ model = RealGroup + ordering = ["name"] template_name = "core/group_list.jinja" @@ -52,6 +53,12 @@ class GroupCreateView(CanEditMixin, CreateView): fields = ["name", "description"] +class GroupDetailView(CanEditMixin, DetailView): + model = RealGroup + pk_url_kwarg = "group_id" + template_name = "core/group_detail.jinja" + + class GroupDeleteView(CanEditMixin, DeleteView): model = RealGroup pk_url_kwarg = "group_id" From 5cc0760e2cf5f21e53704a6fcfd8b88728f3bf9a Mon Sep 17 00:00:00 2001 From: Bartuccio Antoine Date: Wed, 10 Apr 2019 01:22:00 +0200 Subject: [PATCH 02/11] Groups: allow bulk import of users on a group --- core/templates/core/group_detail.jinja | 10 +++ core/urls.py | 2 +- core/views/group.py | 88 +++++++++++++++++++++++++- 3 files changed, 96 insertions(+), 4 deletions(-) diff --git a/core/templates/core/group_detail.jinja b/core/templates/core/group_detail.jinja index 58ec1f89..adcc562b 100644 --- a/core/templates/core/group_detail.jinja +++ b/core/templates/core/group_detail.jinja @@ -15,4 +15,14 @@ {% endfor %} {% endif %} +
+ {% csrf_token %} +

+ {{ form.users_added.errors }} + + {{ form.users_added }} + {{ form.users_added.help_text }} +

+ +
{% endblock content %} \ No newline at end of file diff --git a/core/urls.py b/core/urls.py index 21398841..6798a6bb 100644 --- a/core/urls.py +++ b/core/urls.py @@ -66,7 +66,7 @@ urlpatterns = [ ), url( r"^group/(?P[0-9]+)/detail$", - GroupDetailView.as_view(), + GroupTemplateView.as_view(), name="group_detail", ), # User views diff --git a/core/views/group.py b/core/views/group.py index fb1f7996..76cf6d1e 100644 --- a/core/views/group.py +++ b/core/views/group.py @@ -22,17 +22,46 @@ # # +""" + This module contains views to manage Groups +""" + from django.views.generic.edit import UpdateView, CreateView, DeleteView -from django.views.generic import ListView, DetailView +from django.views.generic import ListView +from django.views.generic.edit import FormView from django.core.urlresolvers import reverse_lazy +from django.shortcuts import get_object_or_404 +from django.utils.functional import cached_property +from django.utils.translation import ugettext_lazy as _ +from django import forms + +from ajax_select.fields import AutoCompleteSelectMultipleField from core.models import RealGroup from core.views import CanEditMixin +# Forms + + +class EditMembersForm(forms.Form): + """ + Add and remove members from a Group + """ + + users_added = AutoCompleteSelectMultipleField( + "users", + label=_("Users to add"), + help_text=_("Search users to add (one or more)."), + required=False, + ) + + +# Views + class GroupListView(CanEditMixin, ListView): """ - Displays the group list + Displays the Group list """ model = RealGroup @@ -41,6 +70,10 @@ class GroupListView(CanEditMixin, ListView): class GroupEditView(CanEditMixin, UpdateView): + """ + Edit infos of a Group + """ + model = RealGroup pk_url_kwarg = "group_id" template_name = "core/group_edit.jinja" @@ -48,18 +81,67 @@ class GroupEditView(CanEditMixin, UpdateView): class GroupCreateView(CanEditMixin, CreateView): + """ + Add a new Group + """ + model = RealGroup template_name = "core/group_edit.jinja" fields = ["name", "description"] -class GroupDetailView(CanEditMixin, DetailView): +class GroupTemplateView(CanEditMixin, FormView): + """ + 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 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 get_object_or_404(self.model, pk=self.group_id) + + def dispatch(self, request, *args, **kwargs): + + self.group_id = kwargs[self.pk_url_kwarg] + return super(GroupTemplateView, self).dispatch(request, *args, **kwargs) + + def form_valid(self, form): + data = form.clean() + group = self.get_object() + for user in data["users_added"]: + group.users.add(user) + group.save() + + return super(GroupTemplateView, self).form_valid(form) + + def get_success_url(self): + return reverse_lazy("core:group_detail", kwargs={"group_id": self.group_id}) + + def get_context_data(self): + kwargs = super(GroupTemplateView, self).get_context_data() + kwargs["object"] = self.get_object() + return kwargs + class GroupDeleteView(CanEditMixin, DeleteView): + """ + Delete a Group + """ + model = RealGroup pk_url_kwarg = "group_id" template_name = "core/delete_confirm.jinja" From 34459f83ecaa3acc8e2be5fe8be1b59c808a8dcc Mon Sep 17 00:00:00 2001 From: Bartuccio Antoine Date: Wed, 10 Apr 2019 12:32:04 +0200 Subject: [PATCH 03/11] Group: Groups: allow bulk removing of users from a group --- core/templates/core/group_detail.jinja | 19 ++++++++---- core/views/group.py | 43 ++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/core/templates/core/group_detail.jinja b/core/templates/core/group_detail.jinja index adcc562b..5ce41fef 100644 --- a/core/templates/core/group_detail.jinja +++ b/core/templates/core/group_detail.jinja @@ -5,15 +5,22 @@ {% endblock title %} {% block content %} +

{{ object }}

{% trans %}Back to list{% endtrans %}

- {% if not object.users.exists() %} + {% if form.users_removed | length <= 0 %}

{% trans %}No user in this group{% endtrans %}

{% else %} -
    - {% for user in object.users.all() %} -
  • {{ user }}
  • - {% endfor %} -
+
+ {% csrf_token %} + {{ form.users_removed.errors }} + {% for user in form.users_removed %} + + {% endfor %} + +
{% endif %}
{% csrf_token %} diff --git a/core/views/group.py b/core/views/group.py index 76cf6d1e..b19a9bb3 100644 --- a/core/views/group.py +++ b/core/views/group.py @@ -37,7 +37,7 @@ from django import forms from ajax_select.fields import AutoCompleteSelectMultipleField -from core.models import RealGroup +from core.models import RealGroup, User from core.views import CanEditMixin # Forms @@ -48,6 +48,16 @@ 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=None, + required=False, + widget=forms.CheckboxSelectMultiple, + ) + users_added = AutoCompleteSelectMultipleField( "users", label=_("Users to add"), @@ -55,6 +65,23 @@ class EditMembersForm(forms.Form): required=False, ) + def clean_users_added(self): + 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 @@ -117,21 +144,31 @@ class GroupTemplateView(CanEditMixin, FormView): def dispatch(self, request, *args, **kwargs): self.group_id = kwargs[self.pk_url_kwarg] + self.users = self.get_object().users.all() return super(GroupTemplateView, self).dispatch(request, *args, **kwargs) 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 super(GroupTemplateView, self).form_valid(form) + return resp def get_success_url(self): return reverse_lazy("core:group_detail", kwargs={"group_id": self.group_id}) - def get_context_data(self): + def get_form_kwargs(self): + kwargs = super(GroupTemplateView, self).get_form_kwargs() + kwargs["users"] = self.users + return kwargs + + def get_context_data(self, *args, **kwargs): kwargs = super(GroupTemplateView, self).get_context_data() kwargs["object"] = self.get_object() return kwargs From 08d03087a475dbc4f6b71e9ff758e91fe3d47c9d Mon Sep 17 00:00:00 2001 From: Bartuccio Antoine Date: Wed, 10 Apr 2019 13:21:34 +0200 Subject: [PATCH 04/11] core: create a DetailFormView --- core/templates/core/group_detail.jinja | 2 +- core/views/__init__.py | 27 ++++++++++++++++++++++ core/views/group.py | 31 ++++++-------------------- 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/core/templates/core/group_detail.jinja b/core/templates/core/group_detail.jinja index 5ce41fef..a9572cc4 100644 --- a/core/templates/core/group_detail.jinja +++ b/core/templates/core/group_detail.jinja @@ -19,7 +19,7 @@ {{ user.tag() }} {% endfor %} - + {% endif %}
diff --git a/core/views/__init__.py b/core/views/__init__.py index 2d764237..c4972bd0 100644 --- a/core/views/__init__.py +++ b/core/views/__init__.py @@ -39,6 +39,9 @@ from django.core.exceptions import ( ImproperlyConfigured, ) 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 core.models import Group @@ -275,6 +278,30 @@ class QuickNotifMixin: 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 .page import * from .files import * diff --git a/core/views/group.py b/core/views/group.py index b19a9bb3..72f9b4f4 100644 --- a/core/views/group.py +++ b/core/views/group.py @@ -31,14 +31,13 @@ from django.views.generic import ListView from django.views.generic.edit import FormView from django.core.urlresolvers import reverse_lazy from django.shortcuts import get_object_or_404 -from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ from django import forms from ajax_select.fields import AutoCompleteSelectMultipleField from core.models import RealGroup, User -from core.views import CanEditMixin +from core.views import CanEditMixin, DetailFormView # Forms @@ -117,7 +116,7 @@ class GroupCreateView(CanEditMixin, CreateView): fields = ["name", "description"] -class GroupTemplateView(CanEditMixin, FormView): +class GroupTemplateView(CanEditMixin, DetailFormView): """ Display all users in a given Group Allow adding and removing users from it @@ -128,24 +127,11 @@ class GroupTemplateView(CanEditMixin, FormView): pk_url_kwarg = "group_id" template_name = "core/group_detail.jinja" - 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 get_object_or_404(self.model, pk=self.group_id) - def dispatch(self, request, *args, **kwargs): - self.group_id = kwargs[self.pk_url_kwarg] self.users = self.get_object().users.all() - return super(GroupTemplateView, self).dispatch(request, *args, **kwargs) + resp = super(GroupTemplateView, self).dispatch(request, *args, **kwargs) + return resp def form_valid(self, form): resp = super(GroupTemplateView, self).form_valid(form) @@ -161,18 +147,15 @@ class GroupTemplateView(CanEditMixin, FormView): return resp def get_success_url(self): - return reverse_lazy("core:group_detail", kwargs={"group_id": self.group_id}) + 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.users return kwargs - def get_context_data(self, *args, **kwargs): - kwargs = super(GroupTemplateView, self).get_context_data() - kwargs["object"] = self.get_object() - return kwargs - class GroupDeleteView(CanEditMixin, DeleteView): """ From b693ee32f29025448d301a48574b182d7a0d8fe4 Mon Sep 17 00:00:00 2001 From: Bartuccio Antoine Date: Wed, 10 Apr 2019 14:11:31 +0200 Subject: [PATCH 05/11] Group: add a label on users to delete --- core/templates/core/group_detail.jinja | 1 + core/views/group.py | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/core/templates/core/group_detail.jinja b/core/templates/core/group_detail.jinja index a9572cc4..e7da48b9 100644 --- a/core/templates/core/group_detail.jinja +++ b/core/templates/core/group_detail.jinja @@ -12,6 +12,7 @@ {% else %} {% csrf_token %} + {{ form.users_removed.errors }} {% for user in form.users_removed %}