Esempio n. 1
0
 def test_composer_detail_single_submitted(self):
     """Composer redirects to foia page if only a single request even
     if it hasn't been filed yet"""
     foia = FOIARequestFactory(
         composer__status='submitted',
         composer__datetime_submitted=timezone.now(),
     )
     composer = foia.composer
     request = self.request_factory.get(
         reverse(
             'foia-composer-detail',
             kwargs={
                 'slug': composer.slug,
                 'idx': composer.pk
             }
         )
     )
     request.user = UserFactory()
     request = mock_middleware(request)
     response = ComposerDetail.as_view()(
         request,
         slug=composer.slug,
         idx=composer.pk,
     )
     eq_(response.status_code, 302)
     eq_(response.url, foia.get_absolute_url())
Esempio n. 2
0
 def test_composer_detail_single(self):
     """Composer redirects to foia page if only a single request"""
     foia = FOIARequestFactory(composer__status="filed")
     composer = foia.composer
     request = self.request_factory.get(
         reverse(
             "foia-composer-detail",
             kwargs={
                 "slug": composer.slug,
                 "idx": composer.pk
             },
         ))
     request.user = UserFactory()
     request = mock_middleware(request)
     response = ComposerDetail.as_view()(request,
                                         slug=composer.slug,
                                         idx=composer.pk)
     eq_(response.status_code, 302)
     eq_(response.url, foia.get_absolute_url())
Esempio n. 3
0
 def test_get_foia(self):
     """Try getting the detail page for a FOIA Request with an unread notification."""
     agency = AgencyFactory()
     foia = FOIARequestFactory(agency=agency)
     view = FOIARequestDetail.as_view()
     # Create a notification for the request
     action = new_action(agency, 'completed', target=foia)
     notification = notify(self.user, action)[0]
     ok_(not notification.read, 'The notification should be unread.')
     # Try getting the view as the user
     response = http_get_response(foia.get_absolute_url(),
                                  view,
                                  self.user,
                                  idx=foia.pk,
                                  slug=foia.slug,
                                  jidx=foia.jurisdiction.pk,
                                  jurisdiction=foia.jurisdiction.slug)
     eq_(response.status_code, 200, 'The view should response 200 OK.')
     # Check that the notification has been read.
     notification.refresh_from_db()
     ok_(notification.read, 'The notification should be marked as read.')
Esempio n. 4
0
class TestFOIANotes(TestCase):
    """Allow editors to attach notes to a request."""

    def setUp(self):
        self.foia = FOIARequestFactory()
        self.editor = UserFactory()
        self.viewer = UserFactory()
        self.foia.add_editor(self.editor)
        self.foia.add_viewer(self.viewer)
        self.data = {
            'action': 'add_note',
            'note': u'Lorem ipsum dolor su ament.'
        }
        self.url = self.foia.get_absolute_url()
        self.view = Detail.as_view()
        self.kwargs = {
            'jurisdiction': self.foia.jurisdiction.slug,
            'jidx': self.foia.jurisdiction.id,
            'slug': self.foia.slug,
            'idx': self.foia.id
        }
        UserFactory(username='******')

    def test_add_note(self):
        """User with edit permission should be able to create a note."""
        response = http_post_response(
            self.url, self.view, self.data, self.editor, **self.kwargs
        )
        self.foia.refresh_from_db()
        eq_(response.status_code, 302)
        eq_(self.foia.notes.count() > 0, True)

    def test_add_sans_permission(self):
        """Normies and viewers cannot add notes."""
        response = http_post_response(
            self.url, self.view, self.data, self.viewer, **self.kwargs
        )
        self.foia.refresh_from_db()
        eq_(response.status_code, 302)
        eq_(self.foia.notes.count(), 0)
