def test_only_comments_from_process_owner_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_process_owner_comments(destruction_list)

        self.assertEqual("I am happy with this 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_retrieve_missing_zaak(self, m):
        self._set_up_services()
        self._set_up_mocks(m)

        user = UserFactory.create(
            username="******",
            password="******",
            email="*****@*****.**",
            role__can_start_destruction=True,
            role__can_review_destruction=True,
        )

        destruction_list = DestructionListFactory.create(author=user,
                                                         assignee=user)
        missing_zaak_url = f"{ZAKEN_ROOT}zaken/uuid-3"
        DestructionListItemFactory.create(destruction_list=destruction_list,
                                          zaak=missing_zaak_url)
        m.get(missing_zaak_url, status_code=404)

        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)
        self.assertIn("error", response.json())
    def test_empty_archiefactiedatum(self, m_update_zaak, m_fetch_zaak):
        user = UserFactory(role__can_start_destruction=True)
        view_url = furl(reverse("destruction:update-zaak-archive-details"))
        view_url.args.set("url", "http://openzaak.nl/some/zaak")

        form = self.app.get(view_url.url, user=user).form

        form["url"] = "http://openzaak.nl/some/valid/zaak/url"
        form["archiefnominatie"] = Archiefnominatie.blijvend_bewaren
        form["comment"] = "Some interesting comment"

        response = form.submit()

        self.assertRedirects(response,
                             view_url.url,
                             fetch_redirect_response=False)
        m_update_zaak.assert_called_with(
            "http://openzaak.nl/some/valid/zaak/url",
            {"archiefnominatie": Archiefnominatie.blijvend_bewaren},
            audit_comment="Some interesting comment",
        )

        response = response.follow()
        messages = list(response.context.get("messages"))

        self.assertEqual(1, len(messages))
        self.assertEqual(messages[0].tags, "success")
    def test_assigned_on_field_population_on_assignment(self):
        reviewers = UserFactory.create_batch(2,
                                             role__can_review_destruction=True)
        zaken = [f"http://some.zaken.nl/api/v1/zaken/{i}" for i in range(1, 3)]
        zaken_identificaties = ["ZAAK-1", "ZAAK-2", "ZAAK-3"]

        url = reverse("destruction:record-manager-create")
        data = {
            "name": "test list",
            "zaken": ",".join(zaken),
            "reviewer_1": reviewers[0].id,
            "reviewer_2": reviewers[1].id,
            "zaken_identificaties": ",".join(zaken_identificaties),
        }

        response = self.client.post(url, data)

        self.assertRedirects(response,
                             reverse("destruction:record-manager-list"))

        destruction_list = DestructionList.objects.get()
        assignees = destruction_list.assignees.order_by("id")

        self.assertIsNotNone(assignees.first().assigned_on)
        self.assertIsNone(assignees.last().assigned_on)
Example #7
0
    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_create_zaak_set(self):
        user = UserFactory.create(is_staff=True, is_superuser=True)
        response = self.app.get(
            reverse("admin:destruction_archiveconfig_change"), user=user
        )
        form = response.form
        form["create_zaak"] = True
        form["source_organisation"] = "111222333"
        form["case_type"] = "http://openzaak.nl/zaaktype/1"
        form["status_type"] = "http://openzaak.nl/statustype/1"
        form["result_type"] = "http://openzaak.nl/resultaattype/1"
        form["document_type"] = "http://openzaak.nl/informatieobjecttype/1"

        response = form.submit().follow()

        self.assertEqual(200, response.status_code)

        conf = ArchiveConfig.get_solo()

        self.assertEqual(conf.create_zaak, True)
        self.assertEqual(conf.source_organisation, "111222333")
        self.assertEqual(conf.case_type, "http://openzaak.nl/zaaktype/1")
        self.assertEqual(conf.result_type, "http://openzaak.nl/resultaattype/1")
        self.assertEqual(conf.status_type, "http://openzaak.nl/statustype/1")
        self.assertEqual(
            conf.document_type, "http://openzaak.nl/informatieobjecttype/1"
        )
