diff --git a/package-lock.json b/package-lock.json index 3bbc3acfd3..42c3f3cb1e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "": { "name": "open_inwoner", "version": "1.0.0-alpha.0", + "hasInstallScript": true, "license": "UNLICENSED", "dependencies": { "@ckeditor/ckeditor5-autoformat": "^33.0.0", diff --git a/requirements/base.in b/requirements/base.in index 8fb4fac43a..a729be0a46 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -10,7 +10,7 @@ furl # processing urls weasyprint # export to pdf pywatchman tinycss2 - +css_inline # Framework libraries Django>=3.2.11<4.0 @@ -37,7 +37,7 @@ django-view-breadcrumbs markdown django_better_admin_arrayfield humanfriendly -git+https://github.com/maykinmedia/mail-editor.git@255bb498b1a0ddee12be4913ed90e7ccdc79e7a0#egg=mail-editor +git+https://github.com/maykinmedia/mail-editor.git@36ea073847bbea4aef3c97723f988927876b7ec9#egg=mail-editor fontawesomefree django-timeline-logger django-csp diff --git a/requirements/base.txt b/requirements/base.txt index 86bb40d59a..0dab4fc9ce 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -61,6 +61,8 @@ cryptography==41.0.7 # josepy # mozilla-django-oidc # pyopenssl +css-inline==0.13.0 + # via -r requirements/base.in cssselect2==0.4.1 # via # svglib @@ -296,9 +298,7 @@ face==20.1.1 fontawesomefree==6.4.2 # via -r requirements/base.in fonttools[woff]==4.29.1 - # via - # fonttools - # weasyprint + # via weasyprint furl==2.1.3 # via # -r requirements/base.in @@ -344,7 +344,7 @@ lxml==4.9.1 # maykin-python3-saml # svglib # xmlsec -mail-editor @ git+https://github.com/maykinmedia/mail-editor.git@255bb498b1a0ddee12be4913ed90e7ccdc79e7a0 +mail-editor @ git+https://github.com/maykinmedia/mail-editor.git@36ea073847bbea4aef3c97723f988927876b7ec9 # via -r requirements/base.in mail-parser==3.15.0 # via django-yubin @@ -481,9 +481,7 @@ sqlparse==0.4.4 svglib==1.5.1 # via easy-thumbnails tablib[html,ods,xls,xlsx,yaml]==3.1.0 - # via - # django-import-export - # tablib + # via django-import-export tinycss2==1.1.1 # via # -r requirements/base.in diff --git a/requirements/ci.txt b/requirements/ci.txt index 3df777436a..6ebc4b1ba3 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -115,6 +115,10 @@ cryptography==41.0.7 # josepy # mozilla-django-oidc # pyopenssl +css-inline==0.13.0 + # via + # -c requirements/base.txt + # -r requirements/base.txt cssselect==1.1.0 # via pyquery cssselect2==0.4.1 @@ -465,7 +469,6 @@ easy-thumbnails[svg]==2.8.5 # -r requirements/base.txt # django-filer # djangocms-picture - # easy-thumbnails ecs-logging==2.1.0 # via # -c requirements/base.txt @@ -507,7 +510,6 @@ fonttools[woff]==4.29.1 # via # -c requirements/base.txt # -r requirements/base.txt - # fonttools # weasyprint freezegun==1.1.0 # via -r requirements/test-tools.in @@ -600,7 +602,7 @@ lxml==4.9.1 # pyquery # svglib # xmlsec -mail-editor @ git+https://github.com/maykinmedia/mail-editor.git@255bb498b1a0ddee12be4913ed90e7ccdc79e7a0 +mail-editor @ git+https://github.com/maykinmedia/mail-editor.git@36ea073847bbea4aef3c97723f988927876b7ec9 # via # -c requirements/base.txt # -r requirements/base.txt @@ -865,7 +867,6 @@ tablib[html,ods,xls,xlsx,yaml]==3.1.0 # -c requirements/base.txt # -r requirements/base.txt # django-import-export - # tablib tblib==1.7.0 # via -r requirements/test-tools.in text-unidecode==1.3 diff --git a/requirements/dev.txt b/requirements/dev.txt index 34a93ecaa9..46f8fe57e9 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -141,6 +141,10 @@ cryptography==41.0.7 # josepy # mozilla-django-oidc # pyopenssl +css-inline==0.13.0 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt cssselect==1.1.0 # via # -c requirements/ci.txt @@ -515,7 +519,6 @@ easy-thumbnails[svg]==2.8.5 # -r requirements/ci.txt # django-filer # djangocms-picture - # easy-thumbnails ecs-logging==2.1.0 # via # -c requirements/ci.txt @@ -573,7 +576,6 @@ fonttools[woff]==4.29.1 # via # -c requirements/ci.txt # -r requirements/ci.txt - # fonttools # weasyprint freezegun==1.1.0 # via @@ -698,7 +700,7 @@ lxml==4.9.1 # pyquery # svglib # xmlsec -mail-editor @ git+https://github.com/maykinmedia/mail-editor.git@255bb498b1a0ddee12be4913ed90e7ccdc79e7a0 +mail-editor @ git+https://github.com/maykinmedia/mail-editor.git@36ea073847bbea4aef3c97723f988927876b7ec9 # via # -c requirements/ci.txt # -r requirements/ci.txt @@ -1043,7 +1045,6 @@ tablib[html,ods,xls,xlsx,yaml]==3.1.0 # -c requirements/ci.txt # -r requirements/ci.txt # django-import-export - # tablib tblib==1.7.0 # via # -c requirements/ci.txt diff --git a/src/open_inwoner/cms/utils/page_display.py b/src/open_inwoner/cms/utils/page_display.py index 8b4283cd87..b7cb99a672 100644 --- a/src/open_inwoner/cms/utils/page_display.py +++ b/src/open_inwoner/cms/utils/page_display.py @@ -9,12 +9,14 @@ from open_inwoner.cms.cases.cms_apps import CasesApphook from open_inwoner.cms.collaborate.cms_apps import CollaborateApphook from open_inwoner.cms.inbox.cms_apps import InboxApphook +from open_inwoner.cms.profile.cms_apps import ProfileApphook cms_apps = { "inbox": InboxApphook, "collaborate": CollaborateApphook, "cases": CasesApphook, "ssd": SSDApphook, + "profile": ProfileApphook, } @@ -56,6 +58,13 @@ def benefits_page_is_published() -> bool: return _is_published("ssd") +def profile_page_is_published() -> bool: + """ + :returns: True if the profile page published, False otherwise + """ + return _is_published("profile") + + def get_active_app_names() -> list[str]: return list( Page.objects.published() diff --git a/src/open_inwoner/conf/base.py b/src/open_inwoner/conf/base.py index 4170a9a88a..3798709484 100644 --- a/src/open_inwoner/conf/base.py +++ b/src/open_inwoner/conf/base.py @@ -774,17 +774,6 @@ # django import-export IMPORT_EXPORT_USE_TRANSACTIONS = True -# mail-editor -from .parts.maileditor import MAIL_EDITOR_BASE_CONTEXT, MAIL_EDITOR_CONF # noqa - -CKEDITOR_CONFIGS = { - "mail_editor": { - "allowedContent": True, - "height": 600, # This is optional - "entities": False, # This is added because CKEDITOR escapes the ' when you do an if statement - } -} - # invite expires in X days after sending INVITE_EXPIRY_DAYS = config("INVITE_EXPIRY_DAYS", default=30) @@ -898,6 +887,27 @@ SECURE_REFERRER_POLICY = "same-origin" +# mail-editor +from .parts.maileditor import ( # noqa + MAIL_EDITOR_BASE_CONTEXT, + MAIL_EDITOR_CONF, + MAIL_EDITOR_DYNAMIC_CONTEXT, +) + +MAIL_EDITOR_BASE_HOST = BASE_URL + +CKEDITOR_CONFIGS = { + "mail_editor": { + "allowedContent": True, + "contentsCss": [ + "/static/mailcss/email.css" + ], # Enter the css file used to style the email. + "height": 600, # This is optional + "entities": False, # This is added because CKEDITOR escapes the ' when you do an if statement + } +} + + # # Project specific settings # diff --git a/src/open_inwoner/conf/local_example.py b/src/open_inwoner/conf/local_example.py index 6c70407e94..62b07924a4 100644 --- a/src/open_inwoner/conf/local_example.py +++ b/src/open_inwoner/conf/local_example.py @@ -21,3 +21,6 @@ INSTALLED_APPS += ["debug_toolbar"] MIDDLEWARE += ["debug_toolbar.middleware.DebugToolbarMiddleware"] + + +MAIL_EDITOR_BASE_HOST = "http://localhost:8000" diff --git a/src/open_inwoner/conf/parts/case_document_notification.html b/src/open_inwoner/conf/parts/case_document_notification.html new file mode 100644 index 0000000000..f4a5602446 --- /dev/null +++ b/src/open_inwoner/conf/parts/case_document_notification.html @@ -0,0 +1,22 @@ +
Beste
+U ontvangt deze email, omdat er bij een van uw zaken een document als bijlage is toegevoegd.
+ +Zaakidentificatie | +{{ identification }} | +
---|---|
Zaaktype | +{{ type_description }} | +
Startdatum | +{{ start_date }} | +
Met vriendelijke groet, + {{ site_name }} +
diff --git a/src/open_inwoner/conf/parts/case_status_notification.html b/src/open_inwoner/conf/parts/case_status_notification.html new file mode 100644 index 0000000000..bcb5c511b3 --- /dev/null +++ b/src/open_inwoner/conf/parts/case_status_notification.html @@ -0,0 +1,95 @@ +
+ Beste inwoner, +Er is iets veranderd in één van uw aanvragen. + |
+ |||||||
+ + | +|||||||
+ Nieuw:+ |
+ |||||||
+ Aanvraag: +{{ type_description }}+ |
+
+ Zaaknummer: |
+ ||||||
+
+
+ +
|
+ |||||||
+ U hoeft niets te doen. Zodra er weer een update beschikbaar is ontvangt u hier een melding over. U kunt wel inloggen om uw aanvraag te bekijken. +Log in → + |
+ |||||||
+ + | +|||||||
+ Met vriendelijke groet, ++ {{ site_name }} + |
+ |||||||
+ + | +|||||||
+ Dit bericht is automatisch verzonden. U kunt niet reageren op deze e-mail. ++ Contact opnemen + |
+ |||||||
+ | ++ | ||||||
+ + | +|||||||
+ Pas hier uw voorkeuren aan voor de notificaties. + |
+
+ Beste inwoner, +Er is iets veranderd in één van uw aanvragen. + |
+ |||||||
+ + | +|||||||
+ Nieuw:+ |
+ |||||||
+ Aanvraag: +{{ type_description }}+ |
+
+ Zaaknummer: |
+ ||||||
+
+
+ +
|
+ |||||||
+ Log in om de documenten te uploaden. + Log in + |
+ |||||||
+ + | +|||||||
+ Met vriendelijke groet, ++ {{ site_name }} + |
+ |||||||
+ + | +|||||||
+ Dit bericht is automatisch verzonden. U kunt niet reageren op deze e-mail. ++ Contact opnemen + |
+ |||||||
+ | ++ | ||||||
+ + | +|||||||
+ U ontvangt deze e-mail notificatie zodat wij u op de hoogte kunnen houden. + |
+
Beste
+Gebruiker {{ sender_name }} wil u toevoegen als contactpersoon op {{ site_name }}. + Volg onderstaande link waarop u uw goedkeuring kan geven of kan aangeven {{ sender_name }} niet als contactpersoon te willen.
+ +U kunt ook op een later moment toestemming geven, het verzoek van {{ sender_name }} blijft open staat totdat u een keuze heeft gemaakt.
+Met vriendelijke groet, + {{ site_name }}
diff --git a/src/open_inwoner/conf/parts/contactform_registration.html b/src/open_inwoner/conf/parts/contactform_registration.html new file mode 100644 index 0000000000..0e996dab18 --- /dev/null +++ b/src/open_inwoner/conf/parts/contactform_registration.html @@ -0,0 +1,29 @@ +Beste
+ +Onderwerp: | +{{ subject }} | +
---|---|
Naam: | +{{ name }} | +
Email: | +{{ email }} | +
Telefoonnummer: | +{{ phonenumber }} | +
Vraag: | +|
{{ question }} | +
Met vriendelijke groet, + {{ site_name }}
diff --git a/src/open_inwoner/conf/parts/daily_email_digest.html b/src/open_inwoner/conf/parts/daily_email_digest.html new file mode 100644 index 0000000000..978ca2cf8c --- /dev/null +++ b/src/open_inwoner/conf/parts/daily_email_digest.html @@ -0,0 +1,22 @@ +Beste
+Het is niet gelukt om de onderstaande emails af te leveren op {{ date }}
+ +Onderwerp | +{{ failed_email.subject }} | +
---|---|
Ontvanger | +{{ failed_email.recipient }} | +
Datum | +{{ failed_email.date }} | +
Met vriendelijke groet, + {{ site_name }}
diff --git a/src/open_inwoner/conf/parts/expiring_action.html b/src/open_inwoner/conf/parts/expiring_action.html new file mode 100644 index 0000000000..345342c82c --- /dev/null +++ b/src/open_inwoner/conf/parts/expiring_action.html @@ -0,0 +1,19 @@ +Dear
+You are receiving this email because you have some actions that are expiring.
+ +Action name | +End date | +
{{ action.name }} | +{{ action.end_date|date:"j F Y" }} | +
Met vriendelijke groet, + {{ site_name }}
diff --git a/src/open_inwoner/conf/parts/expiring_plan.html b/src/open_inwoner/conf/parts/expiring_plan.html new file mode 100644 index 0000000000..2b371bde27 --- /dev/null +++ b/src/open_inwoner/conf/parts/expiring_plan.html @@ -0,0 +1,21 @@ +Dear
+You are receiving this email because you have some plans that are expiring.
+ +Plan name | +Goal | +End date | +
{{ plan.title }} | +{{ plan.goal }} | +{{ plan.end_date|date:"j F Y" }} | +
Met vriendelijke groet, + {{ site_name }}
diff --git a/src/open_inwoner/conf/parts/invite.html b/src/open_inwoner/conf/parts/invite.html new file mode 100644 index 0000000000..dc3e526275 --- /dev/null +++ b/src/open_inwoner/conf/parts/invite.html @@ -0,0 +1,7 @@ +Beste
+Je bent door {{ inviter_name }} uitgenodigd om in te loggen op {{ site_name }}. + Gebruik onderstaande link om je aan te melden
+ +Mocht je geen behoefte hieraan hebben dan staat het je vrij om dit bericht te negeren
+Met vriendelijke groet, + {{ site_name }}
diff --git a/src/open_inwoner/conf/parts/maileditor.py b/src/open_inwoner/conf/parts/maileditor.py index 8c7be75e34..6f5c95aa53 100644 --- a/src/open_inwoner/conf/parts/maileditor.py +++ b/src/open_inwoner/conf/parts/maileditor.py @@ -1,5 +1,14 @@ +import os + from django.utils.translation import gettext_lazy as _ + +def _readfile(name): + p = os.path.join(os.path.dirname(__file__), name) + with open(p, "r") as f: + return f.read() + + # mail-editor MAIL_EDITOR_CONF = { "invite": { @@ -8,19 +17,7 @@ "This email is used to invite people to sing up to the website" ), "subject_default": "Uitnodiging voor {{ site_name }}", - "body_default": """ -Beste
- -Je bent door {{ inviter_name}} uitgenodigd om in te loggen op {{ site_name }}. - Gebruik onderstaande link om je aan te melden
- - - -Mocht je geen behoefte hieraan hebben dan staat het je vrij om dit bericht te negeren
- -Met vriendelijke groet, - {{ site_name }}
- """, + "body_default": _readfile("invite.html"), "subject": [ { "name": "site_name", @@ -50,19 +47,7 @@ "This email is used to notify people for pending approvals of new contacts" ), "subject_default": "Goedkeuring geven op {{ site_name }}: {{ sender_name }} wilt u toevoegen als contactpersoon", - "body_default": """ -Beste
- -Gebruiker {{ sender_name }} wilt u toevoegen als contactpersoon op {{ site_name }}. - Volg onderstaande link waarop u uw goedkeuring kan geven of kan aangeven {{ sender_name }} niet als contactpersoon te willen.
- - - -U kunt ook op een later moment toestemming geven, het verzoek van {{ sender_name }} blijft open staat totdat u een keuze heeft gemaakt.
- -Met vriendelijke groet, - {{ site_name }}
- """, + "body_default": _readfile("contact_approval.html"), "subject": [ { "name": "site_name", @@ -95,16 +80,7 @@ "This email is used to inform users about the new messages in their inbox" ), "subject_default": "New messages at {{ site_name }}", - "body_default": """ -Beste
- -You've received {{ total_messages }} new messages from {{ total_senders }} users
- - - -Met vriendelijke groet, - {{ site_name }}
- """, + "body_default": _readfile("new_messages.html"), "subject": [ { "name": "site_name", @@ -136,29 +112,7 @@ "This email is used to remind users that there are actions that are ending today" ), "subject_default": "Actions about to end today at {{ site_name }}", - "body_default": """ -Beste
- -You are receiving this email because you have some actions that are expiring.
- -Action name | -End date | -
{{ action.name }} | -{{ action.end_date|date:"j F Y" }} | -
Met vriendelijke groet, - {{ site_name }}
- """, + "body_default": _readfile("expiring_action.html"), "subject": [ { "name": "site_name", @@ -186,31 +140,7 @@ "This email is used to remind users that there are plans that are ending today" ), "subject_default": "Plans about to end today at {{ site_name }}", - "body_default": """ -Beste
- -You are receiving this email because you have some plans that are expiring.
- -Plan name | -Goal | -End date | -
{{ plan.title }} | -{{ plan.goal }} | -{{ plan.end_date|date:"j F Y" }} | -
Met vriendelijke groet, - {{ site_name }}
- """, + "body_default": _readfile("expiring_plan.html"), "subject": [ { "name": "site_name", @@ -238,33 +168,7 @@ "This email is used to notify plan participants about the change in the plan action" ), "subject_default": "Plan action has been updated at {{ site_name }}", - "body_default": """ -Beste
- -You are receiving this email because the action in your plan was updated.
- -Action name | -{{ action.name }} | -
---|---|
Plan | -{{ plan.title }} | -
Updated at | -{{ action.updated_on }} | -
Details | -{{ message }} | -
Met vriendelijke groet, - {{ site_name }}
- """, + "body_default": _readfile("plan_action_update.html"), "subject": [ { "name": "site_name", @@ -296,31 +200,7 @@ "This email is used to notify people about a new status being set on their case" ), "subject_default": "Uw zaak is bijgewerkt op {{ site_name }}", - "body_default": """ -Beste
- -U ontvangt deze email, omdat de status van een van uw zaken is bijgewerkt.
- -Zaakidentificatie | -{{ identification }} | -
---|---|
Zaaktype | -{{ type_description }} | -
Startdatum | -{{ start_date }} | -
Met vriendelijke groet, - {{ site_name }}
- """, + "body_default": _readfile("case_status_notification.html"), "subject": [ { "name": "site_name", @@ -337,8 +217,12 @@ "description": _("The description of the type of the case"), }, { - "name": "start_date", - "description": _("The start date of the case"), + "name": "case_link", + "description": _("The link to the case details."), + }, + { + "name": "end_date", + "description": _("The planned final date of the case"), }, { "name": "case_link", @@ -348,6 +232,24 @@ "name": "site_name", "description": _("Name of the site"), }, + { + "name": "contactpage", + "description": _("The link to an existing contactpage"), + }, + { + "name": "profile_notifications", + "description": _( + "The link to the notifications and unsubscribe settings" + ), + }, + { + "name": "profile_page", + "description": _("The link to the user's profile page"), + }, + { + "name": "login_page", + "description": _("The link to the login page"), + }, ], }, "case_document_notification": { @@ -356,31 +258,7 @@ "This email is used to notify people that a new document was added to their case" ), "subject_default": "Uw zaak is bijgewerkt op {{ site_name }}", - "body_default": """ -Beste
- -U ontvangt deze email, omdat er bij een van uw zaken een document als bijlage is toegevoegd.
- -Zaakidentificatie | -{{ identification }} | -
---|---|
Zaaktype | -{{ type_description }} | -
Startdatum | -{{ start_date }} | -
Met vriendelijke groet, - {{ site_name }}
- """, + "body_default": _readfile("case_document_notification.html"), "subject": [ { "name": "site_name", @@ -417,31 +295,7 @@ "that requires action on their part." ), "subject_default": "Uw zaak is bijgewerkt op {{ site_name }} (actie vereist)", - "body_default": """ -Beste
- -U ontvangt deze email, omdat de status van een van uw zaken is bijgewerkt.
- -Zaakidentificatie | -{{ identification }} | -
---|---|
Zaaktype | -{{ type_description }} | -
Startdatum | -{{ start_date }} | -
Met vriendelijke groet, - {{ site_name }}
- """, + "body_default": _readfile("case_status_notification_action_required.html"), "subject": [ { "name": "site_name", @@ -457,14 +311,14 @@ "name": "type_description", "description": _("The description of the type of the case"), }, - { - "name": "start_date", - "description": _("The start date of the case"), - }, { "name": "case_link", "description": _("The link to the case details."), }, + { + "name": "end_date", + "description": _("The planned final date of the case"), + }, { "name": "site_name", "description": _("Name of the site"), @@ -475,37 +329,7 @@ "name": _("Contact form registration notification"), "description": _("This email is used to register a contact form submission"), "subject_default": "Contact formulier inzending vanaf {{ site_name }}", - "body_default": """ -Beste
- -Onderwerp: | -{{ subject }} | -
---|---|
Naam: | -{{ name }} | -
Email: | -{{ email }} | -
Telefoonnummer: | -{{ phonenumber }} | -
Vraag: | -|
{{ question }} - |
Met vriendelijke groet, - {{ site_name }}
- """, + "body_default": _readfile("contactform_registration.html"), "subject": [ { "name": "site_name", @@ -541,30 +365,7 @@ "This email is used to periodically inform an admin about failed emails" ), "subject_default": "Gefaalde emails voor {{ site_name }} ({{ date }})", - "body_default": """ -Beste
- - Het is niet gelukt om de onderstaande emails af te leveren op {{ date }} -Onderwerp | -{{ failed_email.subject }} | -
---|---|
Ontvanger | -{{ failed_email.recipient }} | -
Datum | -{{ failed_email.date }} | -
Met vriendelijke groet, - {{ site_name }}
- """, + "body_default": _readfile("daily_email_digest.html"), "subject": [ { "name": "site_name", @@ -588,3 +389,4 @@ }, } MAIL_EDITOR_BASE_CONTEXT = {"site_name": "Open Inwoner Platform"} +MAIL_EDITOR_DYNAMIC_CONTEXT = "open_inwoner.mail.context.mail_context" diff --git a/src/open_inwoner/conf/parts/new_messages.html b/src/open_inwoner/conf/parts/new_messages.html new file mode 100644 index 0000000000..353768c12b --- /dev/null +++ b/src/open_inwoner/conf/parts/new_messages.html @@ -0,0 +1,5 @@ +Dear
+You've received {{ total_messages }} new messages from {{ total_senders }} users
+ +Met vriendelijke groet, + {{ site_name }}
diff --git a/src/open_inwoner/conf/parts/plan_action_update.html b/src/open_inwoner/conf/parts/plan_action_update.html new file mode 100644 index 0000000000..3e7ef445ae --- /dev/null +++ b/src/open_inwoner/conf/parts/plan_action_update.html @@ -0,0 +1,24 @@ +Dear
+You are receiving this email because the action in your plan was updated.
+ +Action name | +{{ action.name }} | +
---|---|
Plan | +{{ plan.title }} | +
Updated at | +{{ action.updated_on }} | +
Details | +{{ message }} | +
Met vriendelijke groet, + {{ site_name }}
diff --git a/src/open_inwoner/configurations/admin.py b/src/open_inwoner/configurations/admin.py index 9c203e93de..69b2eca426 100644 --- a/src/open_inwoner/configurations/admin.py +++ b/src/open_inwoner/configurations/admin.py @@ -155,6 +155,7 @@ class SiteConfigurationAdmin(OrderedInlineModelAdminMixin, SingletonModelAdmin): { "fields": ( "logo", + "email_logo", "footer_logo", "footer_logo_title", "footer_logo_url", diff --git a/src/open_inwoner/configurations/migrations/0059_siteconfiguration_email_logo.py b/src/open_inwoner/configurations/migrations/0059_siteconfiguration_email_logo.py new file mode 100644 index 0000000000..97224531d1 --- /dev/null +++ b/src/open_inwoner/configurations/migrations/0059_siteconfiguration_email_logo.py @@ -0,0 +1,31 @@ +# Generated by Django 3.2.23 on 2024-02-13 08:43 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations + +import filer.fields.image + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.FILER_IMAGE_MODEL), + ("configurations", "0058_siteconfiguration_recipients_email_digest"), + ] + + operations = [ + migrations.AddField( + model_name="siteconfiguration", + name="email_logo", + field=filer.fields.image.FilerImageField( + blank=True, + help_text="Image to use as logo in email.", + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="email_logo", + to=settings.FILER_IMAGE_MODEL, + verbose_name="Email logo (.png or .jpg)", + ), + ), + ] diff --git a/src/open_inwoner/configurations/migrations/0061_merge_20240214_1308.py b/src/open_inwoner/configurations/migrations/0061_merge_20240214_1308.py new file mode 100644 index 0000000000..8559d22306 --- /dev/null +++ b/src/open_inwoner/configurations/migrations/0061_merge_20240214_1308.py @@ -0,0 +1,13 @@ +# Generated by Django 3.2.23 on 2024-02-14 12:08 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("configurations", "0059_siteconfiguration_email_logo"), + ("configurations", "0060_auto_20240208_1426"), + ] + + operations = [] diff --git a/src/open_inwoner/configurations/models.py b/src/open_inwoner/configurations/models.py index f98d455f69..a442b744b6 100644 --- a/src/open_inwoner/configurations/models.py +++ b/src/open_inwoner/configurations/models.py @@ -257,6 +257,14 @@ class SiteConfiguration(SingletonModel): default="", help_text=_("The external link for the footer logo."), ) + email_logo = FilerImageField( + verbose_name=_("Email logo (.png or .jpg)"), + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name="email_logo", + help_text=_("Image to use as logo in email."), + ) favicon = FilerImageField( verbose_name=_("Favicon image (32x32, .png)"), null=True, diff --git a/src/open_inwoner/mail/__init__.py b/src/open_inwoner/mail/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/open_inwoner/mail/context.py b/src/open_inwoner/mail/context.py new file mode 100644 index 0000000000..203f7c6e13 --- /dev/null +++ b/src/open_inwoner/mail/context.py @@ -0,0 +1,35 @@ +from django.urls import reverse + +from open_inwoner.cms.utils.page_display import profile_page_is_published +from open_inwoner.configurations.models import SiteConfiguration + + +def mail_context(): + """ + Context added to mail editor templates + """ + context = {} + config = SiteConfiguration.get_solo() + context["logo"] = config.email_logo + context["theming"] = { + "primary_color": config.primary_color, + "secondary_color": config.secondary_color, + "accent_color": config.accent_color, + "primary_font_color": config.primary_font_color, + "secondary_font_color": config.secondary_font_color, + "accent_font_color": config.accent_font_color, + } + context["login_page"] = reverse("login") + + if profile_page_is_published(): + context["profile_notifications"] = reverse("profile:notifications") + context["profile_page"] = reverse("profile:detail") + else: + # empty urls to homepage + context["profile_notifications"] = "" + context["profile_page"] = "" + + # if a contact page exists it is a FlatPage + context["contactpage"] = "????" + + return context diff --git a/src/open_inwoner/openzaak/admin.py b/src/open_inwoner/openzaak/admin.py index c3b330cab5..64c9a7a1e4 100644 --- a/src/open_inwoner/openzaak/admin.py +++ b/src/open_inwoner/openzaak/admin.py @@ -46,6 +46,7 @@ class OpenZaakConfigAdmin(SingletonModelAdmin): "fields": [ "zaak_max_confidentiality", "document_max_confidentiality", + "action_required_deadline_days", "max_upload_size", "allowed_file_extensions", "title_text", diff --git a/src/open_inwoner/openzaak/migrations/0035_populate_zaaktypeconfig_urls.py b/src/open_inwoner/openzaak/migrations/0035_populate_zaaktypeconfig_urls.py index 6f4f3f3b40..fe56b59a3d 100644 --- a/src/open_inwoner/openzaak/migrations/0035_populate_zaaktypeconfig_urls.py +++ b/src/open_inwoner/openzaak/migrations/0035_populate_zaaktypeconfig_urls.py @@ -1,49 +1,6 @@ # Generated by Django 3.2.20 on 2023-11-20 10:07 -from django.core.exceptions import ObjectDoesNotExist -from django.db import migrations, transaction - -from open_inwoner.openzaak.zgw_imports import get_configurable_zaaktypes -from open_inwoner.openzaak.clients import build_client -import logging - -logger = logging.getLogger(__name__) - - -def populate_zaaktype_config_urls(apps, schema_editor): - """ - Go through configurable zaaktypen and populate the new URL field where needed - """ - ZaakTypeConfig = apps.get_model("openzaak", "ZaakTypeConfig") - CatalogusConfig = apps.get_model("openzaak", "CatalogusConfig") - catalog_lookup = {c.url: c for c in CatalogusConfig.objects.all()} - - client = build_client("catalogi") - if not client: - logger.warning( - "Not populating zaaktype config urls: could not build Catalogi API client" - ) - return [] - - zaaktypes = get_configurable_zaaktypes(client) - if not zaaktypes: - return [] - - with transaction.atomic(): - for zaaktype in zaaktypes: - catalog = catalog_lookup.get(zaaktype.catalogus) - if not catalog: - continue - - try: - config = ZaakTypeConfig.objects.get( - catalogus=catalog, identificatie=zaaktype.identificatie - ) - if zaaktype.url not in config.urls: - config.urls = config.urls + [zaaktype.url] - config.save() - except ObjectDoesNotExist: - continue +from django.db import migrations class Migration(migrations.Migration): @@ -52,6 +9,5 @@ class Migration(migrations.Migration): ("openzaak", "0037_openzaakconfig_fetch_eherkenning_zaken_with_rsin"), ] - operations = [ - migrations.RunPython(populate_zaaktype_config_urls, migrations.RunPython.noop), - ] + # Cleared this data migration because it caused problems with later migrations and wasn't needed anymore. + operations = [] diff --git a/src/open_inwoner/openzaak/migrations/0044_openzaakconfig_action_required_deadline_days.py b/src/open_inwoner/openzaak/migrations/0044_openzaakconfig_action_required_deadline_days.py new file mode 100644 index 0000000000..bdc5d7e91d --- /dev/null +++ b/src/open_inwoner/openzaak/migrations/0044_openzaakconfig_action_required_deadline_days.py @@ -0,0 +1,22 @@ +# Generated by Django 3.2.23 on 2024-02-13 10:54 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("openzaak", "0043_zaaktypestatustypeconfig_action_required"), + ] + + operations = [ + migrations.AddField( + model_name="openzaakconfig", + name="action_required_deadline_days", + field=models.IntegerField( + default=15, + help_text="Aantal dagen voor gebruiker om actie te ondernemen.", + verbose_name="Standaard actie deadline termijn in dagen", + ), + ), + ] diff --git a/src/open_inwoner/openzaak/models.py b/src/open_inwoner/openzaak/models.py index e27bd775f0..f6cbed2e53 100644 --- a/src/open_inwoner/openzaak/models.py +++ b/src/open_inwoner/openzaak/models.py @@ -163,6 +163,12 @@ class OpenZaakConfig(SingletonModel): ), ) + action_required_deadline_days = models.IntegerField( + verbose_name=_("Standaard actie deadline termijn in dagen"), + default=15, + help_text=_("Aantal dagen voor gebruiker om actie te ondernemen."), + ) + class Meta: verbose_name = _("Open Zaak configuration") diff --git a/src/open_inwoner/openzaak/notifications.py b/src/open_inwoner/openzaak/notifications.py index c134348ea0..369576bf34 100644 --- a/src/open_inwoner/openzaak/notifications.py +++ b/src/open_inwoner/openzaak/notifications.py @@ -1,5 +1,5 @@ import logging -from datetime import timedelta +from datetime import date, timedelta from typing import List from django.conf import settings @@ -572,11 +572,14 @@ def send_case_update_email( reverse("cases:case_detail", kwargs={"object_id": str(case.uuid)}) ) + config = OpenZaakConfig.get_solo() + template = find_template(template_name) context = { "identification": case.identification, "type_description": case.zaaktype.omschrijving, "start_date": case.startdatum, + "end_date": date.today() + timedelta(days=config.action_required_deadline_days), "case_link": case_detail_url, } if extra_context: diff --git a/src/open_inwoner/openzaak/tests/test_notification_utils.py b/src/open_inwoner/openzaak/tests/test_notification_utils.py index 55736d4caa..46c39d5a82 100644 --- a/src/open_inwoner/openzaak/tests/test_notification_utils.py +++ b/src/open_inwoner/openzaak/tests/test_notification_utils.py @@ -54,7 +54,6 @@ def test_send_case_update_email(self): body_html = email.alternatives[0][0] self.assertIn(case.identificatie, body_html) self.assertIn(case.zaaktype.omschrijving, body_html) - self.assertIn(date_format(case.startdatum), body_html) self.assertIn(case_url, body_html) self.assertIn(config.name, body_html) diff --git a/src/open_inwoner/static/img/mail/alarm_danger-orange.jpg b/src/open_inwoner/static/img/mail/alarm_danger-orange.jpg new file mode 100644 index 0000000000..4b5a0c428d Binary files /dev/null and b/src/open_inwoner/static/img/mail/alarm_danger-orange.jpg differ diff --git a/src/open_inwoner/static/img/mail/info_info-blue.jpg b/src/open_inwoner/static/img/mail/info_info-blue.jpg new file mode 100644 index 0000000000..0cc66f0237 Binary files /dev/null and b/src/open_inwoner/static/img/mail/info_info-blue.jpg differ diff --git a/src/open_inwoner/static/mailcss/email.css b/src/open_inwoner/static/mailcss/email.css new file mode 100644 index 0000000000..3661e0262e --- /dev/null +++ b/src/open_inwoner/static/mailcss/email.css @@ -0,0 +1,168 @@ +/* Tags: general styles for all templates */ + +table, th, td, img { + border: 0; + border-spacing: 0; + padding: 0; +} + +th { + font-weight: bold; + padding: 18px 20px 18px 20px; + text-align: left; +} + +p { + padding: 0; + margin: 0; +} + +.heading-font, h1, h2, h3, h4 { + color: #000000; + font-family: Ubuntu, Helvetica, Arial, sans-serif; + font-weight: bold; + padding: 0; + margin: 0; +} + +table, .table-mail { + /* --color-gray-dark */ + background-color: #ffffff; + border-spacing: 0; + border-collapse: collapse; + color: #4B4B4B; + font-family: Lato, Helvetica, sans-serif; + line-height: 24px; +} + +td, .td-mail { + /* --color-gray-dark */ + color: #4B4B4B; + font-family: Lato, Helvetica, Arial, sans-serif; + line-height: 24px; +} + +/* Class styles for differing elements */ + +.td-mail__bg-danger .td-mail__bg-white a { + color: #704000; +} + +.td-mail__bg-info .td-mail__bg-white a, .td-mail__bg-info a, .td__info-link a { + color: #2566A7; +} + +.td__logo-mail { + text-align: center; + padding-top: 16px; +} + +.img__logo-mail { + width: auto; + max-height: 55px; + max-width: 600px; +} + +.mail__icon { + border-right: 5px solid #FFFFFF; +} + +.td-mail h1 { + font-size: 20px; +} + +.td-mail h2 { + font-size: 18px; +} + +.td-mail.align-top { + vertical-align: top; +} + +td.align-center { + vertical-align: middle; +} + +.tr-mail.border-top .td-mail { + border-top: 1px solid #d2d2d2; +} + +.td-mail.spacer-bottom { + border-bottom: 1px solid #d2d2d2; + padding-top: 60px; +} + +.td-mail--accent { + height: 24px; +} + +.td-mail__bg-info { + background-color: #B3D9EB; +} + +.td-mail__bg-danger { + background-color: #FFEDDF; +} + +.td-mail__bg-white { + background-color: #ffffff; + border: 1px solid #ffffff; + border-radius: 6px; + color: #704000; + display: inline-block; + font-family: Lato, Helvetica, Arial, sans-serif; + font-size: 16px; + line-height: 24px; + text-decoration: none; + width: 100%; + -webkit-text-size-adjust: none; +} + +.td__padding-top { + padding-top: 24px; +} + +.td__padding-right { + padding-right: 24px; +} + +.td__padding-bottom { + padding-bottom: 24px; +} + +.td__padding-left { + padding-left: 24px; +} + +.td__padding-all { + padding: 20px 24px 20px 24px; +} + +.td__padding-zero { + padding: 0; +} + +.spacing__extra { + height: 20px; +} + +/* Theme-colors and other mail-template colors */ + +.text-color__info { + color: #2566A7; +} + +.text-color__danger { + color: #704000; +} + +.text-color__gray-900 { + /* --color-gray-dark-900 */ + color: #676767; +} + +.text-color__small-gray-900 { + color: #676767; + font-size: 14px; +} + diff --git a/src/open_inwoner/templates/mail/_base.html b/src/open_inwoner/templates/mail/_base.html index e4fc4d561f..66ff0d059e 100644 --- a/src/open_inwoner/templates/mail/_base.html +++ b/src/open_inwoner/templates/mail/_base.html @@ -1,69 +1,184 @@ - - - - - + + - - + .td--responsive { + display: block; + } + } + + + - ++ |
+
|
+ + |