Esempio n. 5
0
class TestEmbargo(TestCase):
    """Embargoing a request hides it from public view."""
    def setUp(self):
        self.user = ProfessionalUserFactory()
        self.foia = FOIARequestFactory(composer__user=self.user)
        self.request_factory = RequestFactory()
        self.url = self.foia.get_absolute_url()

    def get_response(self, request):
        """Utility function for calling the embargo view function"""
        request = mock_middleware(request)
        return embargo(
            request,
            self.foia.jurisdiction.slug,
            self.foia.jurisdiction.pk,
            self.foia.slug,
            self.foia.pk,
        )

    def test_basic_embargo(self):
        """The embargo should be accepted if the owner can embargo and edit the request."""
        ok_(self.foia.has_perm(self.user, 'change'),
            'The request should be editable by the user.')
        ok_(self.foia.has_perm(self.user, 'embargo'),
            'The user should be allowed to embargo.')
        ok_(self.foia.status not in END_STATUS,
            'The request should not be closed.')
        data = {'embargo': 'create'}
        request = self.request_factory.post(self.url, data)
        request.user = self.user
        response = self.get_response(request)
        self.foia.refresh_from_db()
        eq_(response.status_code, 302)
        ok_(self.foia.embargo, 'An embargo should be set on the request.')

    def test_no_permission_to_edit(self):
        """Users without permission to edit the request should not be able to change the embargo"""
        user_without_permission = ProfessionalUserFactory()
        assert_false(self.foia.has_perm(user_without_permission, 'change'))
        data = {'embargo': 'create'}
        request = self.request_factory.post(self.url, data)
        request.user = user_without_permission
        response = self.get_response(request)
        self.foia.refresh_from_db()
        eq_(response.status_code, 302)
        ok_(not self.foia.embargo,
            'The embargo should not be set on the request.')

    def test_no_permission_to_embargo(self):
        """Users without permission to embargo the request should not be allowed to do so."""
        user_without_permission = UserFactory()
        self.foia.composer.user = user_without_permission
        self.foia.composer.save()
        ok_(self.foia.has_perm(user_without_permission, 'change'))
        assert_false(self.foia.has_perm(user_without_permission, 'embargo'))
        data = {'embargo': 'create'}
        request = self.request_factory.post(self.url, data)
        request.user = user_without_permission
        response = self.get_response(request)
        self.foia.refresh_from_db()
        eq_(response.status_code, 302)
        ok_(not self.foia.embargo,
            'The embargo should not be set on the request.')

    def test_unembargo(self):
        """
        The embargo should be removable by editors of the request.
        Any user should be allowed to remove an embargo, even if they cannot apply one.
        """
        user_without_permission = UserFactory()
        self.foia.composer.user = user_without_permission
        self.foia.composer.save()
        self.foia.embargo = True
        self.foia.save()
        assert_true(self.foia.embargo)
        assert_true(self.foia.has_perm(user_without_permission, 'change'))
        assert_false(self.foia.has_perm(user_without_permission, 'embargo'))
        data = {'embargo': 'delete'}
        request = self.request_factory.post(self.url, data)
        request.user = user_without_permission
        response = self.get_response(request)
        self.foia.refresh_from_db()
        eq_(response.status_code, 302)
        assert_false(self.foia.embargo,
                     'The embargo should be removed from the request.')

    def _test_embargo_details(self):
        """
        If the request is in a closed state, it needs a date to be applied.
        If the user has permission, apply a permanent embargo.
        """
        self.foia.status = 'rejected'
        self.foia.save()
        default_expiration_date = datetime.date.today() + datetime.timedelta(1)
        embargo_form = FOIAEmbargoForm({
            'permanent_embargo': True,
            'date_embargo': default_expiration_date
        })
        assert_true(embargo_form.is_valid(), 'Form should validate.')
        assert_true(self.foia.has_perm(self.user, 'embargo_perm'))
        data = {'embargo': 'create'}
        data.update(embargo_form.data)
        request = self.request_factory.post(self.url, data)
        request.user = self.user
        response = self.get_response(request)
        self.foia.refresh_from_db()
        eq_(response.status_code, 302)
        assert_true(self.foia.embargo,
                    'An embargo should be set on the request.')
        eq_(self.foia.date_embargo, default_expiration_date,
            'An expiration date should be set on the request.')
        assert_true(self.foia.permanent_embargo,
                    'A permanent embargo should be set on the request.')

    def test_cannot_permanent_embargo(self):
        """Users who cannot set permanent embargoes shouldn't be able to."""
        user_without_permission = ProfessionalUserFactory()
        self.foia.composer.user = user_without_permission
        self.foia.composer.save()
        assert_true(self.foia.has_perm(user_without_permission, 'embargo'))
        assert_false(
            self.foia.has_perm(user_without_permission, 'embargo_perm'))
        assert_true(self.foia.has_perm(user_without_permission, 'change'))
        embargo_form = FOIAEmbargoForm({'permanent_embargo': True})
        assert_true(embargo_form.is_valid(), 'Form should validate.')
        data = {'embargo': 'create'}
        data.update(embargo_form.data)
        request = self.request_factory.post(self.url, data)
        request.user = self.foia.composer.user
        response = self.get_response(request)
        self.foia.refresh_from_db()
        eq_(response.status_code, 302)
        assert_true(self.foia.embargo,
                    'An embargo should be set on the request.')
        assert_false(self.foia.permanent_embargo,
                     'A permanent embargo should not be set on the request.')

    def test_update_embargo(self):
        """The embargo should be able to be updated."""
        self.foia.embargo = True
        self.foia.embargo_permanent = True
        self.foia.date_embargo = datetime.date.today() + datetime.timedelta(5)
        self.foia.status = 'rejected'
        self.foia.save()
        self.foia.refresh_from_db()
        assert_true(self.foia.embargo)
        expiration = datetime.date.today() + datetime.timedelta(15)
        embargo_form = FOIAEmbargoForm({'date_embargo': expiration})
        data = {'embargo': 'update'}
        data.update(embargo_form.data)
        request = self.request_factory.post(self.url, data)
        request.user = self.user
        response = self.get_response(request)
        eq_(response.status_code, 302)
        self.foia.refresh_from_db()
        assert_true(self.foia.embargo,
                    'The embargo should stay applied to the request.')
        assert_false(self.foia.permanent_embargo,
                     'The permanent embargo should be repealed.')
        eq_(self.foia.date_embargo, expiration,
            'The embargo expiration date should be updated.')

    def test_expire_embargo(self):
        """Any requests with an embargo date before today should be unembargoed"""
        self.foia.embargo = True
        self.foia.date_embargo = datetime.date.today() - datetime.timedelta(1)
        self.foia.status = 'rejected'
        self.foia.save()
        embargo_expire()
        self.foia.refresh_from_db()
        assert_false(self.foia.embargo, 'The embargo should be repealed.')

    def test_do_not_expire_permanent(self):
        """A request with a permanent embargo should stay embargoed."""
        self.foia.embargo = True
        self.foia.permanent_embargo = True
        self.foia.date_embargo = datetime.date.today() - datetime.timedelta(1)
        self.foia.status = 'rejected'
        self.foia.save()
        embargo_expire()
        self.foia.refresh_from_db()
        assert_true(self.foia.embargo, 'The embargo should remain embargoed.')

    def test_do_not_expire_no_date(self):
        """A request without an expiration date should not expire."""
        self.foia.embargo = True
        self.foia.save()
        embargo_expire()
        self.foia.refresh_from_db()
        assert_true(self.foia.embargo, 'The embargo should remain embargoed.')

    def test_expire_after_date(self):
        """Only after the date_embargo passes should the embargo expire."""
        self.foia.embargo = True
        self.foia.date_embargo = datetime.date.today()
        self.foia.status = 'rejected'
        self.foia.save()
        embargo_expire()
        self.foia.refresh_from_db()
        assert_true(self.foia.embargo, 'The embargo should remain embargoed.')

    def test_set_date_on_status_change(self):
        """
        If the request status is changed to an end status and it is embargoed,
        set the embargo expiration date to 30 days from today.
        """
        default_expiration_date = datetime.date.today() + datetime.timedelta(
            30)
        self.foia.embargo = True
        self.foia.save()
        self.foia.status = 'rejected'
        self.foia.save()
        self.foia.refresh_from_db()
        assert_true(self.foia.embargo and self.foia.status in END_STATUS)
        eq_(self.foia.date_embargo, default_expiration_date,
            'The embargo should be given an expiration date.')

    def test_set_date_exception(self):
        """
        If the request is changed to an inactive state, it is embargoed, and there is no
        previously set expiration date, then set the embargo expiration to its default value.
        """
        extended_expiration_date = datetime.date.today() + datetime.timedelta(
            15)
        self.foia.embargo = True
        self.foia.date_embargo = extended_expiration_date
        self.foia.status = 'rejected'
        self.foia.save()
        self.foia.refresh_from_db()
        assert_true(self.foia.embargo and self.foia.status in END_STATUS)
        eq_(self.foia.date_embargo, extended_expiration_date,
            'The embargo should not change the extended expiration date.')

    def test_remove_date(self):
        """The embargo date should be removed if the request is changed to an active state."""
        default_expiration_date = datetime.date.today() + datetime.timedelta(
            30)
        self.foia.embargo = True
        self.foia.save()
        self.foia.status = 'rejected'
        self.foia.save()
        self.foia.refresh_from_db()
        assert_true(self.foia.embargo and self.foia.status in END_STATUS)
        eq_(self.foia.date_embargo, default_expiration_date,
            'The embargo should be given an expiration date.')
        self.foia.status = 'appealing'
        self.foia.save()
        self.foia.refresh_from_db()
        assert_false(self.foia.embargo and self.foia.status in END_STATUS)
        ok_(not self.foia.date_embargo, 'The embargo date should be removed.')
