Skip to content

Commit

Permalink
[#2638] Update registration with choice of zaken notification channel
Browse files Browse the repository at this point in the history
  • Loading branch information
pi-sigma committed Aug 8, 2024
1 parent dae0798 commit 4526a58
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/open_inwoner/accounts/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ class Meta:
"cases_notifications",
"messages_notifications",
"plans_notifications",
"case_notification_channel",
)

def __init__(self, user, *args, **kwargs):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ <h3 class="utrecht-heading-3">{% trans "Notification preferences" %}</h3>
<p class="choice-list__p">{% trans "E-mailnotificaties wanneer er actie nodig is voor een zaak (kan niet uitgeschakeld worden)" %}</p>
</div>

<h3 class="utrecht-heading-4">{% trans "How do you want to receive notifications about cases?" %}</h3>
{% choice_radio_multiple form.case_notification_channel %}

{% form_actions primary_icon='east' primary_text="Voltooi registratie" fullwidth=True %}
</form>
{% endrender_column %}
Expand Down
42 changes: 39 additions & 3 deletions src/open_inwoner/accounts/tests/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@
OpenIDConnectDigiDConfig,
OpenIDConnectEHerkenningConfig,
)
from open_inwoner.accounts.choices import NotificationChannelChoice
from open_inwoner.configurations.models import SiteConfiguration
from open_inwoner.haalcentraal.tests.mixins import HaalCentraalMixin
from open_inwoner.kvk.branches import get_kvk_branch_number
from open_inwoner.kvk.tests.factories import CertificateFactory
from open_inwoner.openklant.tests.data import MockAPIReadPatchData
from open_inwoner.openzaak.models import OpenZaakConfig
from open_inwoner.utils.tests.helpers import AssertTimelineLogMixin

from ...cms.collaborate.cms_apps import CollaborateApphook
from ...cms.profile.cms_apps import ProfileApphook
Expand All @@ -42,7 +45,9 @@


@override_settings(ROOT_URLCONF="open_inwoner.cms.tests.urls")
class DigiDRegistrationTest(AssertRedirectsMixin, HaalCentraalMixin, WebTest):
class DigiDRegistrationTest(
AssertRedirectsMixin, AssertTimelineLogMixin, HaalCentraalMixin, WebTest
):
"""Tests concerning the registration of DigiD users"""

csrf_checks = False
Expand Down Expand Up @@ -235,12 +240,20 @@ def test_user_can_modify_only_email_when_digid_and_brp(self, m):
self.assertEqual(user.first_name, "Merel")
self.assertEqual(user.last_name, "Kooyman")

def test_notification_settings_with_cms_page_published(self):
@requests_mock.Mocker()
def test_notification_settings_with_cms_page_published(self, m):
"""
Assert that notification settings can be changed via the necessary-fields form
if the corresponding CMS pages are published. Fields corresponding to unpublished
pages should not be present.
"""
MockAPIReadPatchData.setUpServices()
mock_api_data = MockAPIReadPatchData().install_mocks(m)

# reset noise from signals
m.reset_mock()
self.clearTimelineLogs()

