from django.contrib.auth import get_user_model from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin from django.http import HttpResponse, HttpResponseRedirect from django.urls import reverse, reverse_lazy from django.views.generic import DetailView, ListView, RedirectView, TemplateView from django.views.generic.detail import SingleObjectMixin from django.views.generic.edit import BaseFormView from wiki_groups.forms import CreateGroupForm, SelectGroupForm, SelectUserForm from wiki_groups.models import WikiGroup User = get_user_model() def dot_graph(request): response = HttpResponse(content_type="text/vnd.graphviz") response["Content-Disposition"] = 'attachment; filename="groups.dot"' response.write("digraph {\n") nodes = WikiGroup.objects.values_list("id", "django_group__name") edges = WikiGroup.includes_groups.through.objects.values_list( "to_wikigroup", "from_wikigroup" ) for id, name in nodes: response.write(' {} ["label"="{}"];\n'.format(id, name)) for u, v in edges: response.write(" {} -> {};\n".format(u, v)) response.write("}\n") return response graph = TemplateView.as_view(template_name="wiki_groups/graph.html") class WikiGroupMixin(SingleObjectMixin, UserPassesTestMixin): """ Restricts the view to a manager of the wikigroup, and selects automatically the required WikiGroup with its Django group """ model = WikiGroup def get_queryset(self): return super().get_queryset().select_related("django_group") def test_func(self): self.object = self.get_object() return self.request.user.is_staff or self.object.is_manager(self.request.user) class StaffMixin(UserPassesTestMixin): """Restricts the view to a staff member""" def test_func(self): return self.request.user.is_staff class ManagedGroupsView(LoginRequiredMixin, ListView): model = WikiGroup template_name = "wiki_groups/managed.html" def get_queryset(self): if self.request.user.is_staff: return WikiGroup.objects.select_related("django_group") return self.request.user.managed_groups.select_related("django_group") def get_context_data(self, **kwargs): ctx = super().get_context_data(**kwargs) wikigroups = set() for group in ctx["wikigroup_list"]: wikigroups |= group.get_all_groups() ctx["wikigroup_list"] = wikigroups ctx["object_list"] = wikigroups return ctx class WikiGroupView(WikiGroupMixin, DetailView): template_name = "wiki_groups/admin.html" def get_context_data(self, **kwargs): kwargs.update({"errors": self.request.session.pop("wiki_form_errors", None)}) return super().get_context_data(**kwargs) class RemoveUserView(WikiGroupMixin, RedirectView): def get_redirect_url(self, *args, **kwargs): return reverse("wiki_groups:admin-group", args=[kwargs["pk"]]) def get(self, request, *args, **kwargs): user = User.objects.filter(pk=kwargs["user_pk"]).first() if user is not None: self.object.users.remove(user) return super().get(request, *args, **kwargs) class RemoveManagerView(WikiGroupMixin, RedirectView): def get_redirect_url(self, *args, **kwargs): return reverse("wiki_groups:admin-group", args=[kwargs["pk"]]) def get(self, request, *args, **kwargs): user = User.objects.filter(pk=kwargs["user_pk"]).first() if user is not None: self.object.users.remove(user) self.object.managers.remove(user) return super().get(request, *args, **kwargs) class RemoveGroupView(WikiGroupMixin, RedirectView): def get_redirect_url(self, *args, **kwargs): return reverse("wiki_groups:admin-group", args=[kwargs["pk"]]) def get(self, request, *args, **kwargs): group = WikiGroup.objects.filter(pk=kwargs["group_pk"]).first() if group is not None: self.object.includes_groups.remove(group) return super().get(request, *args, **kwargs) class AddUserView(WikiGroupMixin, BaseFormView): form_class = SelectUserForm def get_success_url(self): return reverse("wiki_groups:admin-group", args=[self.object.pk]) def form_valid(self, form): self.object.users.add(form.cleaned_data["user"]) return super().form_valid(form) def form_invalid(self, form): self.request.session["wiki_form_errors"] = { "user": {"value": form["user"].value(), "msg": form.errors["user"]} } return HttpResponseRedirect(self.get_success_url()) class AddManagerView(WikiGroupMixin, BaseFormView): form_class = SelectUserForm def get_success_url(self): return reverse("wiki_groups:admin-group", args=[self.object.pk]) def form_valid(self, form): self.object.managers.add(form.cleaned_data["user"]) return super().form_valid(form) def form_invalid(self, form): self.request.session["wiki_form_errors"] = { "manager": {"value": form["user"].value(), "msg": form.errors["user"]} } return HttpResponseRedirect(self.get_success_url()) class AddGroupView(WikiGroupMixin, BaseFormView): form_class = SelectGroupForm def get_success_url(self): return reverse("wiki_groups:admin-group", args=[self.object.pk]) def form_valid(self, form): subgroup = form.cleaned_data["group"] group = self.object if group.group_in_cycle(list(group.includes_groups.all()) + [subgroup]): form.add_error( "group", ( "Ajout impossible sous peine de créer un cycle " f"({group} est inclus dans {subgroup})" ), ) return self.form_invalid(form) group.includes_groups.add(subgroup) return super().form_valid(form) def form_invalid(self, form): self.request.session["wiki_form_errors"] = { "group_add": {"value": form["group"].value(), "msg": form.errors["group"]} } return HttpResponseRedirect(self.get_success_url()) class CreateGroupView(WikiGroupMixin, BaseFormView): form_class = CreateGroupForm def get_success_url(self): return reverse("wiki_groups:admin-group", args=[self.object.pk]) def form_valid(self, form): new_group = form.cleaned_data["group"] self.object.includes_groups.add(new_group) new_group.managers.add(self.request.user) return super().form_valid(form) def form_invalid(self, form): self.request.session["wiki_form_errors"] = { "group_create": { "value": form["group"].value(), "msg": form.errors["group"], } } return HttpResponseRedirect(self.get_success_url()) class DeleteGroupView(SingleObjectMixin, StaffMixin, RedirectView): model = WikiGroup url = reverse_lazy("wiki_groups:managed-groups") def get(self, request, *args, **kwargs): group = self.get_object() # On enlève les membres pour répercuter les changements group.users.clear() # On utilise la propagation de la suppression django_group -> wiki_group group.django_group.delete() return super().get(request, *args, **kwargs)