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())
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())
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.')
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)
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.')
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")
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))
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)
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')
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)