Esempio n. 6
0
class TestFOIARequestUnit(RunCommitHooksMixin, TestCase):
    """Unit tests for FOIARequests"""
    def setUp(self):
        """Set up tests"""

        mail.outbox = []

        self.foia = FOIARequestFactory(status="submitted", title="Test 1")
        UserFactory(username="******")

    # models
    def test_foia_model_str(self):
        """Test FOIA Request model's __str__ method"""
        nose.tools.eq_(str(self.foia), "Test 1")

    def test_foia_model_url(self):
        """Test FOIA Request model's get_absolute_url method"""

        nose.tools.eq_(
            self.foia.get_absolute_url(),
            reverse(
                "foia-detail",
                kwargs={
                    "idx": self.foia.pk,
                    "slug": "test-1",
                    "jurisdiction": "massachusetts",
                    "jidx": self.foia.jurisdiction.pk,
                },
            ),
        )

    def test_foia_viewable(self):
        """Test all the viewable and embargo functions"""

        user1 = UserFactory()
        user2 = UserFactory()

        foias = [
            FOIARequestFactory(composer__user=user1,
                               status="done",
                               embargo=False),
            FOIARequestFactory(composer__user=user1,
                               status="done",
                               embargo=True),
            FOIARequestFactory(composer__user=user1,
                               status="done",
                               embargo=True),
        ]
        foias[2].add_viewer(user2)

        # check manager get_viewable against view permission
        viewable_foias = FOIARequest.objects.get_viewable(user1)
        for foia in FOIARequest.objects.all():
            if foia in viewable_foias:
                nose.tools.assert_true(foia.has_perm(user1, "view"))
            else:
                nose.tools.assert_false(foia.has_perm(user1, "view"))

        viewable_foias = FOIARequest.objects.get_viewable(user2)
        for foia in FOIARequest.objects.all():
            if foia in viewable_foias:
                nose.tools.assert_true(foia.has_perm(user2, "view"))
            else:
                nose.tools.assert_false(foia.has_perm(user2, "view"))

        viewable_foias = FOIARequest.objects.get_public()
        for foia in FOIARequest.objects.all():
            if foia in viewable_foias:
                nose.tools.assert_true(foia.has_perm(AnonymousUser(), "view"))
            else:
                nose.tools.assert_false(foia.has_perm(AnonymousUser(), "view"))

        nose.tools.assert_true(foias[0].has_perm(user1, "view"))
        nose.tools.assert_true(foias[1].has_perm(user1, "view"))
        nose.tools.assert_true(foias[2].has_perm(user1, "view"))

        nose.tools.assert_true(foias[0].has_perm(user2, "view"))
        nose.tools.assert_false(foias[1].has_perm(user2, "view"))
        nose.tools.assert_true(foias[2].has_perm(user2, "view"))

        nose.tools.assert_true(foias[0].has_perm(AnonymousUser(), "view"))
        nose.tools.assert_false(foias[1].has_perm(AnonymousUser(), "view"))
        nose.tools.assert_false(foias[2].has_perm(AnonymousUser(), "view"))

    def test_foia_viewable_org_share(self):
        """Test all the viewable and embargo functions"""
        user = UserFactory()
        foia = FOIARequestFactory(
            embargo=True, composer__organization=user.profile.organization)
        foias = FOIARequest.objects.get_viewable(user)
        nose.tools.assert_not_in(foia, foias)

        foia.user.profile.org_share = True
        foia.user.profile.save()
        foias = FOIARequest.objects.get_viewable(user)
        nose.tools.assert_in(foia, foias)

    def test_foia_set_mail_id(self):
        """Test the set_mail_id function"""
        foia = FOIARequestFactory()
        foia.set_mail_id()
        mail_id = foia.mail_id
        nose.tools.ok_(re.match(r"\d{1,4}-\d{8}", mail_id))

        foia.set_mail_id()
        nose.tools.eq_(mail_id, foia.mail_id)

    def test_foia_followup(self):
        """Make sure the follow up date is set correctly"""
        # pylint: disable=protected-access
        foia = FOIARequestFactory(
            composer__datetime_submitted=timezone.now(),
            status="processed",
            agency__jurisdiction__level="s",
            agency__jurisdiction__law__days=10,
        )
        FOIACommunicationFactory(foia=foia, response=True)
        foia.followup()
        self.run_commit_hooks()
        nose.tools.assert_in("I can expect", mail.outbox[-1].body)
        nose.tools.eq_(
            foia.date_followup,
            foia.communications.last().datetime.date() +
            timedelta(foia._followup_days()),
        )

        nose.tools.eq_(foia._followup_days(), 15)

        num_days = 365
        foia.date_estimate = date.today() + timedelta(num_days)
        foia.followup()
        self.run_commit_hooks()
        nose.tools.assert_in("I am still", mail.outbox[-1].body)
        nose.tools.eq_(foia._followup_days(), num_days)

        foia.date_estimate = date.today()
        foia.followup()
        self.run_commit_hooks()
        nose.tools.assert_in("check on the status", mail.outbox[-1].body)
        nose.tools.eq_(foia._followup_days(), 15)

    def test_foia_followup_estimated(self):
        """If request has an estimated date, returns number of days until the estimated date"""
        # pylint: disable=protected-access
        num_days = 365
        foia = FOIARequestFactory(date_estimate=date.today() +
                                  timedelta(num_days))
        nose.tools.eq_(foia._followup_days(), num_days)

    def test_manager_get_done(self):
        """Test the FOIA Manager's get_done method"""

        done_foias = FOIARequest.objects.get_done()
        for foia in FOIARequest.objects.all():
            if foia in done_foias:
                nose.tools.eq_(foia.status, "done")
            else:
                nose.tools.assert_in(
                    foia.status,
                    ["submitted", "processed", "fix", "rejected", "payment"],
                )

    def test_soft_delete(self):
        """Test the soft delete method"""
        foia = FOIARequestFactory(status="processed")
        FOIAFileFactory.create_batch(size=3, comm__foia=foia)
        user = UserFactory(is_superuser=True)

        nose.tools.eq_(foia.get_files().count(), 3)
        nose.tools.eq_(
            RawEmail.objects.filter(email__communication__foia=foia).count(),
            3)

        foia.soft_delete(user, "final message", "note")
        foia.refresh_from_db()
        self.run_commit_hooks()

        # final communication we send out is not cleared
        for comm in list(foia.communications.all())[:-1]:
            nose.tools.eq_(comm.communication, "")
        nose.tools.eq_(foia.get_files().count(), 0)
        # one raw email left on the final outgoing message
        nose.tools.eq_(
            RawEmail.objects.filter(email__communication__foia=foia).count(),
            1)
        nose.tools.eq_(foia.last_request().communication, "final message")
        nose.tools.eq_(foia.notes.first().note, "note")

        nose.tools.ok_(foia.deleted)
        nose.tools.ok_(foia.embargo)
        nose.tools.ok_(foia.permanent_embargo)
        nose.tools.eq_(foia.status, "abandoned")
