Skip to content

Commit

Permalink
Merge pull request #429 from maykinmedia/feature/1051-haalcentraal-my…
Browse files Browse the repository at this point in the history
…data-view

[#1051-3] Feature/Haalcentraal BRP data view
  • Loading branch information
alextreme authored Jan 18, 2023
2 parents 13836a4 + 3273500 commit 6993c5e
Show file tree
Hide file tree
Showing 14 changed files with 465 additions and 154 deletions.
1 change: 1 addition & 0 deletions src/open_inwoner/accounts/tests/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@ def test_any_page_for_digid_user_redirect_to_necessary_fields(self):
reverse("accounts:my_profile"),
reverse("accounts:inbox"),
reverse("accounts:my_open_cases"),
reverse("accounts:my_data"),
reverse("plans:plan_list"),
reverse("general_faq"),
]
Expand Down
85 changes: 85 additions & 0 deletions src/open_inwoner/accounts/tests/test_profile_views.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
from django.test import override_settings
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _

import requests_mock
from django_webtest import WebTest
from timeline_logger.models import TimelineLog

from open_inwoner.accounts.choices import StatusChoices
from open_inwoner.haalcentraal.tests.mixins import HaalCentraalMixin
from open_inwoner.pdc.tests.factories import CategoryFactory
from open_inwoner.utils.logentry import LOG_ACTIONS

from ...questionnaire.tests.factories import QuestionnaireStepFactory
from ..choices import LoginTypeChoices
Expand Down Expand Up @@ -122,6 +127,17 @@ def test_get_documents_sorted(self):
self.assertTrue(doc_new.name in file_tags[0].prettify())
self.assertTrue(doc_old.name in file_tags[1].prettify())

def test_mydata_shown_with_digid(self):
user = UserFactory.create(
login_type=LoginTypeChoices.digid, email="[email protected]"
)
response = self.app.get(self.url, user=user)
self.assertContains(response, _("Mijn gegevens"))

def test_mydata_not_shown_without_digid(self):
response = self.app.get(self.url, user=self.user)
self.assertNotContains(response, _("Mijn gegevens"))


class EditProfileTests(WebTest):
def setUp(self):
Expand Down Expand Up @@ -258,6 +274,75 @@ def test_updating_a_field_without_modifying_email_succeeds(self):
self.assertEqual(self.user.first_name, "Testing")


@requests_mock.Mocker()
class MyDataTests(HaalCentraalMixin, WebTest):
expected_response = {
"first_name": "Merel",
"initials": "M.",
"last_name": "Kooyman",
"prefix": None,
"birthday": "1982-04-10",
"birthday_place": "Leerdam",
"birthday_country": "Nederland",
"gender": "vrouw",
"street": "King Olivereiland",
"house_number": 64,
"postcode": "2551JV",
"place": "'s-Gravenhage",
"land": None,
}

def setUp(self):
self.user = UserFactory(
bsn="999993847",
first_name="",
last_name="",
login_type=LoginTypeChoices.digid,
)
self.url = reverse("accounts:my_data")

def test_expected_response_is_returned_brp_v_2(self, m):
self._setUpMocks_v_2(m)
self._setUpService()

response = self.app.get(self.url, user=self.user)
log_entry = TimelineLog.objects.last()

self.assertEqual(
response.context["my_data"],
self.expected_response,
)
self.assertEqual(
log_entry.extra_data,
{
"message": _("user requests for brp data"),
"action_flag": list(LOG_ACTIONS[4]),
"content_object_repr": self.user.email,
},
)

@override_settings(BRP_VERSION="1.3")
def test_expected_response_is_returned_brp_v_1_3(self, m):
self._setUpMocks_v_1_3(m)
self._setUpService()

response = self.app.get(self.url, user=self.user)
log_entry = TimelineLog.objects.last()

self.assertEqual(
response.context["my_data"],
self.expected_response,
)
self.assertEqual(
log_entry.extra_data,
{
"message": _("user requests for brp data"),
"action_flag": list(LOG_ACTIONS[4]),
"content_object_repr": self.user.email,
},
)