cms_tools.create_apphook_page(
CollaborateApphook,
parent_page=self.homepage,
Expand All @@ -256,7 +269,7 @@ def test_notification_settings_with_cms_page_published(self):
url = f"{url}?{urlencode(params)}"

data = {
"auth_name": "533458225",
"auth_name": mock_api_data.user.bsn,
"auth_pass": "bar",
}

Expand All @@ -269,13 +282,33 @@ def test_notification_settings_with_cms_page_published(self):
self.assertNotIn("messages_notifications", necessary_form.fields)

necessary_form["plans_notifications"] = False
necessary_form[
"case_notification_channel"
] = NotificationChannelChoice.digital_only
necessary_form.submit()

user = User.objects.get(bsn=data["auth_name"])

self.assertEqual(user.cases_notifications, True)
self.assertEqual(user.messages_notifications, True)
self.assertEqual(user.plans_notifications, False)
self.assertEqual(
user.case_notification_channel, NotificationChannelChoice.digital_only
)

# check klant api update
self.assertTrue(mock_api_data.matchers[0].called)
klant_patch_data = mock_api_data.matchers[1].request_history[0].json()
self.assertEqual(
klant_patch_data,
{
"toestemmingZaakNotificatiesAlleenDigitaal": True,
},
)
# only check logs for klant api update
dump = self.getTimelineLogDump()
msg = "patched klant from user profile edit with fields: toestemmingZaakNotificatiesAlleenDigitaal"
assert msg in dump

@requests_mock.Mocker()
def test_partial_response_from_haalcentraal_when_digid_and_brp(self, m):
Expand Down Expand Up @@ -1471,9 +1504,12 @@ def test_submit_without_invite(self):
response = self.app.get(self.url, user=user)
form = response.forms["necessary-form"]

from open_inwoner.accounts.choices import NotificationChannelChoice

form["email"] = "john@smith.com"
form["first_name"] = "John"
form["last_name"] = "Smith"
form["case_notification_channel"] = NotificationChannelChoice.digital_only

response = form.submit()

Expand Down
34 changes: 34 additions & 0 deletions src/open_inwoner/accounts/views/auth.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import logging

from django.conf import settings
from django.contrib import auth, messages
from django.contrib.auth.mixins import UserPassesTestMixin
Expand All @@ -16,6 +18,7 @@
from digid_eherkenning.views.base import get_redirect_url
from digid_eherkenning.views.digid import DigiDAssertionConsumerServiceView
from digid_eherkenning.views.eherkenning import eHerkenningAssertionConsumerServiceView
from onelogin.saml2.utils import OneLogin_Saml2_ValidationError

from digid_eherkenning_oidc_generics.views import (
eHerkenningOIDCAuthenticationCallbackView,
Expand All @@ -24,13 +27,16 @@
from eherkenning.mock.views.eherkenning import (
eHerkenningAssertionConsumerServiceMockView,
)
from open_inwoner.openklant.clients import build_klanten_client
from open_inwoner.openklant.models import OpenKlantConfig
from open_inwoner.openzaak.models import OpenZaakConfig
from open_inwoner.utils.views import LogMixin

from ..choices import LoginTypeChoices
from ..forms import CustomPasswordResetForm

logger = logging.getLogger(__name__)


class LogPasswordChangeView(UserPassesTestMixin, LogMixin, PasswordChangeView):
def test_func(self):
Expand Down Expand Up @@ -103,6 +109,34 @@ def get_success_url(self):


class CustomDigiDAssertionConsumerServiceView(DigiDAssertionConsumerServiceView):
def get(self, request):
errors = []
user = auth.authenticate(
request=request,
digid=True,
saml_art=request.GET.get("SAMLart"),
errors=errors,
)
if user is None:
error_code = getattr(errors[0], "code", "") if errors else ""
error_type = (
"cancelled"
if error_code == OneLogin_Saml2_ValidationError.STATUS_CODE_AUTHNFAILED
else "default"
)
messages.error(request, self.error_messages[error_type])
login_url = self.get_login_url(error_type=error_type)
return HttpResponseRedirect(login_url)

if (client := build_klanten_client()) and (
klant := client.create_klant(user_bsn=user.bsn)
):
logger.info("Created klant %s for new user %s", klant, user)

auth.login(request, user)

return HttpResponseRedirect(self.get_success_url())

def get_login_url(self, **kwargs):
invite_url = self.request.session.get("invite_url")
next_url = self.request.GET.get("RelayState")
Expand Down
29 changes: 29 additions & 0 deletions src/open_inwoner/accounts/views/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
OpenIDConnectDigiDConfig,
OpenIDConnectEHerkenningConfig,
)
from open_inwoner.accounts.choices import NotificationChannelChoice
from open_inwoner.openklant.clients import build_klanten_client
from open_inwoner.openklant.wrap import get_fetch_parameters
from open_inwoner.utils.hash import generate_email_from_string
from open_inwoner.utils.views import CommonPageMixin, LogMixin

Expand Down Expand Up @@ -160,6 +163,8 @@ def get_form_kwargs(self):
def form_valid(self, form):
user = form.save()

self.update_klant_api({k: form.cleaned_data[k] for k in form.changed_data})

invite = form.cleaned_data["invite"]
if invite:
self.add_invitee(invite, user)
Expand All @@ -182,6 +187,30 @@ def get_initial(self):

return initial

def update_klant_api(self, user_form_data: dict):
user: User = self.request.user
if not user.bsn and not user.kvk:
return

update_data = {}
if notification_channel := user_form_data.get("case_notification_channel"):
update_data = {
"toestemmingZaakNotificatiesAlleenDigitaal": notification_channel
== NotificationChannelChoice.digital_only
}

if update_data and (client := build_klanten_client()):
klant = client.retrieve_klant(**get_fetch_parameters(self.request))
if not klant:
return

self.log_system_action("retrieved klant for user", user=self.request.user)
client.partial_update_klant(klant, update_data)
self.log_system_action(
f"patched klant from user profile edit with fields: {', '.join(sorted(update_data.keys()))}",
user=self.request.user,
)


class EmailVerificationUserView(LogMixin, LoginRequiredMixin, TemplateView):
model = User
Expand Down
1 change: 0 additions & 1 deletion src/open_inwoner/openklant/tests/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ def setUpServices(cls):
class MockAPIReadPatchData(MockAPIData):
def __init__(self):
self.user = DigidUserFactory(
# bsn = "123456789",
email="old@example.com",
phonenumber="0100000000",
)
Expand Down

0 comments on commit 4526a58

Please sign in to comment.