Esempio n. 7
0
class TestRequestSharingViews(TestCase):
    """Tests access and implementation of view methods for sharing requests."""

    def setUp(self):
        self.factory = RequestFactory()
        self.foia = FOIARequestFactory()
        self.creator = self.foia.user
        self.editor = UserFactory()
        self.viewer = UserFactory()
        self.staff = UserFactory(is_staff=True)
        self.normie = UserFactory()
        self.foia.add_editor(self.editor)
        self.foia.add_viewer(self.viewer)
        self.foia.save()
        UserFactory(username='******')

    def reset_access_key(self):
        """Simple helper to reset access key betweeen tests"""
        self.foia.access_key = None
        assert_false(self.foia.access_key)

    def test_access_key_allowed(self):
        """
        A POST request for a private share link should generate and return an access key.
        Editors and staff should be allowed to do this.
        """
        self.reset_access_key()
        data = {'action': 'generate_key'}
        request = self.factory.post(self.foia.get_absolute_url(), data)
        request = mock_middleware(request)
        # editors should be able to generate the key
        request.user = self.editor
        response = Detail.as_view()(
            request,
            jurisdiction=self.foia.jurisdiction.slug,
            jidx=self.foia.jurisdiction.id,
            slug=self.foia.slug,
            idx=self.foia.id
        )
        self.foia.refresh_from_db()
        eq_(response.status_code, 302)
        assert_true(self.foia.access_key)
        # staff should be able to generate the key
        self.reset_access_key()
        request.user = self.staff
        response = Detail.as_view()(
            request,
            jurisdiction=self.foia.jurisdiction.slug,
            jidx=self.foia.jurisdiction.id,
            slug=self.foia.slug,
            idx=self.foia.id
        )
        self.foia.refresh_from_db()
        eq_(response.status_code, 302)
        assert_true(self.foia.access_key)

    def test_access_key_not_allowed(self):
        """Visitors and normies should not be allowed to generate an access key."""
        self.reset_access_key()
        data = {'action': 'generate_key'}
        request = self.factory.post(self.foia.get_absolute_url(), data)
        request = mock_middleware(request)
        # viewers should not be able to generate the key
        request.user = self.viewer
        response = Detail.as_view()(
            request,
            jurisdiction=self.foia.jurisdiction.slug,
            jidx=self.foia.jurisdiction.id,
            slug=self.foia.slug,
            idx=self.foia.id
        )
        self.foia.refresh_from_db()
        eq_(response.status_code, 302)
        assert_false(self.foia.access_key)
        # normies should not be able to generate the key
        self.reset_access_key()
        request.user = self.normie
        response = Detail.as_view()(
            request,
            jurisdiction=self.foia.jurisdiction.slug,
            jidx=self.foia.jurisdiction.id,
            slug=self.foia.slug,
            idx=self.foia.id
        )
        self.foia.refresh_from_db()
        eq_(response.status_code, 302)
        assert_false(self.foia.access_key)

    def test_grant_edit_access(self):
        """Editors should be able to add editors."""
        user1 = UserFactory()
        user2 = UserFactory()
        edit_data = {
            'action': 'grant_access',
            'users': [user1.pk, user2.pk],
            'access': 'edit'
        }
        edit_request = self.factory.post(
            self.foia.get_absolute_url(), edit_data
        )
        edit_request = mock_middleware(edit_request)
        edit_request.user = self.editor
        edit_response = Detail.as_view()(
            edit_request,
            jurisdiction=self.foia.jurisdiction.slug,
            jidx=self.foia.jurisdiction.id,
            slug=self.foia.slug,
            idx=self.foia.id
        )
        eq_(edit_response.status_code, 302)
        assert_true(self.foia.has_editor(user1) and self.foia.has_editor(user2))

    def test_grant_view_access(self):
        """Editors should be able to add viewers."""
        user1 = UserFactory()
        user2 = UserFactory()
        view_data = {
            'action': 'grant_access',
            'users': [user1.pk, user2.pk],
            'access': 'view'
        }
        view_request = self.factory.post(
            self.foia.get_absolute_url(), view_data
        )
        view_request = mock_middleware(view_request)
        view_request.user = self.editor
        view_response = Detail.as_view()(
            view_request,
            jurisdiction=self.foia.jurisdiction.slug,
            jidx=self.foia.jurisdiction.id,
            slug=self.foia.slug,
            idx=self.foia.id
        )
        eq_(view_response.status_code, 302)
        assert_true(self.foia.has_viewer(user1) and self.foia.has_viewer(user2))

    def test_demote_editor(self):
        """Editors should be able to demote editors to viewers."""
        user = UserFactory()
        self.foia.add_editor(user)
        assert_true(self.foia.has_editor(user))
        data = {'action': 'demote', 'user': user.pk}
        request = self.factory.post(self.foia.get_absolute_url(), data)
        request = mock_middleware(request)
        request.user = self.editor
        response = Detail.as_view()(
            request,
            jurisdiction=self.foia.jurisdiction.slug,
            jidx=self.foia.jurisdiction.id,
            slug=self.foia.slug,
            idx=self.foia.id
        )
        eq_(response.status_code, 302)
        assert_false(self.foia.has_editor(user))
        assert_true(self.foia.has_viewer(user))

    def test_promote_viewer(self):
        """Editors should be able to promote viewers to editors."""
        user = UserFactory()
        self.foia.add_viewer(user)
        assert_true(self.foia.has_viewer(user))
        data = {'action': 'promote', 'user': user.pk}
        request = self.factory.post(self.foia.get_absolute_url(), data)
        request = mock_middleware(request)
        request.user = self.editor
        response = Detail.as_view()(
            request,
            jurisdiction=self.foia.jurisdiction.slug,
            jidx=self.foia.jurisdiction.id,
            slug=self.foia.slug,
            idx=self.foia.id
        )
        eq_(response.status_code, 302)
        assert_false(self.foia.has_viewer(user))
        assert_true(self.foia.has_editor(user))

    def test_revoke_edit_access(self):
        """Editors should be able to revoke access from an editor."""
        an_editor = UserFactory()
        self.foia.add_editor(an_editor)
        data = {'action': 'revoke_access', 'user': an_editor.pk}
        request = self.factory.post(self.foia.get_absolute_url(), data)
        request = mock_middleware(request)
        request.user = self.editor
        response = Detail.as_view()(
            request,
            jurisdiction=self.foia.jurisdiction.slug,
            jidx=self.foia.jurisdiction.id,
            slug=self.foia.slug,
            idx=self.foia.id
        )
        eq_(response.status_code, 302)
        assert_false(self.foia.has_editor(an_editor))

    def test_revoke_view_access(self):
        """Editors should be able to revoke access from a viewer."""
        a_viewer = UserFactory()
        self.foia.add_viewer(a_viewer)
        data = {'action': 'revoke_access', 'user': a_viewer.pk}
        request = self.factory.post(self.foia.get_absolute_url(), data)
        request = mock_middleware(request)
        request.user = self.editor
        response = Detail.as_view()(
            request,
            jurisdiction=self.foia.jurisdiction.slug,
            jidx=self.foia.jurisdiction.id,
            slug=self.foia.slug,
            idx=self.foia.id
        )
        eq_(response.status_code, 302)
        assert_false(self.foia.has_viewer(a_viewer))