class EditIntrestsTests(WebTest):
def setUp(self):
self.url = reverse("accounts:my_themes")
Expand Down
2 changes: 2 additions & 0 deletions src/open_inwoner/accounts/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
InboxView,
InviteAcceptView,
MyCategoriesView,
MyDataView,
MyProfileExportView,
MyProfileView,
NecessaryFieldsUserView,
Expand Down Expand Up @@ -98,6 +99,7 @@
),
path("contacts/", ContactListView.as_view(), name="contact_list"),
path("themes/", MyCategoriesView.as_view(), name="my_themes"),
path("mydata/", MyDataView.as_view(), name="my_data"),
path("cases/open/", OpenCaseListView.as_view(), name="my_open_cases"),
path("cases/closed/", ClosedCaseListView.as_view(), name="my_closed_cases"),
path(
Expand Down
1 change: 1 addition & 0 deletions src/open_inwoner/accounts/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from .profile import (
EditProfileView,
MyCategoriesView,
MyDataView,
MyProfileExportView,
MyProfileView,
)
Expand Down
63 changes: 62 additions & 1 deletion src/open_inwoner/accounts/views/profile.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from datetime import date

from django.conf import settings
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.forms.forms import Form
Expand All @@ -8,16 +9,19 @@
from django.urls import reverse, reverse_lazy
from django.utils.functional import cached_property
from django.utils.translation import gettext as _
from django.views.generic import DetailView, FormView, UpdateView
from django.views.generic import DetailView, FormView, TemplateView, UpdateView

from glom import PathAccessError, glom
from view_breadcrumbs import BaseBreadcrumbMixin

from open_inwoner.accounts.choices import (
ContactTypeChoices,
LoginTypeChoices,
StatusChoices,
)
from open_inwoner.haalcentraal.utils import fetch_brp_data
from open_inwoner.questionnaire.models import QuestionnaireStep
from open_inwoner.utils.logentry import user_action
from open_inwoner.utils.mixins import ExportMixin
from open_inwoner.utils.views import CommonPageMixin, LogMixin

Expand Down Expand Up @@ -149,6 +153,63 @@ def form_valid(self, form):
return HttpResponseRedirect(self.get_success_url())


class MyDataView(
LogMixin, LoginRequiredMixin, CommonPageMixin, BaseBreadcrumbMixin, TemplateView
):
template_name = "pages/profile/mydata.html"

@cached_property
def crumbs(self):
return [
(_("Mijn profiel"), reverse("accounts:my_profile")),
(_("Mijn gegevens"), reverse("accounts:my_data")),
]

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["my_data"] = self.parse_brp_data()
return context

def parse_brp_data(self):
brp_version = settings.BRP_VERSION
user = self.request.user
my_data = {
"first_name": "naam.voornamen",
"initials": "naam.voorletters",
"last_name": "naam.geslachtsnaam",
"prefix": "naam.voorvoegsel",
"birthday": "geboorte.datum.datum",
"birthday_place": "geboorte.plaats.omschrijving",
"birthday_country": "geboorte.land.omschrijving",
"gender": (
"geslachtsaanduiding.omschrijving"
if brp_version == "2.0"
else "geslachtsaanduiding"
),
"street": "verblijfplaats.straat",
"house_number": "verblijfplaats.huisnummer",
"postcode": "verblijfplaats.postcode",
"place": "verblijfplaats.woonplaats",
"land": "verblijfplaats.land.omschrijving",
}

self.log_user_action(user, _("user requests for brp data"))

fetched_data = fetch_brp_data(user, brp_version)

# we have a different response depending on brp version
if brp_version == "2.0" and fetched_data.get("personen"):
fetched_data = fetched_data.get("personen", [])[0]

if not fetched_data:
return {}

for field in my_data:
my_data[field] = glom(fetched_data, my_data[field], default=None)

return my_data


class MyProfileExportView(LogMixin, LoginRequiredMixin, ExportMixin, DetailView):
template_name = "export/profile/profile_export.html"
model = User
Expand Down
70 changes: 6 additions & 64 deletions src/open_inwoner/haalcentraal/signals.py
Original file line number Diff line number Diff line change
@@ -1,79 +1,19 @@
import logging
from urllib.parse import urljoin

from django.conf import settings
from django.db.models.signals import pre_save
from django.dispatch import receiver
from django.utils.translation import gettext as _

from glom import PathAccessError, glom
from requests import RequestException
from zds_client import ClientError

from open_inwoner.accounts.choices import LoginTypeChoices
from open_inwoner.accounts.models import User
from open_inwoner.haalcentraal.models import HaalCentraalConfig
from open_inwoner.utils.logentry import system_action

logger = logging.getLogger(__name__)


def fetch_data(instance, brp_version):
config = HaalCentraalConfig.get_solo()

if not config.service:
logger.warning("no service defined for Haal Centraal")
return {}

client = config.service.build_client()
logger.warning(brp_version)
data = {}
if brp_version == "2.0":
url = urljoin(client.base_url, "personen")
try:
data = client.operation(
operation_id="GetPersonen",
url=url,
data={
"fields": "naam,geboorte",
"type": "RaadpleegMetBurgerservicenummer",
"burgerservicenummer": [instance.bsn],
},
request_kwargs=dict(
headers={"Accept": "application/hal+json"}, verify=False
),
)
except RequestException as e:
logger.exception("exception while making request", exc_info=e)
return {}
except ClientError as e:
logger.exception("exception while making request", exc_info=e)
return {}

elif brp_version == "1.3":
url = urljoin(client.base_url, f"ingeschrevenpersonen/{instance.bsn}")
try:
data = client.retrieve(
"ingeschrevenpersonen",
url=url,
request_kwargs=dict(
headers={
"Accept": "application/hal+json",
"x-doelbinding": "Huisvesting", # See Taiga #755
"x-origin-oin": "00000003273229750000",
}, # See Taiga #755
params={"fields": "naam,geboorte.datum"},
verify=False,
),
)
except RequestException as e:
logger.exception("exception while making request", exc_info=e)
return {}
except ClientError as e:
logger.exception("exception while making request", exc_info=e)
return {}
from .utils import fetch_brp_data

return data
logger = logging.getLogger(__name__)


@receiver(pre_save, sender=User)
Expand All @@ -86,10 +26,12 @@ def on_bsn_change(instance, **kwargs):
and instance.login_type == LoginTypeChoices.digid
):
system_action("Retrieving data from haal centraal based on BSN")
data = fetch_data(instance, brp_version)

data = fetch_brp_data(instance, brp_version)

# we have a different response depending on brp version
if brp_version == "2.0" and data.get("personen"):
data = glom(data, "personen")[0]
data = data.get("personen", [])[0]

try:
instance.first_name = glom(data, "naam.voornamen")
Expand Down
Loading

0 comments on commit 6993c5e

Please sign in to comment.