From a7679a9bb4cbb7dc2955da8c1102b6131352ae2f Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Mon, 21 Sep 2020 12:39:29 +0200 Subject: [PATCH 01/10] requirements: Add django-treebeard Add django-treebeard [1] to requirements. Note, that django-treebeard is already requested by wagtail, because it is also used by wagtail for its pages. [1] https://django-treebeard.readthedocs.io/ --- requirements/base.in | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements/base.in b/requirements/base.in index ec5640a..92f3081 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -12,3 +12,4 @@ markdown pygments ics django-auth-ldap +django-treebeard From da7b16658f9924dab37c619324fd7c6db9c77036 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Mon, 21 Sep 2020 12:41:58 +0200 Subject: [PATCH 02/10] Update requirements Update requirements with (cd requirements && make) --- requirements/base.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/base.txt b/requirements/base.txt index 91e7ff3..d4cb5e7 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -14,7 +14,7 @@ django-filter==2.3.0 # via wagtail django-modelcluster==5.0.2 # via wagtail django-modeltranslation==0.15.1 # via wagtail-modeltranslation django-taggit==1.3.0 # via wagtail -django-treebeard==4.3.1 # via wagtail +django-treebeard==4.3.1 # via -r base.in, wagtail django==3.1 # via -r base.in, django-auth-ldap, django-filter, django-modeltranslation, django-taggit, django-treebeard, djangorestframework, wagtail djangorestframework==3.11.1 # via wagtail draftjs-exporter==2.1.7 # via wagtail From 3701d8a7157ba0739dbe9fad963562c422b7859b Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Mon, 21 Sep 2020 12:45:26 +0200 Subject: [PATCH 03/10] Add treabeard to INSTALLED_APPS --- config/settings/base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/config/settings/base.py b/config/settings/base.py index bc6f4b4..1f9f5b7 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -71,6 +71,7 @@ 'modelcluster', 'taggit', 'rest_framework', + 'treebeard', ] LOCAL_APPS = [ 'mpicms.base.apps.BaseAppConfig', From bfc088bf392091dcf90cd56592eaab3ad1f52649 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Mon, 21 Sep 2020 12:49:37 +0200 Subject: [PATCH 04/10] Make Group into a tree node Use MP_Node for Group and remove priority field. --- mpicms/personal/models.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/mpicms/personal/models.py b/mpicms/personal/models.py index e7c8035..444f77b 100644 --- a/mpicms/personal/models.py +++ b/mpicms/personal/models.py @@ -11,6 +11,8 @@ from modelcluster.models import ClusterableModel from modelcluster.fields import ParentalKey +from treebeard.mp_tree import MP_Node + class FilterableParentalKey(ParentalKey): def get_related_field(self): @@ -152,12 +154,9 @@ class Meta: # noqa @register_snippet -class Group(index.Indexed, ClusterableModel): +class Group(index.Indexed, ClusterableModel, MP_Node): slug = models.CharField(_("slug"), max_length=254) name = models.CharField(_("name"), max_length=254, blank=True) - priority = models.PositiveSmallIntegerField( - _("priority"), blank=True, default=0, validators=[MaxValueValidator(99)], - help_text=_("Priority from 0-99 to determine the sorting order.")) panels = [ FieldPanel('name'), @@ -179,4 +178,3 @@ def __str__(self): class Meta: # noqa verbose_name = 'Group' verbose_name_plural = 'Groups' - ordering = ['-priority'] From 1a2576068db4b62aa47049bae58ad966e68f25f5 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Fri, 25 Sep 2020 13:25:02 +0200 Subject: [PATCH 05/10] Add migration for personal Group model Add migration. Add the column "path" without the unique constraint and an invalid value first. Next, go over all group objects and set a path from a sequential index. Use alphabetical order, so that menus displayed be tree are in the same order as before unless sorted by the admin. As a last step add the unique contraint. --- .../personal/migrations/0027_group_to_tree.py | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 mpicms/personal/migrations/0027_group_to_tree.py diff --git a/mpicms/personal/migrations/0027_group_to_tree.py b/mpicms/personal/migrations/0027_group_to_tree.py new file mode 100644 index 0000000..2798bae --- /dev/null +++ b/mpicms/personal/migrations/0027_group_to_tree.py @@ -0,0 +1,59 @@ +from django.db import migrations, models +from treebeard.mp_tree import MP_Node + + +def update_path(apps, schema_editor): + + class Node(MP_Node): + # may overwrite, should match new model: + # steplen = 4 + # alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' + # node_order_by = [] + pass + + Group = apps.get_model("personal", "Group") + db_alias = schema_editor.connection.alias + + for i, group in enumerate(Group.objects.all().order_by('name'), 1): + group.path = Node._get_path(None, 1, i) + group.save(using=db_alias) + +class Migration(migrations.Migration): + + dependencies = [ + ('personal', '0026_auto_20200813_1342'), + ] + + operations = [ + migrations.AlterModelOptions( + name='group', + options={'verbose_name': 'Group', 'verbose_name_plural': 'Groups'}, + ), + migrations.RemoveField( + model_name='group', + name='priority', + ), + migrations.AddField( + model_name='group', + name='depth', + field=models.PositiveIntegerField(default=1), + preserve_default=False, + ), + migrations.AddField( + model_name='group', + name='numchild', + field=models.PositiveIntegerField(default=0), + ), + migrations.AddField( + model_name='group', + name='path', + field=models.CharField(default='', max_length=255), + preserve_default=False, + ), + migrations.RunPython(update_path, migrations.RunPython.noop), + migrations.AlterField( + model_name='group', + name='path', + field=models.CharField(max_length=255, unique=True), + ), + ] From 22a7af85f9591e7544a16388a8a87862f943d269 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Fri, 25 Sep 2020 13:32:07 +0200 Subject: [PATCH 06/10] Add admin interace for group tree management Add TreeAdmin for groups. Note, that TreeAdmin is based on Djangos ModelAdmin, not on Wagtails ModelAdmin. So we hook into Djangos admin-interface (available at /django-admin) Disable CSRF_COOKIE_HTTPONLY, because TreeAdmin uses Ajax over http to arrange the group tree. --- config/settings/base.py | 1 - mpicms/personal/admin.py | 10 ++++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 mpicms/personal/admin.py diff --git a/config/settings/base.py b/config/settings/base.py index 1f9f5b7..18a8f31 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -189,7 +189,6 @@ # SECURITY # ------------------------------------------------------------------------------ SESSION_COOKIE_HTTPONLY = True -CSRF_COOKIE_HTTPONLY = True SECURE_BROWSER_XSS_FILTER = True X_FRAME_OPTIONS = 'DENY' diff --git a/mpicms/personal/admin.py b/mpicms/personal/admin.py new file mode 100644 index 0000000..73f9e62 --- /dev/null +++ b/mpicms/personal/admin.py @@ -0,0 +1,10 @@ +from django.contrib import admin +from treebeard.admin import TreeAdmin +from treebeard.forms import movenodeform_factory +from mpicms.personal.models import Group + +class GroupAdmin(TreeAdmin): + form = movenodeform_factory(Group) + pass + +admin.site.register(Group, GroupAdmin) From 40dca951608f8114d2b0074ee26ac229ff0a434f Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Fri, 25 Sep 2020 14:35:16 +0200 Subject: [PATCH 07/10] Remove unneeded
The
before the "Reset filter" entry is not needed, because its at the top of the box. We already have a visual separation between "Reset filter" and the group names, because the later are in the .dropdown-content div, which as a little border. Remove
element. --- mpicms/templates/personal/list.html | 2 -- 1 file changed, 2 deletions(-) diff --git a/mpicms/templates/personal/list.html b/mpicms/templates/personal/list.html index 2382ada..19e87ba 100644 --- a/mpicms/templates/personal/list.html +++ b/mpicms/templates/personal/list.html @@ -15,7 +15,6 @@