Esempio n. 8
0
class TestRequestDetailView(TestCase):
    """Request detail views support a wide variety of interactions"""

    def setUp(self):
        agency = AgencyFactory(appeal_agency=AppealAgencyFactory())
        self.foia = FOIARequestFactory(agency=agency)
        self.view = Detail.as_view()
        self.url = self.foia.get_absolute_url()
        self.kwargs = {
            'jurisdiction': self.foia.jurisdiction.slug,
            'jidx': self.foia.jurisdiction.id,
            'slug': self.foia.slug,
            'idx': self.foia.id
        }
        UserFactory(username='******')

    def test_add_tags(self):
        """Posting a collection of tags to a request should update its tags."""
        data = {'action': 'tags', 'tags': 'foo, bar'}
        http_post_response(
            self.url, self.view, data, self.foia.user, **self.kwargs
        )
        self.foia.refresh_from_db()
        ok_('foo' in [tag.name for tag in self.foia.tags.all()])
        ok_('bar' in [tag.name for tag in self.foia.tags.all()])

    def test_add_projects(self):
        """Posting a collection of projects to a request should add it to those projects."""
        project = ProjectFactory()
        project.contributors.add(self.foia.user)
        form = ProjectManagerForm(
            {
                'projects': [project.pk]
            },
            user=self.foia.user,
        )
        ok_(form.is_valid())
        data = {'action': 'projects'}
        data.update(form.data)
        http_post_response(
            self.url, self.view, data, self.foia.user, **self.kwargs
        )
        project.refresh_from_db()
        ok_(self.foia in project.requests.all())

    def test_appeal(self):
        """Appealing a request should send a new communication,
        record the details of the appeal, and update the status of the request."""
        comm_count = self.foia.communications.count()
        data = {'action': 'appeal', 'text': 'Lorem ipsum'}
        http_post_response(
            self.url, self.view, data, self.foia.user, **self.kwargs
        )
        self.foia.refresh_from_db()
        eq_(self.foia.status, 'appealing')
        eq_(self.foia.communications.count(), comm_count + 1)
        eq_(
            self.foia.communications.last().communication, data['text'],
            'The appeal should use the language provided by the user.'
        )
        appeal = Appeal.objects.last()
        ok_(appeal, 'An Appeal object should be created.')
        eq_(
            self.foia.communications.last(), appeal.communication,
            'The appeal should reference the communication that was created.'
        )

    def test_appeal_example(self):
        """If an example appeal is used to base the appeal off of,
        then the examples should be recorded to the appeal object as well."""
        example_appeal = ExampleAppealFactory()
        data = {
            'action': 'appeal',
            'text': 'Lorem ipsum',
            'base_language': example_appeal.pk
        }
        http_post_response(
            self.url, self.view, data, self.foia.user, **self.kwargs
        )
        self.foia.refresh_from_db()
        appeal = Appeal.objects.last()
        ok_(appeal.base_language, 'The appeal should record its base language.')
        ok_(appeal.base_language.count(), 1)

    def test_unauthorized_appeal(self):
        """Appealing a request without permission should not do anything."""
        unauth_user = UserFactory()
        comm_count = self.foia.communications.count()
        previous_status = self.foia.status
        data = {'action': 'appeal', 'text': 'Lorem ipsum'}
        http_post_response(
            self.url, self.view, data, unauth_user, **self.kwargs
        )
        self.foia.refresh_from_db()
        eq_(
            self.foia.status, previous_status,
            'The status of the request should not be changed.'
        )
        eq_(
            self.foia.communications.count(), comm_count,
            'No communication should be added to the request.'
        )

    def test_missing_appeal(self):
        """An appeal that is missing its language should not do anything."""
        comm_count = self.foia.communications.count()
        previous_status = self.foia.status
        data = {'action': 'appeal', 'text': ''}
        http_post_response(
            self.url, self.view, data, self.foia.user, **self.kwargs
        )
        self.foia.refresh_from_db()
        eq_(
            self.foia.status, previous_status,
            'The status of the request should not be changed.'
        )
        eq_(
            self.foia.communications.count(), comm_count,
            'No communication should be added to the request.'
        )

    def test_unappealable_request(self):
        """An appeal on a request that cannot be appealed should not do anything."""
        self.foia.status = 'submitted'
        self.foia.save()
        nose.tools.assert_false(self.foia.has_perm(self.foia.user, 'appeal'))
        comm_count = self.foia.communications.count()
        previous_status = self.foia.status
        data = {'action': 'appeal', 'text': 'Lorem ipsum'}
        http_post_response(
            self.url, self.view, data, self.foia.user, **self.kwargs
        )
        self.foia.refresh_from_db()
        eq_(
            self.foia.status, previous_status,
            'The status of the request should not be changed.'
        )
        eq_(
            self.foia.communications.count(), comm_count,
            'No communication should be added to the request.'
        )

    def test_post_status(self):
        """A user updating the status of their request should update the status,
        open a status change task, and close any open response tasks"""
        nose.tools.assert_not_equal(self.foia.status, 'done')
        eq_(
            len(
                StatusChangeTask.objects.filter(
                    foia=self.foia,
                    user=self.foia.user,
                    resolved=False,
                )
            ), 0
        )
        communication = FOIACommunicationFactory(foia=self.foia)
        response_task = ResponseTaskFactory(
            communication=communication,
            resolved=False,
        )
        data = {'action': 'status', 'status': 'done'}
        http_post_response(
            self.url, self.view, data, self.foia.user, **self.kwargs
        )
        self.foia.refresh_from_db()
        eq_(self.foia.status, 'done')
        eq_(
            len(
                StatusChangeTask.objects.filter(
                    foia=self.foia,
                    user=self.foia.user,
                    resolved=False,
                )
            ), 1
        )
        response_task.refresh_from_db()
        ok_(response_task.resolved)
