Skip to content

Commit 3743516

Browse files
authored
Merge pull request #835 from maykinmedia/feature/1821-onderwerp-visibility-flags
✨ [#1821] Add visibility flags for Category model
2 parents 438f9a4 + b66ba9a commit 3743516

File tree

11 files changed

+302
-22
lines changed

11 files changed

+302
-22
lines changed

src/open_inwoner/cms/products/cms_plugins.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ def render(self, context, instance, placeholder):
2929

3030
# Highlighted categories
3131
highlighted_categories = (
32-
Category.objects.published().filter(highlighted=True).order_by("path")
32+
Category.objects.published()
33+
.visible_for_user(request.user)
34+
.filter(highlighted=True)
35+
.order_by("path")
3336
)
3437
if request.user.is_authenticated and request.user.selected_categories.exists():
3538
categories = request.user.selected_categories.order_by("name")[: self.limit]

src/open_inwoner/cms/products/tests/test_plugin_categories.py

+48-6
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,35 @@ def setUp(self):
2323

2424
def test_only_highlighted_categories_exist_in_context_when_they_exist(self):
2525
CategoryFactory(name="Should be first")
26-
highlighted_category = CategoryFactory(
27-
name="This should be second", highlighted=True
26+
highlighted_category1 = CategoryFactory(
27+
name="This should be second",
28+
highlighted=True,
29+
visible_for_anonymous=True,
30+
visible_for_authenticated=True,
31+
)
32+
highlighted_category2 = CategoryFactory(
33+
path="0002",
34+
highlighted=True,
35+
visible_for_anonymous=True,
36+
visible_for_authenticated=False,
37+
)
38+
highlighted_category3 = CategoryFactory(
39+
path="0003",
40+
highlighted=True,
41+
visible_for_anonymous=False,
42+
visible_for_authenticated=True,
43+
)
44+
highlighted_category4 = CategoryFactory(
45+
path="0004",
46+
highlighted=True,
47+
visible_for_anonymous=False,
48+
visible_for_authenticated=False,
2849
)
2950

3051
html, context = cms_tools.render_plugin(CategoriesPlugin)
3152
self.assertEqual(
3253
list(context["categories"]),
33-
[highlighted_category],
54+
[highlighted_category1, highlighted_category2],
3455
)
3556

3657
def test_highlighted_categories_are_ordered_by_alphabetically(self):
@@ -49,15 +70,36 @@ def test_highlighted_categories_are_ordered_by_alphabetically(self):
4970
def test_only_highlighted_categories_are_shown_when_they_exist(self):
5071
user = UserFactory()
5172
category = CategoryFactory(name="Should be first")
52-
highlighted_category = CategoryFactory(
53-
name="This should be second", highlighted=True
73+
highlighted_category1 = CategoryFactory(
74+
name="This should be second",
75+
highlighted=True,
76+
visible_for_anonymous=True,
77+
visible_for_authenticated=True,
78+
)
79+
highlighted_category2 = CategoryFactory(
80+
path="0002",
81+
highlighted=True,
82+
visible_for_anonymous=True,
83+
visible_for_authenticated=False,
84+
)
85+
highlighted_category3 = CategoryFactory(
86+
path="0003",
87+
highlighted=True,
88+
visible_for_anonymous=False,
89+
visible_for_authenticated=True,
90+
)
91+
highlighted_category4 = CategoryFactory(
92+
path="0004",
93+
highlighted=True,
94+
visible_for_anonymous=False,
95+
visible_for_authenticated=False,
5496
)
5597

5698
html, context = cms_tools.render_plugin(CategoriesPlugin, user=user)
5799

58100
self.assertEqual(
59101
list(context["categories"]),
60-
[highlighted_category],
102+
[highlighted_category1, highlighted_category3],
61103
)
62104

63105
def test_category_selected(self):

src/open_inwoner/components/tests/test_header.py

+55-2
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,32 @@ def setUpTestData(cls):
2323
# PrimaryNavigation.html requires apphook + categories
2424
create_apphook_page(ProductsApphook)
2525
cls.published1 = CategoryFactory(
26-
path="0001", name="First one", slug="first-one"
26+
path="0001",
27+
name="First one",
28+
slug="first-one",
29+
visible_for_anonymous=True,
30+
visible_for_authenticated=True,
2731
)
2832
cls.published2 = CategoryFactory(
29-
path="0002", name="Second one", slug="second-one"
33+
path="0002",
34+
name="Second one",
35+
slug="second-one",
36+
visible_for_anonymous=True,
37+
visible_for_authenticated=False,
38+
)
39+
cls.published3 = CategoryFactory(
40+
path="0003",
41+
name="Third one",
42+
slug="third-one",
43+
visible_for_anonymous=False,
44+
visible_for_authenticated=True,
45+
)
46+
cls.published4 = CategoryFactory(
47+
path="0004",
48+
name="Fourth one",
49+
slug="fourth-one",
50+
visible_for_anonymous=False,
51+
visible_for_authenticated=False,
3052
)
3153

3254
def test_categories_hidden_from_anonymous_users(self):
@@ -55,6 +77,37 @@ def test_categories_not_hidden_from_anonymous_users(self):
5577
self.assertEqual(categories[0].tag, "a")
5678
self.assertEqual(categories[1].tag, "button")
5779

80+
links = [x for x in doc.find("[title='Onderwerpen'] + ul li a").items()]
81+
self.assertEqual(len(links), 4)
82+
self.assertEqual(links[0].attr("href"), self.published1.get_absolute_url())
83+
self.assertEqual(links[1].attr("href"), self.published2.get_absolute_url())
84+
self.assertEqual(links[2].attr("href"), self.published1.get_absolute_url())
85+
self.assertEqual(links[3].attr("href"), self.published2.get_absolute_url())
86+
87+
def test_categories_visibility_for_authenticated_users(self):
88+
config = SiteConfiguration.get_solo()
89+
config.hide_categories_from_anonymous_users = False
90+
config.save()
91+
92+
self.client.force_login(self.user)
93+
94+
response = self.client.get("/", user=self.user)
95+
96+
doc = PyQuery(response.content)
97+
98+
categories = doc.find("[title='Onderwerpen']")
99+
100+
self.assertEqual(len(categories), 2)
101+
self.assertEqual(categories[0].tag, "a")
102+
self.assertEqual(categories[1].tag, "button")
103+
104+
links = [x for x in doc.find("[title='Onderwerpen'] + ul li a").items()]
105+
self.assertEqual(len(links), 4)
106+
self.assertEqual(links[0].attr("href"), self.published1.get_absolute_url())
107+
self.assertEqual(links[1].attr("href"), self.published3.get_absolute_url())
108+
self.assertEqual(links[2].attr("href"), self.published1.get_absolute_url())
109+
self.assertEqual(links[3].attr("href"), self.published3.get_absolute_url())
110+
58111
def test_search_bar_hidden_from_anonymous_users(self):
59112
config = SiteConfiguration.get_solo()
60113
config.hide_search_from_anonymous_users = True

src/open_inwoner/pdc/admin/category.py

+23-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
from django.forms import BaseModelFormSet
44
from django.utils.translation import gettext as _
55

6+
from django_better_admin_arrayfield.admin.mixins import DynamicArrayMixin
7+
from django_better_admin_arrayfield.forms.widgets import DynamicArrayWidget
68
from import_export.admin import ImportExportMixin
79
from import_export.formats import base_formats
810
from ordered_model.admin import OrderedInlineModelAdminMixin, OrderedTabularInline
@@ -32,7 +34,7 @@ class CategoryAdminForm(movenodeform_factory(Category)):
3234
class Meta:
3335
model = Category
3436
fields = "__all__"
35-
widgets = {"description": CKEditorWidget}
37+
widgets = {"description": CKEditorWidget, "zaaktypen": DynamicArrayWidget}
3638

3739
def clean(self, *args, **kwargs):
3840
cleaned_data = super().clean(*args, **kwargs)
@@ -71,7 +73,9 @@ def clean(self):
7173

7274

7375
@admin.register(Category)
74-
class CategoryAdmin(OrderedInlineModelAdminMixin, ImportExportMixin, TreeAdmin):
76+
class CategoryAdmin(
77+
DynamicArrayMixin, OrderedInlineModelAdminMixin, ImportExportMixin, TreeAdmin
78+
):
7579
change_list_template = "admin/category_change_list.html"
7680
form = CategoryAdminForm
7781
inlines = (
@@ -81,8 +85,23 @@ class CategoryAdmin(OrderedInlineModelAdminMixin, ImportExportMixin, TreeAdmin):
8185
prepopulated_fields = {"slug": ("name",)}
8286
search_fields = ("name",)
8387
ordering = ("path",)
84-
list_display = ("name", "highlighted", "published")
85-
list_editable = ("highlighted", "published")
88+
list_display = (
89+
"name",
90+
"highlighted",
91+
"published",
92+
"visible_for_anonymous",
93+
"visible_for_authenticated",
94+
"visible_for_companies",
95+
"visible_for_citizens",
96+
)
97+
list_editable = (
98+
"highlighted",
99+
"published",
100+
"visible_for_anonymous",
101+
"visible_for_authenticated",
102+
"visible_for_companies",
103+
"visible_for_citizens",
104+
)
86105
exclude = ("path", "depth", "numchild")
87106

88107
# import-export

src/open_inwoner/pdc/managers.py

+7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
from ordered_model.models import OrderedModelQuerySet
44
from treebeard.mp_tree import MP_NodeQuerySet
55

6+
from open_inwoner.accounts.models import User
7+
68

79
class ProductQueryset(models.QuerySet):
810
def published(self):
@@ -22,6 +24,11 @@ def published(self):
2224
def draft(self):
2325
return self.filter(published=False)
2426

27+
def visible_for_user(self, user: User):
28+
if user.is_authenticated:
29+
return self.filter(visible_for_authenticated=True)
30+
return self.filter(visible_for_anonymous=True)
31+
2532

2633
class QuestionQueryset(OrderedModelQuerySet):
2734
def general(self):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Generated by Django 3.2.20 on 2023-11-06 11:07
2+
3+
import django.contrib.postgres.fields
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
("pdc", "0060_content_collapsable"),
11+
]
12+
13+
operations = [
14+
migrations.AddField(
15+
model_name="category",
16+
name="relevante_zaakperiode",
17+
field=models.PositiveIntegerField(
18+
blank=True,
19+
help_text="Aantal maanden dat teruggekeken moet worden naar Zaken van deze zaaktypes.",
20+
null=True,
21+
verbose_name="Relevante zaakperiode",
22+
),
23+
),
24+
migrations.AddField(
25+
model_name="category",
26+
name="visible_for_anonymous",
27+
field=models.BooleanField(
28+
default=True,
29+
help_text="Of het onderwerp zichtbaar moet zijn op het anonieme deel (zonder inloggen).",
30+
verbose_name="Anonieme deel",
31+
),
32+
),
33+
migrations.AddField(
34+
model_name="category",
35+
name="visible_for_authenticated",
36+
field=models.BooleanField(
37+
default=True,
38+
help_text="Of het onderwerp zichtbaar moet zijn op het beveiligde deel (achter inloggen).",
39+
verbose_name="Beveiligde deel",
40+
),
41+
),
42+
migrations.AddField(
43+
model_name="category",
44+
name="visible_for_citizens",
45+
field=models.BooleanField(
46+
default=True,
47+
help_text="Of het onderwerp zichtbaar moet zijn wanneer iemand aangeeft een inwoner te zijn (of is ingelogd met BSN).",
48+
verbose_name="Inwoner content",
49+
),
50+
),
51+
migrations.AddField(
52+
model_name="category",
53+
name="visible_for_companies",
54+
field=models.BooleanField(
55+
default=True,
56+
help_text="Of het onderwerp zichtbaar moet zijn wanneer iemand aangeeft een bedrijf te zijn (of is ingelogd met KvK).",
57+
verbose_name="Bedrijven content",
58+
),
59+
),
60+
migrations.AddField(
61+
model_name="category",
62+
name="zaaktypen",
63+
field=django.contrib.postgres.fields.ArrayField(
64+
base_field=models.CharField(blank=True, max_length=1000),
65+
blank=True,
66+
default=list,
67+
help_text="Zaaktypen waarvoor bij aanwezigheid dit onderwerp getoond moet worden.",
68+
size=None,
69+
verbose_name="Zaaktypen",
70+
),
71+
),
72+
]

src/open_inwoner/pdc/models/category.py

+46
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from django.contrib.postgres.fields import ArrayField
12
from django.db import models
23
from django.urls import reverse
34
from django.utils.translation import ugettext_lazy as _
@@ -34,6 +35,51 @@ class Category(MP_Node):
3435
default=False,
3536
help_text=_("Whether the category should be published or not."),
3637
)
38+
visible_for_anonymous = models.BooleanField(
39+
verbose_name=_("Anonieme deel"),
40+
default=True,
41+
help_text=_(
42+
"Of het onderwerp zichtbaar moet zijn op het anonieme deel (zonder inloggen)."
43+
),
44+
)
45+
visible_for_authenticated = models.BooleanField(
46+
verbose_name=_("Beveiligde deel"),
47+
default=True,
48+
help_text=_(
49+
"Of het onderwerp zichtbaar moet zijn op het beveiligde deel (achter inloggen)."
50+
),
51+
)
52+
visible_for_companies = models.BooleanField(
53+
verbose_name=_("Bedrijven content"),
54+
default=True,
55+
help_text=_(
56+
"Of het onderwerp zichtbaar moet zijn wanneer iemand aangeeft een bedrijf te zijn (of is ingelogd met KvK)."
57+
),
58+
)
59+
visible_for_citizens = models.BooleanField(
60+
verbose_name=_("Inwoner content"),
61+
default=True,
62+
help_text=_(
63+
"Of het onderwerp zichtbaar moet zijn wanneer iemand aangeeft een inwoner te zijn (of is ingelogd met BSN)."
64+
),
65+
)
66+
zaaktypen = ArrayField(
67+
models.CharField(max_length=1000, blank=True),
68+
verbose_name=_("Zaaktypen"),
69+
default=list,
70+
blank=True,
71+
help_text=_(
72+
"Zaaktypen waarvoor bij aanwezigheid dit onderwerp getoond moet worden."
73+
),
74+
)
75+
relevante_zaakperiode = models.PositiveIntegerField(
76+
verbose_name=_("Relevante zaakperiode"),
77+
blank=True,
78+
null=True,
79+
help_text=_(
80+
"Aantal maanden dat teruggekeken moet worden naar Zaken van deze zaaktypes."
81+
),
82+
)
3783
highlighted = models.BooleanField(
3884
verbose_name=_("Highlighted"),
3985
default=False,

0 commit comments

Comments
 (0)