{% trans 'Contact List' %}

From 3b4bc3b3653f3bea17333b8e9c415346419bd652 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Fri, 25 Sep 2020 14:39:03 +0200 Subject: [PATCH 08/10] Show groups in tree order in menu Add groups in tree order instead of alphabetical order to the context of the contacts page alphabetical order. Groups will be shown in that order in the drop-down menu. --- mpicms/personal/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mpicms/personal/views.py b/mpicms/personal/views.py index 740eeca..acac3bb 100644 --- a/mpicms/personal/views.py +++ b/mpicms/personal/views.py @@ -16,7 +16,7 @@ def get_queryset(self): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['groups'] = Group.objects.all().order_by("name") + context['groups'] = Group.get_tree() group_pk = self.request.GET.get('group') context['selected_group_pk'] = group_pk context['selected_group'] = get_object_or_404(Group, pk=group_pk) if group_pk else "" From 5db26fbbe2cbb85ef2cb6abeb677548523eba00f Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Fri, 25 Sep 2020 14:58:53 +0200 Subject: [PATCH 09/10] Group: Add get_depth_fill method Add a method which can be used by a template to get a number of   entities based on the depth of the group, Note: Yes, this is an ugly mixture of code and style. Should be fixed up by some clever CSS using the depth attribute only. --- mpicms/personal/models.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mpicms/personal/models.py b/mpicms/personal/models.py index 444f77b..3b1d133 100644 --- a/mpicms/personal/models.py +++ b/mpicms/personal/models.py @@ -1,5 +1,6 @@ from django.db import models from django.utils.translation import gettext_lazy as _ +from django.utils.safestring import mark_safe from django.core.validators import MaxValueValidator from wagtail.core.models import Orderable @@ -175,6 +176,9 @@ def members(self): def __str__(self): return self.name or self.slug + def get_depth_fill(self): + return (mark_safe(" " * ((self.get_depth()-1) * 2))) + class Meta: # noqa verbose_name = 'Group' verbose_name_plural = 'Groups' From 931b5a6ecd15a5871bcda3e48c748f93ad11ee92 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Fri, 25 Sep 2020 14:45:19 +0200 Subject: [PATCH 10/10] Show groups intended by depth in pulldown menu Use Group.get_depth_fill method to get some indention into the group pulldown menu. --- mpicms/templates/personal/list.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mpicms/templates/personal/list.html b/mpicms/templates/personal/list.html index 19e87ba..dba2463 100644 --- a/mpicms/templates/personal/list.html +++ b/mpicms/templates/personal/list.html @@ -21,7 +21,7 @@

{% trans 'Contact List' %}