Esempio n. 9
0
class TestFOIARequestUnit(TestCase):
    """Unit tests for FOIARequests"""

    def setUp(self):
        """Set up tests"""

        mail.outbox = []

        self.foia = FOIARequestFactory(status='submitted', title='Test 1')
        UserFactory(username='******')

    # models
    def test_foia_model_unicode(self):
        """Test FOIA Request model's __unicode__ method"""
        nose.tools.eq_(unicode(self.foia), 'Test 1')

    def test_foia_model_url(self):
        """Test FOIA Request model's get_absolute_url method"""

        nose.tools.eq_(
            self.foia.get_absolute_url(),
            reverse(
                'foia-detail',
                kwargs={
                    'idx': self.foia.pk,
                    'slug': 'test-1',
                    'jurisdiction': 'massachusetts',
                    'jidx': self.foia.jurisdiction.pk
                }
            )
        )

    def test_foia_viewable(self):
        """Test all the viewable and embargo functions"""

        user1 = UserFactory()
        user2 = UserFactory()

        foias = [
            FOIARequestFactory(
                composer__user=user1,
                status='done',
                embargo=False,
            ),
            FOIARequestFactory(
                composer__user=user1,
                status='done',
                embargo=True,
            ),
            FOIARequestFactory(
                composer__user=user1,
                status='done',
                embargo=True,
            ),
        ]
        foias[2].add_viewer(user2)

        # check manager get_viewable against view permission
        viewable_foias = FOIARequest.objects.get_viewable(user1)
        for foia in FOIARequest.objects.all():
            if foia in viewable_foias:
                nose.tools.assert_true(foia.has_perm(user1, 'view'))
            else:
                nose.tools.assert_false(foia.has_perm(user1, 'view'))

        viewable_foias = FOIARequest.objects.get_viewable(user2)
        for foia in FOIARequest.objects.all():
            if foia in viewable_foias:
                nose.tools.assert_true(foia.has_perm(user2, 'view'))
            else:
                nose.tools.assert_false(foia.has_perm(user2, 'view'))

        viewable_foias = FOIARequest.objects.get_public()
        for foia in FOIARequest.objects.all():
            if foia in viewable_foias:
                nose.tools.assert_true(foia.has_perm(AnonymousUser(), 'view'))
            else:
                nose.tools.assert_false(foia.has_perm(AnonymousUser(), 'view'))

        nose.tools.assert_true(foias[0].has_perm(user1, 'view'))
        nose.tools.assert_true(foias[1].has_perm(user1, 'view'))
        nose.tools.assert_true(foias[2].has_perm(user1, 'view'))

        nose.tools.assert_true(foias[0].has_perm(user2, 'view'))
        nose.tools.assert_false(foias[1].has_perm(user2, 'view'))
        nose.tools.assert_true(foias[2].has_perm(user2, 'view'))

        nose.tools.assert_true(foias[0].has_perm(AnonymousUser(), 'view'))
        nose.tools.assert_false(foias[1].has_perm(AnonymousUser(), 'view'))
        nose.tools.assert_false(foias[2].has_perm(AnonymousUser(), 'view'))

    def test_foia_viewable_org_share(self):
        """Test all the viewable and embargo functions"""
        org = OrganizationFactory()
        org.owner.profile.organization = org
        foia = FOIARequestFactory(
            embargo=True,
            composer__user__profile__organization=org,
        )
        foias = FOIARequest.objects.get_viewable(org.owner)
        nose.tools.assert_not_in(foia, foias)

        foia.user.profile.org_share = True
        foia.user.profile.save()
        foias = FOIARequest.objects.get_viewable(org.owner)
        nose.tools.assert_in(foia, foias)

    def test_foia_set_mail_id(self):
        """Test the set_mail_id function"""
        foia = FOIARequestFactory()
        foia.set_mail_id()
        mail_id = foia.mail_id
        nose.tools.ok_(re.match(r'\d{1,4}-\d{8}', mail_id))

        foia.set_mail_id()
        nose.tools.eq_(mail_id, foia.mail_id)

    def test_foia_followup(self):
        """Make sure the follow up date is set correctly"""
        # pylint: disable=protected-access
        foia = FOIARequestFactory(
            composer__datetime_submitted=timezone.now(),
            status='processed',
            agency__jurisdiction__level='s',
            agency__jurisdiction__law__days=10,
        )
        FOIACommunicationFactory(
            foia=foia,
            response=True,
        )
        foia.followup()
        nose.tools.assert_in('I can expect', mail.outbox[-1].body)
        nose.tools.eq_(
            foia.date_followup,
            date.today() + timedelta(foia._followup_days())
        )

        nose.tools.eq_(foia._followup_days(), 15)

        num_days = 365
        foia.date_estimate = date.today() + timedelta(num_days)
        foia.followup()
        nose.tools.assert_in('I am still', mail.outbox[-1].body)
        nose.tools.eq_(foia._followup_days(), num_days)

        foia.date_estimate = date.today()
        foia.followup()
        nose.tools.assert_in('check on the status', mail.outbox[-1].body)
        nose.tools.eq_(foia._followup_days(), 15)

    def test_foia_followup_estimated(self):
        """If request has an estimated date, returns number of days until the estimated date"""
        # pylint: disable=protected-access
        num_days = 365
        foia = FOIARequestFactory(
            date_estimate=date.today() + timedelta(num_days)
        )
        nose.tools.eq_(foia._followup_days(), num_days)

    def test_manager_get_done(self):
        """Test the FOIA Manager's get_done method"""

        done_foias = FOIARequest.objects.get_done()
        for foia in FOIARequest.objects.all():
            if foia in done_foias:
                nose.tools.eq_(foia.status, 'done')
            else:
                nose.tools.assert_in(
                    foia.status, [
                        'submitted',
                        'processed',
                        'fix',
                        'rejected',
                        'payment',
                    ]
                )
