diff --git a/app/apps/authenticatie/managers.py b/app/apps/authenticatie/managers.py
index a2e412cc..7e68a08e 100644
--- a/app/apps/authenticatie/managers.py
+++ b/app/apps/authenticatie/managers.py
@@ -1,6 +1,6 @@
from django.contrib.auth.base_user import BaseUserManager
from django.contrib.auth.hashers import make_password
-from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import gettext_lazy as _
class GebruikerManager(BaseUserManager):
diff --git a/app/apps/authenticatie/signal_receivers.py b/app/apps/authenticatie/signal_receivers.py
index 4b2fdc93..9d9ed4e4 100644
--- a/app/apps/authenticatie/signal_receivers.py
+++ b/app/apps/authenticatie/signal_receivers.py
@@ -12,6 +12,8 @@
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
+ if kwargs.get("raw"):
+ return
if not hasattr(instance, "profiel"):
Profiel.objects.create(gebruiker=instance)
try:
diff --git a/app/apps/authorisatie/apps.py b/app/apps/authorisatie/apps.py
new file mode 100644
index 00000000..eb0fadb8
--- /dev/null
+++ b/app/apps/authorisatie/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class AuthorisatieConfig(AppConfig):
+ name = "apps.authorisatie"
+ verbose_name = "Authorisatie"
diff --git a/app/apps/context/forms.py b/app/apps/context/forms.py
index d6ea0aea..8c5cca6b 100644
--- a/app/apps/context/forms.py
+++ b/app/apps/context/forms.py
@@ -3,7 +3,6 @@
from apps.context.constanten import FILTERS, KOLOMMEN
from apps.context.models import Context
from django import forms
-from utils.forms import RadioSelect
class CheckboxSelectMultiplePaths(forms.CheckboxSelectMultiple):
@@ -50,7 +49,7 @@ def optgroups(self, name, value, attrs=None):
class ContextAanpassenForm(forms.ModelForm):
template = forms.ChoiceField(
- widget=RadioSelect(
+ widget=forms.RadioSelect(
attrs={
"class": "list--form-radio-input",
}
diff --git a/app/apps/context/templates/context/context_form.html b/app/apps/context/templates/context/context_form.html
index eaa7d397..7bf67857 100644
--- a/app/apps/context/templates/context/context_form.html
+++ b/app/apps/context/templates/context/context_form.html
@@ -56,9 +56,12 @@
diff --git a/app/apps/context/templatetags/main_tags.py b/app/apps/context/templatetags/main_tags.py
index a439cb47..56bc8127 100644
--- a/app/apps/context/templatetags/main_tags.py
+++ b/app/apps/context/templatetags/main_tags.py
@@ -1,4 +1,5 @@
import json
+import os
from datetime import datetime
from django import template
@@ -87,3 +88,10 @@ def python_any(values):
if values:
return any(values)
return values
+
+
+@register.filter
+def file_exists(file_path):
+ return os.path.isfile(
+ os.path.join(settings.BASE_DIR, "apps/main/templates/", file_path)
+ )
diff --git a/app/apps/main/apps.py b/app/apps/main/apps.py
new file mode 100644
index 00000000..3244b3a0
--- /dev/null
+++ b/app/apps/main/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class MainConfig(AppConfig):
+ name = "apps.main"
+ verbose_name = "Main"
diff --git a/app/apps/main/forms.py b/app/apps/main/forms.py
index d79879c4..13736e44 100644
--- a/app/apps/main/forms.py
+++ b/app/apps/main/forms.py
@@ -18,6 +18,24 @@
logger = logging.getLogger(__name__)
+class MultipleFileInput(forms.ClearableFileInput):
+ allow_multiple_selected = True
+
+
+class MultipleFileField(forms.FileField):
+ def __init__(self, *args, **kwargs):
+ kwargs.setdefault("widget", MultipleFileInput())
+ super().__init__(*args, **kwargs)
+
+ def clean(self, data, initial=None):
+ single_file_clean = super().clean
+ if isinstance(data, (list, tuple)):
+ result = [single_file_clean(d, initial) for d in data]
+ else:
+ result = [single_file_clean(data, initial)]
+ return result
+
+
class CheckboxSelectMultiple(forms.CheckboxSelectMultiple):
template_name = "widgets/checkbox_options_grouped.html"
@@ -273,13 +291,14 @@ class InformatieToevoegenForm(forms.Form):
max_length=5000,
)
- bijlagen_extra = forms.FileField(
- widget=forms.widgets.FileInput(
+ bijlagen_extra = MultipleFileField(
+ widget=MultipleFileInput(
attrs={
"accept": ".jpg, .jpeg, .png, .heic",
"data-action": "change->bijlagen#updateImageDisplay",
"data-bijlagen-target": "bijlagenExtra",
- "multiple": "multiple",
+ "class": "file-upload-input",
+ # "multiple": "multiple",
}
),
label="Voeg één of meerdere foto's toe",
@@ -291,7 +310,7 @@ class TaakStartenForm(forms.Form):
afdeling = forms.ChoiceField(
label="Afdeling",
required=True,
- widget=RadioSelect(
+ widget=forms.RadioSelect(
attrs={
"class": "form-check-input",
}
@@ -299,7 +318,7 @@ class TaakStartenForm(forms.Form):
)
onderwerp_gerelateerd_taaktype = forms.ChoiceField(
- widget=RadioSelect(
+ widget=forms.RadioSelect(
attrs={
"data-taakstartenformulier-target": "onderwerpGerelateerdTaaktypeField",
"class": "form-check-input",
@@ -310,7 +329,7 @@ class TaakStartenForm(forms.Form):
)
taaktype = forms.ChoiceField(
- widget=RadioSelect(
+ widget=forms.RadioSelect(
attrs={
"data-taakstartenformulier-target": "taaktypeField",
"class": "form-check-input",
@@ -364,7 +383,7 @@ def __init__(self, *args, **kwargs):
class TaakAfrondenForm(forms.Form):
resolutie = forms.ChoiceField(
- widget=RadioSelect(
+ widget=forms.RadioSelect(
attrs={
"class": "list--form-radio-input",
"data-action": "change->bijlagen#updateImageDisplay",
@@ -374,13 +393,14 @@ class TaakAfrondenForm(forms.Form):
choices=[[x[4], x[1]] for x in TAAK_BEHANDEL_OPTIES],
required=True,
)
- bijlagen = forms.FileField(
- widget=forms.widgets.FileInput(
+ bijlagen = MultipleFileField(
+ widget=MultipleFileInput(
attrs={
"accept": ".jpg, .jpeg, .png, .heic",
"data-action": "change->bijlagen#updateImageDisplay",
"data-bijlagen-target": "bijlagenAfronden",
- "multiple": "multiple",
+ "class": "file-upload-input",
+ # "multiple": "multiple",
}
),
label="Foto's",
@@ -818,13 +838,14 @@ class MeldingAanmakenForm(forms.Form):
required=True,
)
- bijlagen = forms.FileField(
- widget=forms.widgets.FileInput(
+ bijlagen = MultipleFileField(
+ widget=MultipleFileInput(
attrs={
"accept": ".jpg, .jpeg, .png, .heic",
"data-action": "change->bijlagen#updateImageDisplay",
"data-bijlagen-target": "bijlagenNieuw",
- "multiple": "multiple",
+ "class": "file-upload-input",
+ # "multiple": "multiple",
}
),
label="Foto's",
diff --git a/app/apps/main/templates/django/forms/widgets/checkbox_select.html b/app/apps/main/templates/django/forms/widgets/checkbox_select.html
new file mode 100644
index 00000000..737a6187
--- /dev/null
+++ b/app/apps/main/templates/django/forms/widgets/checkbox_select.html
@@ -0,0 +1,68 @@
+{% load file_exists from main_tags %}
+{% load l10n %}
+{% with id=widget.attrs.id %}
+
+{% endwith %}
diff --git a/app/apps/main/templates/django/forms/widgets/checkbox_select_old.html b/app/apps/main/templates/django/forms/widgets/checkbox_select_old.html
new file mode 100644
index 00000000..70d25a5f
--- /dev/null
+++ b/app/apps/main/templates/django/forms/widgets/checkbox_select_old.html
@@ -0,0 +1,26 @@
+{% with id=widget.attrs.id %}
+
+
+ {% for group, options, index in widget.optgroups %}
+ {% if group %}
+ -
+ {{ group }}
+
+
+ {% endif %}
+ {% endfor %}
+
+
+{% endwith %}
diff --git a/app/apps/main/templates/django/forms/widgets/clearable_file_input.html b/app/apps/main/templates/django/forms/widgets/clearable_file_input.html
new file mode 100644
index 00000000..7603115c
--- /dev/null
+++ b/app/apps/main/templates/django/forms/widgets/clearable_file_input.html
@@ -0,0 +1,30 @@
+
+
+ {% if field.help_text %}
{{ field.help_text|safe }}
{% endif %}
+ {% for error in field.errors %}
+
{{ error }}
+ {% endfor %}
+
+
Sleep één of meer bestanden hier naartoe, of klik hier om bestanden te uploaden
+ {% include "django/forms/widgets/input.html" %}
+
+
+
diff --git a/app/apps/main/templates/django/forms/widgets/file.html b/app/apps/main/templates/django/forms/widgets/file.html
new file mode 100644
index 00000000..380c0663
--- /dev/null
+++ b/app/apps/main/templates/django/forms/widgets/file.html
@@ -0,0 +1,30 @@
+
+
+ {% if field.help_text %}
{{ field.help_text|safe }}
{% endif %}
+ {% for error in field.errors %}
+
{{ error }}
+ {% endfor %}
+
+
Sleep één of meer bestanden hier naartoe, of klik hier om bestanden te uploaden
+ {% include "django/forms/widgets/input.html" %}
+
+
+
diff --git a/app/apps/main/templates/django/forms/widgets/multiple_input.html b/app/apps/main/templates/django/forms/widgets/multiple_input.html
new file mode 100644
index 00000000..0d2acf25
--- /dev/null
+++ b/app/apps/main/templates/django/forms/widgets/multiple_input.html
@@ -0,0 +1,19 @@
+{% with id=widget.attrs.id %}
+
+ {% for group, options, index in widget.optgroups %}
+ {% if group %}
+ -
+ {{ group }}
+
+ {% endif %}
+ {% for option in options %}
+ - {% include option.template_name with widget=option %}
+ {% endfor %}
+ {% if group %}
+
+
+ {% endif %}
+ {% endfor %}
+
+{% endwith %}
diff --git a/app/apps/main/templates/widgets/checkbox_select.html b/app/apps/main/templates/widgets/checkbox_select.html
new file mode 100644
index 00000000..a80a5ac9
--- /dev/null
+++ b/app/apps/main/templates/widgets/checkbox_select.html
@@ -0,0 +1,31 @@
+{% with id=widget.attrs.id %}
+
+{% endwith %}
diff --git a/app/apps/main/templates/widgets/radio_option.html b/app/apps/main/templates/widgets/radio_option.html
index d67c0b3c..08b1e61c 100644
--- a/app/apps/main/templates/widgets/radio_option.html
+++ b/app/apps/main/templates/widgets/radio_option.html
@@ -1,3 +1 @@
{% include "django/forms/widgets/input.html" %}
-
diff --git a/app/apps/main/templates/widgets/radio_option_simple.html b/app/apps/main/templates/widgets/radio_option_simple.html
index d67c0b3c..08b1e61c 100644
--- a/app/apps/main/templates/widgets/radio_option_simple.html
+++ b/app/apps/main/templates/widgets/radio_option_simple.html
@@ -1,3 +1 @@
{% include "django/forms/widgets/input.html" %}
-
diff --git a/app/apps/main/views.py b/app/apps/main/views.py
index 9f2310d6..ba4498e9 100644
--- a/app/apps/main/views.py
+++ b/app/apps/main/views.py
@@ -62,7 +62,13 @@
from django.core.cache import cache
from django.core.files.storage import default_storage
from django.db.models import Q
-from django.http import HttpResponse, JsonResponse, QueryDict, StreamingHttpResponse
+from django.http import (
+ HttpResponse,
+ HttpResponseRedirect,
+ JsonResponse,
+ QueryDict,
+ StreamingHttpResponse,
+)
from django.shortcuts import redirect, render
from django.template.loader import render_to_string
from django.urls import reverse, reverse_lazy
@@ -1299,6 +1305,9 @@ class StandaardExterneOmschrijvingVerwijderenView(
def get(self, request, *args, **kwargs):
return self.post(request, *args, **kwargs)
+ def render_to_response(self, context, **response_kwargs):
+ return HttpResponseRedirect(self.get_success_url())
+
# Locatie views
diff --git a/app/apps/release_notes/forms.py b/app/apps/release_notes/forms.py
index 43d5a309..538f35e2 100644
--- a/app/apps/release_notes/forms.py
+++ b/app/apps/release_notes/forms.py
@@ -48,7 +48,7 @@ class ReleaseNoteAanpassenForm(forms.ModelForm):
"accept": ".jpg, .jpeg, .png, .heic, .gif",
"data-action": "change->bijlagen#updateImageDisplay",
"data-bijlagen-target": "bijlagenExtra",
- "multiple": "multiple",
+ # "multiple": "multiple",
"hideLabel": True,
}
),
diff --git a/app/config/settings.py b/app/config/settings.py
index 9c2569b9..a4b968ec 100644
--- a/app/config/settings.py
+++ b/app/config/settings.py
@@ -16,9 +16,12 @@
SECRET_KEY = os.getenv(
"DJANGO_SECRET_KEY", os.getenv("SECRET_KEY", os.getenv("APP_SECRET"))
)
+
+# APP_ENV's
PRODUCTIE = "productie"
ACCEPTATIE = "acceptatie"
TEST = "test"
+
APP_ENV = os.getenv("APP_ENV", PRODUCTIE) # acceptatie/test/productie
GIT_SHA = os.getenv("GIT_SHA")
DEPLOY_DATE = os.getenv("DEPLOY_DATE", "")
@@ -45,6 +48,7 @@
INSTALLED_APPS = (
# templates override
+ "apps.main",
"apps.health",
"django.contrib.humanize",
"django.contrib.contenttypes",
@@ -56,6 +60,7 @@
"django.contrib.admin",
"django.contrib.gis",
"django.contrib.postgres",
+ "django.forms",
"rest_framework",
"rest_framework.authtoken",
"drf_spectacular",
@@ -76,7 +81,6 @@
"django_select2",
# Apps
"apps.rotterdam_formulier_html",
- "apps.main",
"apps.authorisatie",
"apps.authenticatie",
"apps.context",
@@ -305,6 +309,7 @@
)
)
+FORM_RENDERER = "django.forms.renderers.TemplatesSetting"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
diff --git a/app/frontend/assets/controllers/taakstartenformulier_controller.js b/app/frontend/assets/controllers/taakstartenformulier_controller.js
index d4d924f1..34cf945e 100644
--- a/app/frontend/assets/controllers/taakstartenformulier_controller.js
+++ b/app/frontend/assets/controllers/taakstartenformulier_controller.js
@@ -60,8 +60,14 @@ export default class extends Controller {
handleTaaktypeChoices() {
const self = this
- this.afdelingFieldTarget.addEventListener('change', (event) => {
- const selectedAfdeling = event.target.value
+ this.afdelingFieldTarget.addEventListener('change', (e) => {
+ const selectedAfdeling = e.target
+ const list = e.target.closest('ul').getElementsByTagName('label')
+
+ for (let item of list) {
+ item.classList.remove('checked')
+ }
+ e.target.parentNode.classList.add('checked')
self.clearSearch()
self.filterTaaktypes(selectedAfdeling)
@@ -163,7 +169,7 @@ export default class extends Controller {
input.name = 'taaktype'
input.value = value
input.id = `id_taaktype_${index}`
- input.className = 'form-check-input'
+ input.className = 'form-check-input hooooi'
input.required = true
input.setAttribute('data-taakstartenformulier-target', 'taaktypeField')
diff --git a/app/frontend/assets/styles/_theme.scss b/app/frontend/assets/styles/_theme.scss
index b37b6466..637aea77 100644
--- a/app/frontend/assets/styles/_theme.scss
+++ b/app/frontend/assets/styles/_theme.scss
@@ -85,6 +85,7 @@ $container-max-widths: (
lg: 832px,
xl: 992px,
xxl: 1152px,
+ xxxl: 1280px,
);
// rotterdam-ui extension: we have extra margins *outside* the normal
diff --git a/app/frontend/assets/styles/components/_forms.scss b/app/frontend/assets/styles/components/_forms.scss
index 1f1d6fa5..c995d33a 100644
--- a/app/frontend/assets/styles/components/_forms.scss
+++ b/app/frontend/assets/styles/components/_forms.scss
@@ -285,11 +285,14 @@ textarea {
~ .form-radio-label {
line-height: 1.5rem;
font-weight: 400;
+ font-size: 1rem;
}
}
.list--form-check-input,
-.list--form-radio-input {
+.list--form-radio-input,
+.list--form-check-input ul,
+.list--form-radio-input ul {
@include list-clean();
li {
margin-bottom: 0.25rem;
@@ -517,6 +520,15 @@ input.form-radio-input {
margin: 0;
}
}
+
+ .list--grouped {
+ font-weight: 700;
+ font-size: 1rem;
+ ul ul {
+ font-weight: 400;
+ margin: $input-padding-y 0;
+ }
+ }
}
.wrapper-horizontal {
@@ -673,6 +685,7 @@ input.form-radio-input {
border: 0;
border-radius: 0;
color: $white;
+ white-space: initial;
.select2-selection__choice__remove {
height: 100%;
@@ -821,8 +834,9 @@ form.taak--start {
padding: $input-padding-y 0;
border-top: 1px solid $gray-tint04;
border-bottom: 1px solid $gray-tint04;
- max-height: 295px;
+ max-height: 300px;
overflow: auto;
+ box-sizing: border-box;
ul {
margin: 0 0 0 2px;
@@ -845,6 +859,22 @@ form.taak--start {
margin-bottom: 0;
}
}
+ label {
+ display: block;
+ padding: 0.25em 0.5em;
+ border-left: 3px solid $gray-tint01;
+ line-height: 1.5em;
+ font-weight: 400;
+ cursor: pointer;
+
+ &.checked,
+ &:hover,
+ &:focus {
+ border-color: $green-tint01;
+ color: $green-tint01;
+ font-weight: 700;
+ }
+ }
input.form-check-input {
-webkit-appearance: none;
position: relative;
@@ -853,24 +883,6 @@ form.taak--start {
position: absolute;
border: 0;
box-shadow: none;
-
- + label {
- display: block;
- padding: 0.25em 0.5em;
- border-left: 3px solid $gray-tint01;
- cursor: pointer;
- }
- &:checked,
- &:hover,
- &:focus {
- border: 0;
-
- + label {
- border-color: $green-tint01;
- color: $green-tint01;
- font-weight: 700;
- }
- }
}
.inactive {
diff --git a/app/frontend/assets/styles/components/_modal.scss b/app/frontend/assets/styles/components/_modal.scss
index a1b5b180..73e95261 100644
--- a/app/frontend/assets/styles/components/_modal.scss
+++ b/app/frontend/assets/styles/components/_modal.scss
@@ -66,7 +66,7 @@ body.show-modal--first-filter {
max-width: map-get($container-max-widths, md);
}
&--wide {
- max-width: 100%;
+ max-width: map-get($container-max-widths, xxxl);
}
}
diff --git a/app/requirements.txt b/app/requirements.txt
index a4317564..586547de 100644
--- a/app/requirements.txt
+++ b/app/requirements.txt
@@ -1,8 +1,8 @@
-Django==3.2.16
+Django==4.2.15
django-filter==22.1
-djangorestframework==3.13.1
+djangorestframework==3.15.1
drf-spectacular==0.26.0
-uWSGI==2.0.22
+uWSGI==2.0.25.1
django-webpack-loader==1.7.0
requests==2.29.0
debugpy
@@ -18,9 +18,9 @@ mozilla-django-oidc==3.0.0
PyJWT<2.4.0
django-session-timeout-joinup==1.0.0
deepdiff==6.7.1
-celery==5.2.6
-django-celery-beat==2.2.1
-django-celery-results==2.4.0
+celery==5.4.0
+django-celery-beat==2.5.0
+django-celery-results==2.5.1
django-select2==8.1.2
Pillow==9.4.0
pillow-heif==0.13.0
diff --git a/docker-compose.test.yaml b/docker-compose.test.yaml
index 4952e405..dc3afd44 100644
--- a/docker-compose.test.yaml
+++ b/docker-compose.test.yaml
@@ -23,7 +23,7 @@ services:
- "6379"
database:
- image: postgis/postgis:11-3.3
+ image: postgis/postgis:16-3.4
shm_size: "1024m"
ports:
- "5432"
diff --git a/docker-compose.yaml b/docker-compose.yaml
index 559a6088..87aa1263 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -46,14 +46,14 @@ services:
- "6379"
database:
- image: postgis/postgis:11-3.3
+ image: postgis/postgis:16-3.4
shm_size: "1024m"
ports:
- "7997:5432"
env_file:
- .env.local
volumes:
- - postgres-data:/var/lib/postgresql/data
+ - postgres-data-16:/var/lib/postgresql/data
healthcheck:
test: [ "CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}" ]
interval: 5s
@@ -115,7 +115,7 @@ services:
- mercure_config:/config
volumes:
- postgres-data:
+ postgres-data-16:
mercure_data:
mercure_config: