def test_only_assigned_process_owner_can_access(self): process_owner_assigned = UserFactory.create( role__type=RoleTypeChoices.process_owner ) another_process_owner = UserFactory.create( role__type=RoleTypeChoices.process_owner ) report = DestructionReportFactory.create(process_owner=process_owner_assigned) self.client.force_login(process_owner_assigned) response_pdf = self.client.get( reverse("report:download-report", args=[report.pk]), data={"type": "pdf"} ) response_csv = self.client.get( reverse("report:download-report", args=[report.pk]), data={"type": "csv"} ) self.assertEqual(200, response_pdf.status_code) self.assertGreater(len(response_pdf.content), 0) self.assertEqual(200, response_csv.status_code) self.assertGreater(len(response_csv.content), 0) self.client.force_login(another_process_owner) response_pdf = self.client.get( reverse("report:download-report", args=[report.pk]), data={"type": "pdf"} ) response_csv = self.client.get( reverse("report:download-report", args=[report.pk]), data={"type": "csv"} ) self.assertEqual(403, response_pdf.status_code) self.assertEqual(403, response_csv.status_code)
def test_create_new_user_creates_email_preferences(self): self.assertFalse(EmailPreference.objects.all().exists()) # Signals take care of creating the Email preferences UserFactory.create() self.assertTrue(EmailPreference.objects.all().exists())
def test_list_author_cannot_comment_on_approved_list(self, m): record_manager = UserFactory( role__can_start_destruction=True, role__type=RoleTypeChoices.archivist ) process_owner = UserFactory( role__can_review_destruction=True, role__type=RoleTypeChoices.process_owner ) destruction_list = DestructionListFactory.create(author=record_manager) DestructionListItemFactory.create_batch(2, destruction_list=destruction_list) DestructionListReviewFactory.create( destruction_list=destruction_list, author=process_owner, status=ReviewStatus.approved, ) self.client.force_login(record_manager) response = self.client.get( reverse("destruction:record-manager-detail", args=[destruction_list.pk]), user=record_manager, ) self.assertEqual(200, response.status_code) self.assertNotIn(b"<textarea", response.content)
def test_archivist_cannot_download(self): archivist = UserFactory.create(role__can_review_destruction=True, role__type=RoleTypeChoices.archivist) process_owner = UserFactory.create( role__can_review_destruction=True, role__type=RoleTypeChoices.functional_admin, ) list_reviewed = DestructionListFactory.create( name="list reviewed", status=ListItemStatus.destroyed) DestructionListReviewFactory.create(destruction_list=list_reviewed, author=archivist) DestructionReportFactory.create(destruction_list=list_reviewed, process_owner=process_owner) self.app.set_user(archivist) response = self.app.get(self.url, {"reviewed": ReviewerDisplay.reviewed}) self.assertEqual(response.status_code, 200) destruction_lists = response.html.find_all( class_="destruction-list-preview") self.assertEqual(len(destruction_lists), 1) self.assertNotIn("Download verklaring van vernietiging", response.html.text)
def test_state_after_changes_requested(self): record_manager = UserFactory(role__can_start_destruction=True, role__type=RoleTypeChoices.record_manager) process_owner = UserFactory(role__can_review_destruction=True, role__type=RoleTypeChoices.process_owner) archivist = UserFactory(role__can_review_destruction=True, role__type=RoleTypeChoices.archivist) destruction_list = DestructionListFactory.create(author=record_manager) DestructionListAssigneeFactory.create( assignee=process_owner, destruction_list=destruction_list, order=1) DestructionListAssigneeFactory.create( assignee=archivist, destruction_list=destruction_list, order=2) DestructionListReviewFactory.create( author=process_owner, status=ReviewStatus.changes_requested, destruction_list=destruction_list, ) destruction_list.assignee = record_manager destruction_list.save() list_state = destruction_list.list_state() self.assertEqual("changes_requested", list_state.value) self.assertEqual(2, destruction_list.total_reviewers()) self.assertEqual(0, destruction_list.completed_reviewers())
def setUpTestData(cls): AutomaticEmailFactory.create( type=EmailTypeChoices.review_required, body="Review is required!", subject="Review", ) AutomaticEmailFactory.create( type=EmailTypeChoices.changes_required, body="Changes are required!", subject="Changes", ) record_manager = RoleFactory.create(record_manager=True) process_owner = RoleFactory.create(process_owner=True) user_author = UserFactory.create(role=record_manager, email="*****@*****.**") user_reviewer = UserFactory.create(role=process_owner, email="*****@*****.**") destruction_list = DestructionListFactory.create(author=user_author) DestructionListAssigneeFactory.create( destruction_list=destruction_list, assignee=user_reviewer) cls.destruction_list = destruction_list cls.user_author = user_author cls.user_reviewer = user_reviewer
def test_reviewer_landing_page(self): url = reverse("destruction:reviewer-list") reviewer = UserFactory.create(role__can_review_destruction=True) other_user = UserFactory.create(role__can_review_destruction=False) self.assertLoginRequired(url) self.assertHasPermission(url, reviewer) self.assertHasNoPermission(url, other_user)
def test_wrong_user_cant_access(self): user_1 = UserFactory.create() user_2 = UserFactory.create() self.client.force_login(user_1) response = self.client.get( reverse("emails:email-preference-update", args=[user_2.emailpreference.pk])) self.assertEqual(403, response.status_code)
def test_list_author_can_leave_comment_empty(self, m): record_manager = UserFactory( role__can_start_destruction=True, role__type=RoleTypeChoices.archivist ) process_owner = UserFactory( role__can_review_destruction=True, role__type=RoleTypeChoices.process_owner ) destruction_list = DestructionListFactory.create(author=record_manager) item = DestructionListItemFactory.create(destruction_list=destruction_list) DestructionListAssigneeFactory.create( assignee=record_manager, destruction_list=destruction_list ) destruction_list.assignee = record_manager destruction_list.save() DestructionListReviewFactory.create( destruction_list=destruction_list, author=process_owner, status=ReviewStatus.changes_requested, ) data = { "items-TOTAL_FORMS": 1, "items-INITIAL_FORMS": 1, "items-MIN_NUM_FORMS": 0, "items-MAX_NUM_FORMS": 1000, "items-0-id": item.id, "items-0-action": "", "items-0-archiefnominatie": "blijvend_bewaren", "items-0-archiefactiedatum": "2020-06-17", "items-0-identificatie": "ZAAK-01", } self.client.force_login(record_manager) response = self.client.post( reverse("destruction:record-manager-detail", args=[destruction_list.pk]), data=data, ) self.assertRedirects(response, reverse("destruction:record-manager-list")) comments = DestructionListReviewComment.objects.all() self.assertEqual(0, comments.count()) logs = TimelineLog.objects.all() self.assertEqual(1, logs.count()) log = logs.first() self.assertIn("text", log.extra_data) self.assertEqual("", log.extra_data["text"])
def test_only_comments_from_archivaris_returned(self): archivaris = UserFactory.create( role__type=RoleTypeChoices.archivist, role__can_start_destruction=False, role__can_review_destruction=True, role__can_view_case_details=False, ) process_owner = UserFactory.create( role__type=RoleTypeChoices.process_owner, role__can_start_destruction=False, role__can_review_destruction=True, role__can_view_case_details=True, ) destruction_list = DestructionListFactory.create( status=ListStatus.processing) DestructionListItemFactory.create( destruction_list=destruction_list, status=ListItemStatus.failed, extra_zaak_data={ "identificatie": "ZAAK-1", "omschrijving": "Een zaak", "toelichting": "Bah", "startdatum": "2020-01-01", "einddatum": "2021-01-01", "zaaktype": "https://oz.nl/catalogi/api/v1/zaaktypen/uuid-1", }, ) DestructionListItemFactory.create( destruction_list=destruction_list, status=ListItemStatus.destroyed, extra_zaak_data={ "identificatie": "ZAAK-2", "omschrijving": "Een andere zaak", "toelichting": "", "startdatum": "2020-02-01", "einddatum": "2021-03-01", "zaaktype": "https://oz.nl/catalogi/api/v1/zaaktypen/uuid-2", }, ) DestructionListReviewFactory.create( destruction_list=destruction_list, status=ReviewStatus.approved, author=archivaris, text="What a magnificent list!", ) DestructionListReviewFactory.create( destruction_list=destruction_list, status=ReviewStatus.approved, author=process_owner, text="I am happy with this list!", ) comment = get_destruction_list_archivaris_comments(destruction_list) self.assertEqual("What a magnificent list!", comment)
def test_start_page_with_demo_details_if_demo_mode(self): UserFactory.create( username="******", role__can_start_destruction=True, role__can_review_destruction=False, role__can_view_case_details=True, ) response = self.client.get(reverse("entry"), follow=True) self.assertEqual(200, response.status_code) self.assertIn(b"demo mode", response.content)
def test_demo_mode_normal_user(self): UserFactory.create( username="******", role__can_start_destruction=True, role__can_review_destruction=False, role__can_view_case_details=True, ) response = self.client.get(reverse("demo-login", args=[self.user.pk]), follow=True) self.assertEqual(200, response.status_code) self.assertEqual(response.request["PATH_INFO"], reverse("start-page"))
def test_archivarist_cant_access(self): process_owner = UserFactory.create(role__type=RoleTypeChoices.process_owner) archivist = UserFactory.create(role__type=RoleTypeChoices.archivist) report = DestructionReportFactory.create(process_owner=process_owner) self.client.force_login(archivist) response_pdf = self.client.get( reverse("report:download-report", args=[report.pk]), data={"type": "pdf"} ) response_csv = self.client.get( reverse("report:download-report", args=[report.pk]), data={"type": "csv"} ) self.assertEqual(403, response_pdf.status_code) self.assertEqual(403, response_csv.status_code)
def setUpTestData(cls): cls.record_manager = UserFactory( role__can_start_destruction=True, role__type=RoleTypeChoices.record_manager) cls.process_owner = UserFactory( role__can_review_destruction=True, role__type=RoleTypeChoices.process_owner) # List 1: In progress cls.dl_in_progress = DestructionListFactory.create( author=cls.record_manager) assignee = DestructionListAssigneeFactory.create( assignee=cls.process_owner, destruction_list=cls.dl_in_progress, order=1) cls.dl_in_progress.assignee = assignee.assignee cls.dl_in_progress.save() # List 2: Changes requested cls.dl_changes_required = DestructionListFactory.create( author=cls.record_manager) assignee = DestructionListAssigneeFactory.create( assignee=cls.record_manager, destruction_list=cls.dl_changes_required) cls.dl_changes_required.assignee = assignee.assignee cls.dl_changes_required.save() # List 3: Rejected cls.dl_rejected = DestructionListFactory.create( author=cls.record_manager) assignee = DestructionListAssigneeFactory.create( assignee=cls.record_manager, destruction_list=cls.dl_rejected) cls.dl_rejected.assignee = assignee.assignee cls.dl_rejected.save() # List 4: Approved cls.dl_approved = DestructionListFactory.create( author=cls.record_manager) cls.dl_approved.assignee = None cls.dl_approved.save() # List 5: Complete cls.dl_complete = DestructionListFactory.create( author=cls.record_manager) cls.dl_complete.process() cls.dl_complete.save() cls.dl_complete.complete() cls.dl_complete.save()
def test_no_municipality_configured(self): config = EmailConfig.get_solo() config.municipality = "" config.save() user = UserFactory.create(is_staff=True, is_superuser=True) response = self.app.get(reverse("admin:emails_automaticemail_add"), user=user) form = response.form form["type"] = EmailTypeChoices.review_required form["body"] = "This is a test body with a variable {{ municipality }}" form["subject"] = "Test subject" response = form.submit() self.assertEqual(200, response.status_code) self.assertIn( "When using the municipality variable, a municipality name needs to be configured.", response.text, ) self.assertEqual(0, AutomaticEmail.objects.count())
def setUpTestData(cls): super().setUpTestData() cls.functioneel_beheer = UserFactory.create( username="******", role__can_start_destruction=True, role__can_review_destruction=True, role__can_view_case_details=True, ) cls.process_eigenaar = UserFactory.create( username="******", role__can_start_destruction=False, role__can_review_destruction=True, role__can_view_case_details=True, ) cls.user = UserFactory.create(username="******")
def test_send_email_with_variables(self): recipient = UserFactory.create(first_name="John", last_name="Doe") config = EmailConfig.objects.create() config.municipality = "Gemeente X" config.save() destruction_list = DestructionListFactory.create( name="Interesting List") email = AutomaticEmailFactory( body="This is a test email for {{ user }} " "from municipality {{ municipality }} about " "the list {{ list }} ({{ link_list }})", subject="This is a test subject", ) email.send(recipient=recipient, destruction_list=destruction_list) self.assertEqual(1, len(mail.outbox)) sent_mail = mail.outbox[0] list_url = get_absolute_url( reverse("destruction:dl-redirect", args=[destruction_list.pk])) expected_body = ( f"This is a test email for John Doe from municipality Gemeente X about the " f"list Interesting List ({list_url})") self.assertEqual(expected_body, sent_mail.body) self.assertEqual("This is a test subject", sent_mail.subject)
def test_logs_are_in_correct_order(self): record_manager = UserFactory.create( role__type=RoleTypeChoices.record_manager) archivaris = UserFactory.create(role__type=RoleTypeChoices.archivist) destruction_list = DestructionListFactory.create(author=record_manager) review = DestructionListReviewFactory.create( destruction_list=destruction_list, author=archivaris) with freeze_time("2012-01-14 12:00"): TimelineLog.objects.create( content_object=destruction_list, template="destruction/logs/created.html", extra_data={"n_items": 3}, user=record_manager, ) with freeze_time("2012-01-14 12:05"): TimelineLog.objects.create( content_object=review, template="destruction/logs/review_created.html", user=archivaris, ) with freeze_time("2012-01-14 12:10"): TimelineLog.objects.create( content_object=destruction_list, template="destruction/logs/updated.html", extra_data={"n_items": 1}, user=record_manager, ) with freeze_time("2012-01-14 12:15"): TimelineLog.objects.create( content_object=destruction_list, template="destruction/logs/aborted.html", extra_data={"n_items": 3}, user=record_manager, ) report = create_audittrail_report(destruction_list) html_report = document_fromstring(report) self.assertEqual(4, len(html_report.find_class("log-item"))) titles = html_report.find_class("log-item__title") times = [title.text_content() for title in titles] sorted_times = sorted(times) self.assertEqual(times, sorted_times)
def test_no_sensitive_data_for_process_owner(self, m): self._set_up_services() record_manager = UserFactory.create( role__can_start_destruction=True, role__type=RoleTypeChoices.record_manager, ) process_owner = UserFactory.create( role__can_review_destruction=True, role__type=RoleTypeChoices.process_owner, ) destruction_list = DestructionListFactory.create( author=record_manager, assignee=process_owner, contains_sensitive_info=False, ) DestructionListItemFactory.create( destruction_list=destruction_list, zaak=ZAAK_1["url"] ) DestructionListItemFactory.create( destruction_list=destruction_list, zaak=ZAAK_2["url"] ) DestructionListAssigneeFactory.create( destruction_list=destruction_list, assignee=process_owner ) self._set_up_mocks(m) url = reverse("destruction:fetch-list-items", args=[destruction_list.id]) self.client.force_login(process_owner) response = self.client.get(url) self.assertEqual(200, response.status_code) response_data = response.json() self.assertIn("items", response_data) self.assertEqual(2, len(response_data["items"])) # Since the list does NOT contain sensitive data, the process owner can see it zaak_1_data = response_data["items"][0]["zaak"] self.assertIn("omschrijving", zaak_1_data) zaak_2_data = response_data["items"][1]["zaak"] self.assertIn("omschrijving", zaak_2_data)
def test_state_after_creation(self): record_manager = UserFactory(role__can_start_destruction=True, role__type=RoleTypeChoices.record_manager) process_owner = UserFactory(role__can_review_destruction=True, role__type=RoleTypeChoices.process_owner) destruction_list = DestructionListFactory.create(author=record_manager) assignee = DestructionListAssigneeFactory.create( assignee=process_owner, destruction_list=destruction_list, order=1) destruction_list.assignee = assignee.assignee destruction_list.save() list_state = destruction_list.list_state() self.assertEqual("in_progress", list_state.value) self.assertEqual(1, destruction_list.total_reviewers()) self.assertEqual(0, destruction_list.completed_reviewers())
def test_right_user_can_access(self): user = UserFactory.create() self.client.force_login(user) response = self.client.get( reverse("emails:email-preference-update", args=[user.emailpreference.pk])) self.assertEqual(200, response.status_code)
def test_cant_add_report(self): superuser = UserFactory.create(is_staff=True, is_superuser=True) self.client.force_login(superuser) url = reverse("admin:report_destructionreport_add") response = self.client.get(url) self.assertEqual(403, response.status_code)
def test_sensitive_data_for_archivist(self, m): self._set_up_services() record_manager = UserFactory.create( role__can_start_destruction=True, role__type=RoleTypeChoices.record_manager, ) archivist = UserFactory.create( role__can_review_destruction=True, role__type=RoleTypeChoices.archivist, ) destruction_list = DestructionListFactory.create( author=record_manager, assignee=archivist, contains_sensitive_info=True, ) DestructionListItemFactory.create( destruction_list=destruction_list, zaak=ZAAK_1["url"] ) DestructionListItemFactory.create( destruction_list=destruction_list, zaak=ZAAK_2["url"] ) DestructionListAssigneeFactory.create( destruction_list=destruction_list, assignee=archivist ) self._set_up_mocks(m) url = reverse("destruction:fetch-list-items", args=[destruction_list.id]) self.client.force_login(archivist) response = self.client.get(url) self.assertEqual(200, response.status_code) response_data = response.json() self.assertIn("items", response_data) self.assertEqual(2, len(response_data["items"])) # The list contains sensitive data, the archivist should NOT be able to see it zaak_1_data = response_data["items"][0]["zaak"] self.assertNotIn("omschrijving", zaak_1_data) zaak_2_data = response_data["items"][1]["zaak"] self.assertNotIn("omschrijving", zaak_2_data)
def test_logs_from_right_list_are_shown(self): record_manager = UserFactory.create( role__type=RoleTypeChoices.record_manager) archivaris = UserFactory.create(role__type=RoleTypeChoices.archivist) destruction_list_1 = DestructionListFactory.create( author=record_manager, name="Incredible list 1") review_1 = DestructionListReviewFactory.create( destruction_list=destruction_list_1, author=archivaris) destruction_list_2 = DestructionListFactory.create( author=record_manager, name="Incredible list 2") review_2 = DestructionListReviewFactory.create( destruction_list=destruction_list_2, author=archivaris) TimelineLog.objects.create( content_object=destruction_list_1, template="destruction/logs/created.html", extra_data={"n_items": 3}, user=record_manager, ) TimelineLog.objects.create( content_object=review_1, template="destruction/logs/review_created.html", user=archivaris, ) # These should not appear in the audit trail report, because they are not related to the right list TimelineLog.objects.create( content_object=destruction_list_2, template="destruction/logs/created.html", extra_data={"n_items": 3}, user=record_manager, ) TimelineLog.objects.create( content_object=review_2, template="destruction/logs/review_created.html", user=archivaris, ) report = create_audittrail_report(destruction_list_1) html_report = document_fromstring(report) self.assertEqual(2, len(html_report.find_class("log-item"))) self.assertIn("Incredible list 1", report) self.assertNotIn("Incredible list 2", report)
def setUpTestData(cls): record_manager = RoleFactory.create(record_manager=True) process_owner = RoleFactory.create(process_owner=True) archivaris = RoleFactory.create(archivaris=True) user1 = UserFactory.create(role=record_manager) user2 = UserFactory.create(role=process_owner) user3 = UserFactory.create(role=archivaris) destruction_list = DestructionListFactory.create(author=user1) DestructionListAssigneeFactory.create( destruction_list=destruction_list, assignee=user2) DestructionListAssigneeFactory.create( destruction_list=destruction_list, assignee=user3) cls.destruction_list = destruction_list cls.user1 = user1 cls.user2 = user2 cls.user3 = user3
def test_functional_admin_can_access(self): process_owner = UserFactory.create(role__type=RoleTypeChoices.process_owner) functional_admin = UserFactory.create( role__type=RoleTypeChoices.functional_admin ) report = DestructionReportFactory.create(process_owner=process_owner) self.client.force_login(functional_admin) response_pdf = self.client.get( reverse("report:download-report", args=[report.pk]), data={"type": "pdf"} ) response_csv = self.client.get( reverse("report:download-report", args=[report.pk]), data={"type": "csv"} ) self.assertEqual(200, response_pdf.status_code) self.assertGreater(len(response_pdf.content), 0) self.assertEqual(200, response_csv.status_code) self.assertGreater(len(response_csv.content), 0)
def test_state_after_rejection(self): record_manager = UserFactory(role__can_start_destruction=True, role__type=RoleTypeChoices.record_manager) archivist = UserFactory(role__can_review_destruction=True, role__type=RoleTypeChoices.archivist) destruction_list = DestructionListFactory.create(author=record_manager) DestructionListReviewFactory.create( author=archivist, status=ReviewStatus.rejected, destruction_list=destruction_list, ) destruction_list.assignee = record_manager destruction_list.save() list_state = destruction_list.list_state() self.assertEqual("rejected", list_state.value)
def test_state_after_last_review(self): record_manager = UserFactory(role__can_start_destruction=True, role__type=RoleTypeChoices.record_manager) destruction_list = DestructionListFactory.create(author=record_manager) destruction_list.assignee = None destruction_list.save() list_state = destruction_list.list_state() self.assertEqual("approved", list_state.value)
def setUpTestData(cls): cls.user = UserFactory.create(role__can_review_destruction=True) cls.list_to_review = DestructionListFactory.create( assignee=cls.user, name="list to review") DestructionListReviewFactory.create( destruction_list=cls.list_to_review, author=cls.user) cls.list_reviewed = DestructionListFactory.create(name="list reviewed") DestructionListReviewFactory.create(destruction_list=cls.list_reviewed, author=cls.user) cls.list_extra = DestructionListFactory.create(author=cls.user, name="list extra")
def test_zaakafhandelcomponent_link(self, m): self._set_up_services() config = ArchiveConfig.get_solo() config.link_to_zac = ( "http://example.nl/{{ bronorganisatie }}/{{ identificatie }}/{{ uuid }}" ) config.save() user = UserFactory.create( username="******", password="******", email="*****@*****.**", role__can_start_destruction=True, role__can_review_destruction=True, ) destruction_list = DestructionListFactory.create(author=user, assignee=user) DestructionListItemFactory.create( destruction_list=destruction_list, zaak=ZAAK_1["url"] ) DestructionListItemFactory.create( destruction_list=destruction_list, zaak=ZAAK_2["url"] ) self._set_up_mocks(m) url = reverse("destruction:fetch-list-items", args=[destruction_list.id]) self.client.force_login(user) response = self.client.get(url) self.assertEqual(200, response.status_code) response_data = response.json() self.assertIn("items", response_data) self.assertEqual(2, len(response_data["items"])) zaak_1_data = response_data["items"][0]["zaak"] self.assertIn("zac_link", zaak_1_data) self.assertEqual( "http://example.nl/123456789/ZAAK-001/uuid-1", zaak_1_data["zac_link"] ) zaak_2_data = response_data["items"][1]["zaak"] self.assertIn("zac_link", zaak_2_data) self.assertEqual( "http://example.nl/987654321/ZAAK-002/uuid-2", zaak_2_data["zac_link"] )