class TestFOIARequestUnit(TestCase):
    """Unit tests for FOIARequests"""
    def setUp(self):
        """Set up tests"""

        mail.outbox = []

        self.foia = FOIARequestFactory(status='submitted', title='Test 1')
        UserFactory(username='******')

    def run_commit_hooks(self):
        """
        Fake transaction commit to run delayed on_commit functions
        https://medium.com/gitux/speed-up-django-transaction-hooks-tests-6de4a558ef96
        """
        for db_name in reversed(self._databases_names()):
            with mock.patch(
                    'django.db.backends.base.base.BaseDatabaseWrapper.'
                    'validate_no_atomic_block', lambda a: False):
                transaction.get_connection(
                    using=db_name, ).run_and_clear_commit_hooks()

    # models
    def test_foia_model_unicode(self):
        """Test FOIA Request model's __unicode__ method"""
        nose.tools.eq_(unicode(self.foia), 'Test 1')

    def test_foia_model_url(self):
        """Test FOIA Request model's get_absolute_url method"""

        nose.tools.eq_(
            self.foia.get_absolute_url(),
            reverse('foia-detail',
                    kwargs={
                        'idx': self.foia.pk,
                        'slug': 'test-1',
                        'jurisdiction': 'massachusetts',
                        'jidx': self.foia.jurisdiction.pk
                    }))

    def test_foia_viewable(self):
        """Test all the viewable and embargo functions"""

        user1 = UserFactory()
        user2 = UserFactory()

        foias = [
            FOIARequestFactory(
                composer__user=user1,
                status='done',
                embargo=False,
            ),
            FOIARequestFactory(
                composer__user=user1,
                status='done',
                embargo=True,
            ),
            FOIARequestFactory(
                composer__user=user1,
                status='done',
                embargo=True,
            ),
        ]
        foias[2].add_viewer(user2)

        # check manager get_viewable against view permission
        viewable_foias = FOIARequest.objects.get_viewable(user1)
        for foia in FOIARequest.objects.all():
            if foia in viewable_foias:
                nose.tools.assert_true(foia.has_perm(user1, 'view'))
            else:
                nose.tools.assert_false(foia.has_perm(user1, 'view'))

        viewable_foias = FOIARequest.objects.get_viewable(user2)
        for foia in FOIARequest.objects.all():
            if foia in viewable_foias:
                nose.tools.assert_true(foia.has_perm(user2, 'view'))
            else:
                nose.tools.assert_false(foia.has_perm(user2, 'view'))

        viewable_foias = FOIARequest.objects.get_public()
        for foia in FOIARequest.objects.all():
            if foia in viewable_foias:
                nose.tools.assert_true(foia.has_perm(AnonymousUser(), 'view'))
            else:
                nose.tools.assert_false(foia.has_perm(AnonymousUser(), 'view'))

        nose.tools.assert_true(foias[0].has_perm(user1, 'view'))
        nose.tools.assert_true(foias[1].has_perm(user1, 'view'))
        nose.tools.assert_true(foias[2].has_perm(user1, 'view'))

        nose.tools.assert_true(foias[0].has_perm(user2, 'view'))
        nose.tools.assert_false(foias[1].has_perm(user2, 'view'))
        nose.tools.assert_true(foias[2].has_perm(user2, 'view'))

        nose.tools.assert_true(foias[0].has_perm(AnonymousUser(), 'view'))
        nose.tools.assert_false(foias[1].has_perm(AnonymousUser(), 'view'))
        nose.tools.assert_false(foias[2].has_perm(AnonymousUser(), 'view'))

    def test_foia_viewable_org_share(self):
        """Test all the viewable and embargo functions"""
        user = UserFactory()
        foia = FOIARequestFactory(
            embargo=True,
            composer__organization=user.profile.organization,
        )
        foias = FOIARequest.objects.get_viewable(user)
        nose.tools.assert_not_in(foia, foias)

        foia.user.profile.org_share = True
        foia.user.profile.save()
        foias = FOIARequest.objects.get_viewable(user)
        nose.tools.assert_in(foia, foias)

    def test_foia_set_mail_id(self):
        """Test the set_mail_id function"""
        foia = FOIARequestFactory()
        foia.set_mail_id()
        mail_id = foia.mail_id
        nose.tools.ok_(re.match(r'\d{1,4}-\d{8}', mail_id))

        foia.set_mail_id()
        nose.tools.eq_(mail_id, foia.mail_id)

    def test_foia_followup(self):
        """Make sure the follow up date is set correctly"""
        # pylint: disable=protected-access
        foia = FOIARequestFactory(
            composer__datetime_submitted=timezone.now(),
            status='processed',
            agency__jurisdiction__level='s',
            agency__jurisdiction__law__days=10,
        )
        FOIACommunicationFactory(
            foia=foia,
            response=True,
        )
        foia.followup()
        self.run_commit_hooks()
        nose.tools.assert_in('I can expect', mail.outbox[-1].body)
        nose.tools.eq_(
            foia.date_followup,
            foia.communications.last().datetime.date() +
            timedelta(foia._followup_days()))

        nose.tools.eq_(foia._followup_days(), 15)

        num_days = 365
        foia.date_estimate = date.today() + timedelta(num_days)
        foia.followup()
        self.run_commit_hooks()
        nose.tools.assert_in('I am still', mail.outbox[-1].body)
        nose.tools.eq_(foia._followup_days(), num_days)

        foia.date_estimate = date.today()
        foia.followup()
        self.run_commit_hooks()
        nose.tools.assert_in('check on the status', mail.outbox[-1].body)
        nose.tools.eq_(foia._followup_days(), 15)

    def test_foia_followup_estimated(self):
        """If request has an estimated date, returns number of days until the estimated date"""
        # pylint: disable=protected-access
        num_days = 365
        foia = FOIARequestFactory(date_estimate=date.today() +
                                  timedelta(num_days))
        nose.tools.eq_(foia._followup_days(), num_days)

    def test_manager_get_done(self):
        """Test the FOIA Manager's get_done method"""

        done_foias = FOIARequest.objects.get_done()
        for foia in FOIARequest.objects.all():
            if foia in done_foias:
                nose.tools.eq_(foia.status, 'done')
            else:
                nose.tools.assert_in(foia.status, [
                    'submitted',
                    'processed',
                    'fix',
                    'rejected',
                    'payment',
                ])

    def test_soft_delete(self):
        """Test the soft delete method"""
        foia = FOIARequestFactory(status='processed')
        FOIAFileFactory.create_batch(size=3, comm__foia=foia)
        user = UserFactory(is_superuser=True)

        nose.tools.eq_(foia.get_files().count(), 3)
        nose.tools.eq_(
            RawEmail.objects.filter(email__communication__foia=foia).count(),
            3)

        foia.soft_delete(user, 'final message', 'note')
        foia.refresh_from_db()
        self.run_commit_hooks()

        # final communication we send out is not cleared
        for comm in list(foia.communications.all())[:-1]:
            nose.tools.eq_(comm.communication, '')
        nose.tools.eq_(foia.get_files().count(), 0)
        # one raw email left on the final outgoing message
        nose.tools.eq_(
            RawEmail.objects.filter(email__communication__foia=foia).count(),
            1)
        nose.tools.eq_(foia.last_request().communication, 'final message')
        nose.tools.eq_(foia.notes.first().note, 'note')

        nose.tools.ok_(foia.deleted)
        nose.tools.ok_(foia.embargo)
        nose.tools.ok_(foia.permanent_embargo)
        nose.tools.eq_(foia.status, 'abandoned')
