diff --git a/src/open_inwoner/cms/objects/cms_plugins.py b/src/open_inwoner/cms/objects/cms_plugins.py
index 2fc06260cb..f62bdb2748 100644
--- a/src/open_inwoner/cms/objects/cms_plugins.py
+++ b/src/open_inwoner/cms/objects/cms_plugins.py
@@ -3,7 +3,7 @@
from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool
-from .models import ObjectsList
+from .models import ComponentChoices, ObjectsList
@plugin_pool.register_plugin
@@ -12,3 +12,28 @@ class ObjectsListPlugin(CMSPluginBase):
name = _("Object List Plugin")
render_template = "cms/objects/objects_list.html"
cache = False
+
+ def _get_render_template(self, context, instance, placeholder):
+ default_template = super()._get_render_template(context, instance, placeholder)
+ if component := instance.component:
+ match component:
+ case ComponentChoices.link:
+ return "cms/objects/objects_list.html"
+ case ComponentChoices.map:
+ return "cms/objects/objects_map.html"
+
+ return default_template
+
+ def render(self, context, instance, placeholder):
+ request = context["request"]
+ context["instance"] = instance
+ context["objects"] = []
+
+ if request.user.is_authenticated and (bsn := request.user.bsn):
+ objects = instance.get_objects_by_bsn(bsn)
+ match instance.component:
+ case ComponentChoices.link:
+ context["objects"] = instance.convert_objects_to_actiondata(objects)
+ case ComponentChoices.map:
+ context["objects"] = instance.convert_objects_to_geodata(objects)
+ return context
diff --git a/src/open_inwoner/cms/objects/constants.py b/src/open_inwoner/cms/objects/constants.py
new file mode 100644
index 0000000000..7f0fe7c840
--- /dev/null
+++ b/src/open_inwoner/cms/objects/constants.py
@@ -0,0 +1,20 @@
+from django.utils.translation import ugettext_lazy as _
+
+from djchoices import ChoiceItem, DjangoChoices
+
+
+class StatusChoices(DjangoChoices):
+ open = ChoiceItem("open", _("Open"))
+ submitted = ChoiceItem("ingediend", _("Submitted"))
+ processed = ChoiceItem("verwerkt", _("Processed"))
+ closed = ChoiceItem("gesloten", _("Closed"))
+
+
+class DateOrderChoices(DjangoChoices):
+ ascend = ChoiceItem("+", _("Ascend"))
+ descent = ChoiceItem("-", _("Descent"))
+
+
+class ComponentChoices(DjangoChoices):
+ link = ChoiceItem("link", _("Link"))
+ map = ChoiceItem("map", _("Map"))
diff --git a/src/open_inwoner/cms/objects/migrations/0002_auto_20231006_1047.py b/src/open_inwoner/cms/objects/migrations/0002_auto_20231006_1047.py
new file mode 100644
index 0000000000..c6c27c42fe
--- /dev/null
+++ b/src/open_inwoner/cms/objects/migrations/0002_auto_20231006_1047.py
@@ -0,0 +1,131 @@
+# Generated by Django 3.2.20 on 2023-10-06 08:47
+
+import django.core.validators
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("objects", "0001_initial"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="objectslist",
+ name="bsn_path",
+ field=models.CharField(
+ blank=True,
+ help_text="The path to the bsn value from data, for example: 'identificatie.value'",
+ max_length=250,
+ verbose_name="BSN Path",
+ ),
+ ),
+ migrations.AddField(
+ model_name="objectslist",
+ name="component",
+ field=models.CharField(
+ choices=[("link", "Link"), ("map", "Map")],
+ default="link",
+ max_length=30,
+ verbose_name="Component",
+ ),
+ ),
+ migrations.AddField(
+ model_name="objectslist",
+ name="date_order",
+ field=models.CharField(
+ choices=[("+", "Ascend"), ("-", "Descent")],
+ default="-",
+ help_text="Order date on acending or decending.",
+ max_length=1,
+ verbose_name="Date Order",
+ ),
+ ),
+ migrations.AddField(
+ model_name="objectslist",
+ name="map_lat",
+ field=models.DecimalField(
+ decimal_places=6,
+ default=52.1326,
+ max_digits=9,
+ verbose_name="Map starting Latitude",
+ ),
+ ),
+ migrations.AddField(
+ model_name="objectslist",
+ name="map_long",
+ field=models.DecimalField(
+ decimal_places=6,
+ default=5.2913,
+ max_digits=9,
+ verbose_name="Map starting Longitude",
+ ),
+ ),
+ migrations.AddField(
+ model_name="objectslist",
+ name="map_zoom_level",
+ field=models.IntegerField(
+ default=3,
+ validators=[
+ django.core.validators.MaxValueValidator(18),
+ django.core.validators.MinValueValidator(1),
+ ],
+ verbose_name="Map starting Longitude",
+ ),
+ ),
+ migrations.AddField(
+ model_name="objectslist",
+ name="no_results_message",
+ field=models.TextField(
+ default="no results found",
+ help_text="Text message to tell the user that there are no results found",
+ verbose_name="No results message",
+ ),
+ preserve_default=False,
+ ),
+ migrations.AddField(
+ model_name="objectslist",
+ name="object_date",
+ field=models.CharField(
+ default="start_at",
+ help_text="The path to the date, for example: 'start_at'",
+ max_length=250,
+ verbose_name="Object Date",
+ ),
+ ),
+ migrations.AddField(
+ model_name="objectslist",
+ name="object_link",
+ field=models.CharField(
+ default="data.formulier.value",
+ help_text="The path to the url, for example: 'data.formulier.value'",
+ max_length=250,
+ verbose_name="Object Link",
+ ),
+ ),
+ migrations.AddField(
+ model_name="objectslist",
+ name="object_title",
+ field=models.CharField(
+ default="data.title",
+ help_text="The path to the title, for example: 'data.title'",
+ max_length=250,
+ verbose_name="Object Title",
+ ),
+ ),
+ migrations.AddField(
+ model_name="objectslist",
+ name="status",
+ field=models.CharField(
+ blank=True,
+ choices=[
+ ("open", "Open"),
+ ("ingediend", "Submitted"),
+ ("verwerkt", "Processed"),
+ ("gesloten", "Closed"),
+ ],
+ max_length=250,
+ verbose_name="Status",
+ ),
+ ),
+ ]
diff --git a/src/open_inwoner/cms/objects/models.py b/src/open_inwoner/cms/objects/models.py
index d2da14c207..b578786c32 100644
--- a/src/open_inwoner/cms/objects/models.py
+++ b/src/open_inwoner/cms/objects/models.py
@@ -1,20 +1,147 @@
-import os
+import json
+from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from django.utils.translation import ugettext_lazy as _
from cms.models import CMSPlugin
+from glom import glom
+from glom.core import PathAccessError, PathAssignError
from objectsapiclient.models import Configuration, ObjectTypeField
+from .constants import ComponentChoices, DateOrderChoices, StatusChoices
+
class ObjectsList(CMSPlugin):
title = models.CharField(_("Title"), max_length=250)
object_type = ObjectTypeField() # Stores the UUID of the selected object_type
+ status = models.CharField(
+ _("Status"),
+ max_length=250,
+ choices=StatusChoices.choices,
+ blank=True,
+ )
+ component = models.CharField(
+ _("Component"),
+ max_length=30,
+ choices=ComponentChoices.choices,
+ default=ComponentChoices.link,
+ )
+ no_results_message = models.TextField(
+ _("No results message"),
+ help_text=_("Text message to tell the user that there are no results found"),
+ )
+ date_order = models.CharField(
+ _("Date Order"),
+ help_text=_("Order date on acending or decending."),
+ max_length=1,
+ choices=DateOrderChoices.choices,
+ default=DateOrderChoices.descent,
+ )
+ map_lat = models.DecimalField(
+ _("Map starting Latitude"), max_digits=9, decimal_places=6, default=52.1326
+ )
+ map_long = models.DecimalField(
+ _("Map starting Longitude"), max_digits=9, decimal_places=6, default=5.2913
+ )
+ map_zoom_level = models.IntegerField(
+ _("Map starting Longitude"),
+ validators=[MaxValueValidator(18), MinValueValidator(1)],
+ default=3,
+ )
+ bsn_path = models.CharField(
+ _("BSN Path"),
+ max_length=250,
+ help_text=_(
+ "The path to the bsn value from data, for example: 'identificatie.value'"
+ ),
+ blank=True,
+ )
+ object_title = models.CharField(
+ _("Object Title"),
+ max_length=250,
+ default="data.title",
+ help_text=_("The path to the title, for example: 'data.title'"),
+ )
+ object_date = models.CharField(
+ _("Object Date"),
+ max_length=250,
+ default="start_at",
+ help_text=_("The path to the date, for example: 'start_at'"),
+ )
+ object_link = models.CharField(
+ _("Object Link"),
+ max_length=250,
+ default="data.formulier.value",
+ help_text=_("The path to the url, for example: 'data.formulier.value'"),
+ )
+
+ def _return_self(self):
+ return f"{self.title}, {self.object_type}, {self.bsn_path}"
def get_objects(self):
return Configuration.get_solo().client.get_objects(
object_type_uuid=self.object_type
)
+ def get_objects_by_bsn(self, bsn):
+ data_attrs = []
+ if self.object_type and self.bsn_path:
+ data_attrs.append(
+ "__".join(self.bsn_path.split(".")) + "__exact__" + str(bsn)
+ )
+ if self.status:
+ data_attrs.append("status__exact__" + self.status)
+
+ return Configuration.get_solo().client.get_objects_by_bsn(
+ object_type_uuid=self.object_type,
+ ordering=self.date_order + "record__startAt",
+ data_attrs=",".join(data_attrs),
+ )
+
+ def convert_objects_to_actiondata(self, objects):
+ object_list = []
+ if objects:
+ for object in objects:
+ try:
+ object_list.append(
+ {
+ "title": glom(object.record, self.object_title),
+ "date": glom(object.record, self.object_date),
+ "link": glom(object.record, self.object_link),
+ }
+ )
+ except (PathAccessError, PathAssignError):
+ pass
+
+ return object_list
+
+ def convert_objects_to_geodata(self, objects):
+ features = []
+ if objects:
+ for object in objects:
+ if geometry := object.record.get("geometry"):
+ try:
+ features.append(
+ {
+ "type": "Feature",
+ "geometry": geometry,
+ "properties": {
+ "name": glom(object.record, self.object_title),
+ "date": glom(object.record, self.object_date),
+ "link": glom(object.record, self.object_link),
+ },
+ }
+ )
+ except (PathAccessError, PathAssignError):
+ pass
+
+ return json.dumps(
+ {
+ "type": "FeatureCollection",
+ "features": features,
+ }
+ )
+
def __str__(self):
return self.title
diff --git a/src/open_inwoner/components/templates/components/DenhaagAction/DenhaagAction.html b/src/open_inwoner/components/templates/components/DenhaagAction/DenhaagAction.html
new file mode 100644
index 0000000000..bd5d5972d3
--- /dev/null
+++ b/src/open_inwoner/components/templates/components/DenhaagAction/DenhaagAction.html
@@ -0,0 +1,15 @@
+{% load l10n i18n %}
+
+
+
${displayAddress1}
` : '') + + (displayAddress2 ? `${displayAddress2}
` : '') + + (displayDate ? `${displayDate}
` : '') + + (displayPhonenumber ? phonenumberElement : '') + + (displayEmail ? emailElement : '') + + (buttonLink ? buttonLinkElement : '') + + '{{ instance.no_results_message }}
+ {% endif %}{{ instance.no_results_message }}
+ {% endif %} +