Example #10
0
    def test_empty_comment_is_not_saved(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",
            "text": "",
        }

        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())
    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_permission_denied_if_no_zaak_url(self):
        user = UserFactory(role__can_start_destruction=True)
        self.client.force_login(user)

        response = self.client.get(
            reverse("destruction:update-zaak-archive-details"))

        self.assertEqual(403, response.status_code)
Example #13
0
    def test_no_zaak_urls_query_param_raises_error(self):
        user = UserFactory(role__can_start_destruction=True)
        self.client.force_login(user)
        url = furl(reverse("destruction:export-zaken-without-archive-date"))

        response = self.client.get(url.url)

        self.assertEqual(400, response.status_code)
    def test_fetch_zaken_no_filters(self, m):
        user = UserFactory.create(role__can_start_destruction=True)
        self.client.force_login(user)

        response = self.client.get(reverse("destruction:fetch-zaken"))

        self.assertEqual(200, response.status_code)
        m.assert_called_once_with({})
    def setUpTestData(cls):
        cls.user = UserFactory.create(role__can_review_destruction=True)

        destruction_list = DestructionListFactory.create()
        DestructionListReviewFactory.create(destruction_list=destruction_list,
                                            author=cls.user)
        DestructionReportFactory.create(destruction_list=destruction_list,
                                        process_owner=cls.user)
    def test_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=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=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"]))

        # Even if the list contains sensitive data, the process owner should be able to 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_no_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=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=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"]))

        # Since the list does NOT contain sensitive data, the archivist 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)
Example #18
0
    def test_cant_access_without_can_start_destruction(self):
        user = UserFactory(role__can_start_destruction=False)
        self.client.force_login(user)

        response = self.client.get(
            reverse("destruction:zaken-without-archive-date"))

        self.assertEqual(403, response.status_code)
Example #19
0
    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_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)
Example #21
0
    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_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)
Example #23
0
    def test_archivarist_cant_access(self, m_archive_config):
        m_archive_config.return_value = ArchiveConfig(
            destruction_report_downloadable=True)

        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 test_can_access_with_can_start_destruction_and_zaak_url(
            self, m_fetch_zaak):
        user = UserFactory(role__can_start_destruction=True)
        self.client.force_login(user)

        form_url = furl(reverse("destruction:update-zaak-archive-details"))
        form_url.args.set("url", "http://openzaak.nl/some/zaak")

        response = self.client.get(form_url.url)

        self.assertEqual(200, response.status_code)
Example #25
0
    def test_can_access_with_can_start_destruction(self, m_choices):
        user = UserFactory(role__can_start_destruction=True)
        self.client.force_login(user)

        response = self.client.get(
            reverse("destruction:zaken-without-archive-date"))

        self.assertEqual(200, response.status_code)
        self.assertIn("zaaktypen", response.context_data)
        self.assertEqual("http://test.zaaktype.nl",
                         response.context_data["zaaktypen"][0]["url"])
Example #26
0
    def test_complete_and_notify_process_owner(self, m):
        process_owner = UserFactory.create(
            role__type=RoleTypeChoices.process_owner,
            role__can_review_destruction=True,
            role__can_view_case_details=True,
        )
        destruction_list = DestructionListFactory.create(name="Summer List", )
        DestructionListReviewFactory.create(
            author=process_owner,
            status=ReviewStatus.approved,
            destruction_list=destruction_list,
        )

        destruction_list.process()
        destruction_list.save()

        complete_and_notify(destruction_list.id)

        notifications = Notification.objects.all()

        self.assertEqual(2, notifications.count())

        notification = notifications.get(user=process_owner)

        self.assertEqual(notification.destruction_list, destruction_list)

        report = DestructionReport.objects.get()

        self.assertEqual(
            notification.message,
            _("Destruction list %(list)s has been processed. "
              "You can download the report of destruction here: %(url)s") % {
                  "list":
                  "Summer List",
                  "url":
                  "http://example.com{}".format(
                      reverse("report:download-report", args=[report.pk])),
              },
        )

        self.client.force_login(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(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 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 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