Esempio n. 11
0
class TestRequestDetailView(TestCase):
    """Request detail views support a wide variety of interactions"""
    def setUp(self):
        agency = AgencyFactory(appeal_agency=AppealAgencyFactory())
        self.foia = FOIARequestFactory(agency=agency)
        self.view = Detail.as_view()
        self.url = self.foia.get_absolute_url()
        self.kwargs = {
            "jurisdiction": self.foia.jurisdiction.slug,
            "jidx": self.foia.jurisdiction.id,
            "slug": self.foia.slug,
            "idx": self.foia.id,
        }
        UserFactory(username="******")

    def test_add_tags(self):
        """Posting a collection of tags to a request should update its tags."""
        data = {"action": "tags", "tags": ["foo", "bar"]}
        http_post_response(self.url, self.view, data, self.foia.user,
                           **self.kwargs)
        self.foia.refresh_from_db()
        ok_("foo" in [tag.name for tag in self.foia.tags.all()])
        ok_("bar" in [tag.name for tag in self.foia.tags.all()])

    def test_add_projects(self):
        """Posting a collection of projects to a request should add it to those projects."""
        project = ProjectFactory()
        project.contributors.add(self.foia.user)
        form = ProjectManagerForm({"projects": [project.pk]},
                                  user=self.foia.user)
        ok_(form.is_valid())
        data = {"action": "projects"}
        data.update(form.data)
        http_post_response(self.url, self.view, data, self.foia.user,
                           **self.kwargs)
        project.refresh_from_db()
        ok_(self.foia in project.requests.all())

    def test_appeal(self):
        """Appealing a request should send a new communication,
        record the details of the appeal, and update the status of the request."""
        comm_count = self.foia.communications.count()
        data = {"action": "appeal", "text": "Lorem ipsum"}
        http_post_response(self.url, self.view, data, self.foia.user,
                           **self.kwargs)
        self.foia.refresh_from_db()
        eq_(self.foia.status, "appealing")
        eq_(self.foia.communications.count(), comm_count + 1)
        eq_(
            self.foia.communications.last().communication,
            data["text"],
            "The appeal should use the language provided by the user.",
        )
        appeal = Appeal.objects.last()
        ok_(appeal, "An Appeal object should be created.")
        eq_(
            self.foia.communications.last(),
            appeal.communication,
            "The appeal should reference the communication that was created.",
        )

    def test_appeal_example(self):
        """If an example appeal is used to base the appeal off of,
        then the examples should be recorded to the appeal object as well."""
        example_appeal = ExampleAppealFactory()
        data = {
            "action": "appeal",
            "text": "Lorem ipsum",
            "base_language": example_appeal.pk,
        }
        http_post_response(self.url, self.view, data, self.foia.user,
                           **self.kwargs)
        self.foia.refresh_from_db()
        appeal = Appeal.objects.last()
        ok_(appeal.base_language,
            "The appeal should record its base language.")
        ok_(appeal.base_language.count(), 1)

    def test_unauthorized_appeal(self):
        """Appealing a request without permission should not do anything."""
        unauth_user = UserFactory()
        comm_count = self.foia.communications.count()
        previous_status = self.foia.status
        data = {"action": "appeal", "text": "Lorem ipsum"}
        http_post_response(self.url, self.view, data, unauth_user,
                           **self.kwargs)
        self.foia.refresh_from_db()
        eq_(
            self.foia.status,
            previous_status,
            "The status of the request should not be changed.",
        )
        eq_(
            self.foia.communications.count(),
            comm_count,
            "No communication should be added to the request.",
        )

    def test_missing_appeal(self):
        """An appeal that is missing its language should not do anything."""
        comm_count = self.foia.communications.count()
        previous_status = self.foia.status
        data = {"action": "appeal", "text": ""}
        http_post_response(self.url, self.view, data, self.foia.user,
                           **self.kwargs)
        self.foia.refresh_from_db()
        eq_(
            self.foia.status,
            previous_status,
            "The status of the request should not be changed.",
        )
        eq_(
            self.foia.communications.count(),
            comm_count,
            "No communication should be added to the request.",
        )

    def test_unappealable_request(self):
        """An appeal on a request that cannot be appealed should not do anything."""
        self.foia.status = "submitted"
        self.foia.save()
        nose.tools.assert_false(self.foia.has_perm(self.foia.user, "appeal"))
        comm_count = self.foia.communications.count()
        previous_status = self.foia.status
        data = {"action": "appeal", "text": "Lorem ipsum"}
        http_post_response(self.url, self.view, data, self.foia.user,
                           **self.kwargs)
        self.foia.refresh_from_db()
        eq_(
            self.foia.status,
            previous_status,
            "The status of the request should not be changed.",
        )
        eq_(
            self.foia.communications.count(),
            comm_count,
            "No communication should be added to the request.",
        )

    def test_post_status(self):
        """A user updating the status of their request should update the status,
        open a status change task, and close any open response tasks"""
        nose.tools.assert_not_equal(self.foia.status, "done")
        eq_(
            len(
                StatusChangeTask.objects.filter(foia=self.foia,
                                                user=self.foia.user,
                                                resolved=False)),
            0,
        )
        communication = FOIACommunicationFactory(foia=self.foia)
        response_task = ResponseTaskFactory(communication=communication,
                                            resolved=False)
        data = {"action": "status", "status": "done"}
        http_post_response(self.url, self.view, data, self.foia.user,
                           **self.kwargs)
        self.foia.refresh_from_db()
        eq_(self.foia.status, "done")
        eq_(
            len(
                StatusChangeTask.objects.filter(foia=self.foia,
                                                user=self.foia.user,
                                                resolved=False)),
            1,
        )
        response_task.refresh_from_db()
        ok_(response_task.resolved)