Newer
Older
from opentech.apply.activity.models import Activity, INTERNAL
from opentech.apply.determinations.tests.factories import DeterminationFactory
from opentech.apply.funds.tests.factories import (
ApplicationSubmissionFactory,
ApplicationRevisionFactory,
LabSubmissionFactory,
SealedRoundFactory,
from opentech.apply.review.tests.factories import ReviewFactory
from opentech.apply.stream_forms.testing.factories import flatten_for_form
from opentech.apply.users.tests.factories import (
ReviewerFactory,
StaffFactory,
SuperUserFactory,
UserFactory,
)
from opentech.apply.utils.testing import make_request
from opentech.apply.utils.testing.tests import BaseViewTestCase
from ..models import ApplicationRevision
def prepare_form_data(submission, **kwargs):
data = submission.raw_data
for field, value in kwargs.items():
# convert named fields into id
field_id = submission.field(field).id
data[field_id] = value
address_field = submission.named_blocks['address']
address = data.pop(address_field)
data.update(**prepare_address(address, address_field))
return data
def prepare_address(address, field):
address = json.loads(address)
address['locality'] = {
'localityname': address.pop('localityname'),
'administrativearea': address.pop('administrativearea'),
'postalcode': address.pop('postalcode'),
}
address = flatten_for_form(address, field, number=True)
return address
class BaseSubmissionViewTestCase(BaseViewTestCase):
url_name = 'funds:submissions:{}'
base_view_name = 'detail'
def get_kwargs(self, instance):
return {'pk': instance.id}
class TestStaffSubmissionView(BaseSubmissionViewTestCase):
user_factory = StaffFactory
@classmethod
def setUpTestData(cls):
cls.submission = ApplicationSubmissionFactory()
def __setUp__(self):
self.refresh(self.submission)
def test_can_view_a_submission(self):
response = self.get_page(self.submission)
self.assertContains(response, self.submission.title)
def test_can_view_a_lab_submission(self):
submission = LabSubmissionFactory()
response = self.get_page(submission)
self.assertContains(response, submission.title)
def test_can_progress_phase(self):
Fredrik Jonsson
committed
next_status = 'internal_review'
self.post_page(self.submission, {'form-submitted-progress_form': '', 'action': next_status})
submission = self.refresh(self.submission)
self.assertEqual(submission.status, next_status)
def test_redirected_to_determination(self):
submission = ApplicationSubmissionFactory(status='concept_review_discussion', workflow_stages=2, lead=self.user)
response = self.post_page(submission, {'form-submitted-progress_form': '', 'action': 'invited_to_proposal'})
# Invited for proposal is a a determination, so this will redirect to the determination form.
url = self.url_from_pattern('funds:submissions:determinations:form', kwargs={'submission_pk': submission.id})
self.assertRedirects(response, f"{url}?action=invited_to_proposal")
def test_new_form_after_progress(self):
submission = ApplicationSubmissionFactory(status='invited_to_proposal', workflow_stages=2, lead=self.user)
stage = submission.stage
DeterminationFactory(submission=submission, accepted=True)
request = make_request(self.user, method='get', site=submission.page.get_site())
submission.progress_stage_when_possible(self.user, request)
submission = self.refresh(submission)
new_stage = submission.stage
self.assertNotEqual(stage, new_stage)
get_forms = submission.get_from_parent('get_defined_fields')
self.assertEqual(submission.form_fields, get_forms(new_stage))
self.assertNotEqual(submission.form_fields, get_forms(stage))
def test_cant_progress_stage_if_not_lead(self):
submission = ApplicationSubmissionFactory(status='concept_review_discussion', workflow_stages=2)
self.post_page(submission, {'form-submitted-progress_form': '', 'action': 'invited_to_proposal'})
submission = self.refresh(submission)
self.assertEqual(submission.status, 'concept_review_discussion')
self.assertIsNone(submission.next)
def test_not_redirected_if_determination_submitted(self):
submission = ApplicationSubmissionFactory(lead=self.user)
DeterminationFactory(submission=submission, rejected=True, submitted=True)
self.post_page(submission, {'form-submitted-progress_form': '', 'action': 'rejected'})
submission = self.refresh(submission)
self.assertEqual(submission.status, 'rejected')
def test_not_redirected_if_wrong_determination_selected(self):
submission = ApplicationSubmissionFactory(lead=self.user)
DeterminationFactory(submission=submission, accepted=True, submitted=True)
response = self.post_page(submission, {'form-submitted-progress_form': '', 'action': 'rejected'})
self.assertContains(response, 'you tried to progress')
submission = self.refresh(submission)
self.assertNotEqual(submission.status, 'accepted')
self.assertNotEqual(submission.status, 'rejected')
def test_cant_access_edit_button_when_applicant_editing(self):
submission = ApplicationSubmissionFactory(status='more_info')
response = self.get_page(submission)
self.assertNotContains(response, self.url(submission, 'edit', absolute=False))
def test_can_access_edit_button(self):
response = self.get_page(self.submission)
self.assertContains(response, self.url(self.submission, 'edit', absolute=False))
def test_can_access_edit(self):
response = self.get_page(self.submission, 'edit')
self.assertContains(response, self.submission.title)
def test_previous_and_next_appears_on_page(self):
proposal = InvitedToProposalFactory()
response = self.get_page(proposal)
self.assertContains(response, self.url(proposal.previous, absolute=False))
response = self.get_page(proposal.previous)
self.assertContains(response, self.url(proposal, absolute=False))
def test_can_edit_submission(self):
old_status = self.submission.status
data = prepare_form_data(self.submission, title=new_title)
response = self.post_page(self.submission, {'submit': True, **data}, 'edit')
url = self.url(self.submission)
self.assertRedirects(response, url)
submission = self.refresh(self.submission)
# Staff edits don't affect the status
self.assertEqual(old_status, submission.status)
self.assertEqual(new_title, submission.title)
def test_not_included_fields_render(self):
submission = ApplicationSubmissionFactory(form_fields__exclude__value=True)
response = self.get_page(submission)
self.assertNotContains(response, 'Value')
def test_can_screen_submission(self):
screening_outcome = ScreeningStatusFactory()
self.post_page(self.submission, {'form-submitted-screening_form': '', 'screening_status': screening_outcome.id})
submission = self.refresh(self.submission)
self.assertEqual(submission.screening_status, screening_outcome)
def test_can_view_submission_screening_block(self):
response = self.get_page(self.submission)
self.assertContains(response, 'Screening Status')
class TestReviewersUpdateView(BaseSubmissionViewTestCase):
user_factory = StaffFactory
@classmethod
def setUpTestData(cls):
super().setUpTestData()
cls.staff = StaffFactory.create_batch(4)
cls.reviewers = ReviewerFactory.create_batch(4)
cls.roles = ReviewerRoleFactory.create_batch(2)
def post_form(self, submission, reviewer_roles=list(), reviewers=list()):
data = {
'form-submitted-reviewer_form': '',
'reviewer_reviewers': [r.id for r in reviewers]
}
data.update(
**{
f'reviewer_role_{str(role)}': reviewer.id
for role, reviewer in zip(self.roles, reviewer_roles)
}
)
return self.post_page(submission, data)
def test_lead_can_add_staff_single(self):
submission = ApplicationSubmissionFactory(lead=self.user)
self.post_form(submission, [self.staff[0]])
self.assertCountEqual(submission.reviewers.all(), [self.staff[0]])
def test_lead_can_change_staff_single(self):
submission = ApplicationSubmissionFactory(lead=self.user)
AssignedWithRoleReviewersFactory(role=self.roles[0], submission=submission, reviewer=self.staff[0])
self.assertCountEqual(submission.reviewers.all(), [self.staff[0]])
self.post_form(submission, [self.staff[1]])
self.assertCountEqual(submission.reviewers.all(), [self.staff[1]])
def test_lead_cant_add_reviewers_single(self):
submission = ApplicationSubmissionFactory(lead=self.user)
self.post_form(submission, reviewers=self.reviewers)
self.assertCountEqual(submission.reviewers.all(), [])
def test_lead_can_add_reviewers_for_proposal(self):
submission = InvitedToProposalFactory(lead=self.user)
self.post_form(submission, reviewers=self.reviewers)
self.assertCountEqual(submission.reviewers.all(), self.reviewers)
def test_lead_can_remove_reviewers_for_proposal(self):
submission = InvitedToProposalFactory(lead=self.user, reviewers=self.reviewers)
self.assertCountEqual(submission.reviewers.all(), self.reviewers)
self.post_form(submission)
self.assertCountEqual(submission.reviewers.all(), [])
def test_lead_can_remove_some_reviewers_for_proposal(self):
submission = InvitedToProposalFactory(lead=self.user, reviewers=self.reviewers)
self.assertCountEqual(submission.reviewers.all(), self.reviewers)
self.post_form(submission, reviewers=self.reviewers[0:2])
self.assertCountEqual(submission.reviewers.all(), self.reviewers[0:2])
def test_staff_cant_add_reviewers_proposal(self):
submission = ApplicationSubmissionFactory()
self.post_form(submission, reviewers=self.reviewers)
self.assertCountEqual(submission.reviewers.all(), [])
def test_staff_cant_remove_reviewers_proposal(self):
submission = ApplicationSubmissionFactory(reviewers=self.reviewers)
self.assertCountEqual(submission.reviewers.all(), self.reviewers)
self.post_form(submission, reviewers=[])
self.assertCountEqual(submission.reviewers.all(), self.reviewers)
def test_lead_can_change_role_reviewer_and_review_remains(self):
submission = ApplicationSubmissionFactory(lead=self.user)
self.post_form(submission, reviewer_roles=[self.staff[0]])
self.assertCountEqual(submission.reviewers.all(), [self.staff[0]])
# Add a review from that staff reviewer
review = ReviewFactory(submission=submission, author=self.staff[0])
# Assign a different reviewer to the same role
self.post_form(submission, reviewer_roles=[self.staff[1]])
# TODO: need to test that submission.assigned still contains self.staff[0]
# self.assertIn(self.staff[0], submission.reviewers.all())
class TestApplicantSubmissionView(BaseSubmissionViewTestCase):
user_factory = UserFactory
@classmethod
def setUpTestData(cls):
super().setUpTestData()
cls.submission = ApplicationSubmissionFactory(user=cls.user)
cls.draft_proposal_submission = InvitedToProposalFactory(user=cls.user, draft=True)
def __setUp__(self):
self.refresh(self.submission)
self.refresh(self.draft_proposal_submission)
def test_can_view_own_submission(self):
response = self.get_page(self.submission)
self.assertContains(response, self.submission.title)
def test_sees_latest_draft_if_it_exists(self):
draft_revision = ApplicationRevisionFactory(submission=self.submission)
self.submission.draft_revision = draft_revision
self.submission.save()
draft_submission = self.submission.from_draft()
response = self.get_page(self.submission)
self.assertContains(response, draft_submission.title)
def test_cant_view_others_submission(self):
submission = ApplicationSubmissionFactory()
response = self.get_page(submission)
self.assertEqual(response.status_code, 403)
def test_get_edit_link_when_editable(self):
submission = ApplicationSubmissionFactory(user=self.user, status='more_info')
response = self.get_page(submission)
self.assertContains(response, 'Edit')
self.assertContains(response, self.url(submission, 'edit', absolute=False))
self.assertNotContains(response, 'Congratulations')
def test_get_congratulations_draft_proposal(self):
response = self.get_page(self.draft_proposal_submission)
self.assertContains(response, 'Congratulations')
response = self.get_page(self.draft_proposal_submission, 'edit')
self.assertContains(response, self.draft_proposal_submission.title)
def test_can_submit_submission(self):
old_status = self.draft_proposal_submission.status
data = prepare_form_data(self.draft_proposal_submission, title='This is different')
response = self.post_page(self.draft_proposal_submission, {'submit': True, **data}, 'edit')
url = self.url_from_pattern('funds:submissions:detail', kwargs={'pk': self.draft_proposal_submission.id})
self.assertRedirects(response, url)
submission = self.refresh(self.draft_proposal_submission)
self.assertNotEqual(old_status, submission.status)
def test_gets_draft_on_edit_submission(self):
draft_revision = ApplicationRevisionFactory(submission=self.draft_proposal_submission)
self.draft_proposal_submission.draft_revision = draft_revision
self.draft_proposal_submission.save()
response = self.get_page(self.draft_proposal_submission, 'edit')
self.assertDictEqual(response.context['object'].form_data, draft_revision.form_data)
def test_cant_edit_submission_incorrect_state(self):
submission = InvitedToProposalFactory(user=self.user)
response = self.get_page(submission, 'edit')
self.assertEqual(response.status_code, 403)
def test_cant_edit_other_submission(self):
submission = InvitedToProposalFactory(draft=True)
response = self.get_page(submission, 'edit')
self.assertEqual(response.status_code, 403)
def test_cant_screen_submission(self):
"""
Test that an applicant cannot set the screening status
and that they don't see the screening status form.
"""
screening_outcome = ScreeningStatusFactory()
response = self.post_page(self.submission, {'form-submitted-screening_form': '', 'screening_status': screening_outcome.id})
self.assertNotIn('screening_form', response.context_data)
submission = self.refresh(self.submission)
self.assertNotEqual(submission.screening_status, screening_outcome)
def test_cant_see_screening_status_block(self):
response = self.get_page(self.submission)
self.assertNotContains(response, 'Screening Status')
class TestRevisionsView(BaseSubmissionViewTestCase):
user_factory = UserFactory
def test_create_revisions_on_submit(self):
submission = ApplicationSubmissionFactory(status='draft_proposal', workflow_stages=2, user=self.user)
old_data = submission.form_data.copy()
new_title = 'New title'
new_data = prepare_form_data(submission, title=new_title)
self.post_page(submission, {'submit': True, **new_data}, 'edit')
submission = self.refresh(submission)
self.assertEqual(submission.status, 'proposal_discussion')
self.assertEqual(submission.revisions.count(), 2)
self.assertDictEqual(submission.revisions.last().form_data, old_data)
self.assertDictEqual(submission.live_revision.form_data, submission.form_data)
self.assertEqual(submission.live_revision.author, self.user)
self.assertEqual(submission.title, new_title)
def test_dont_update_live_revision_on_save(self):
submission = ApplicationSubmissionFactory(status='draft_proposal', workflow_stages=2, user=self.user)
old_data = submission.form_data.copy()
new_data = prepare_form_data(submission, title='New title')
self.post_page(submission, {'save': True, **new_data}, 'edit')
submission = self.refresh(submission)
self.assertEqual(submission.status, 'draft_proposal')
self.assertEqual(submission.revisions.count(), 2)
self.assertDictEqual(submission.draft_revision.form_data, submission.from_draft().form_data)
self.assertEqual(submission.draft_revision.author, self.user)
self.assertDictEqual(submission.live_revision.form_data, old_data)
def test_existing_draft_edit_and_submit(self):
submission = ApplicationSubmissionFactory(status='draft_proposal', workflow_stages=2, user=self.user)
draft_data = prepare_form_data(submission, title='A new title')
self.post_page(submission, {'save': True, **draft_data}, 'edit')
submission = self.refresh(submission)
newer_title = 'Newer title'
draft_data = prepare_form_data(submission, title=newer_title)
self.post_page(submission, {'submit': True, **draft_data}, 'edit')
submission = self.refresh(submission)
self.maxDiff = None
self.assertEqual(submission.revisions.count(), 2)
self.assertDictEqual(submission.draft_revision.form_data, submission.from_draft().form_data)
self.assertDictEqual(submission.live_revision.form_data, submission.form_data)
self.assertEqual(submission.title, newer_title)
class TestRevisionCompare(BaseSubmissionViewTestCase):
base_view_name = 'revisions:compare'
user_factory = StaffFactory
def get_kwargs(self, instance):
return {
'submission_pk': instance.pk,
'to': instance.live_revision.id,
'from': instance.revisions.last().id,
}
def test_renders_with_all_the_diffs(self):
submission = ApplicationSubmissionFactory()
new_data = ApplicationSubmissionFactory(round=submission.round, form_fields=submission.form_fields).form_data
submission.form_data = new_data
submission.create_revision()
response = self.get_page(submission)
self.assertEqual(response.status_code, 200)
class TestRevisionList(BaseSubmissionViewTestCase):
base_view_name = 'revisions:list'
user_factory = StaffFactory
def get_kwargs(self, instance):
return {'submission_pk': instance.pk}
def test_list_doesnt_include_draft(self):
submission = ApplicationSubmissionFactory()
draft_revision = ApplicationRevisionFactory(submission=submission)
submission.draft_revision = draft_revision
submission.save()
response = self.get_page(submission)
self.assertNotIn(draft_revision, response.context['object_list'])
def test_get_in_correct_order(self):
submission = ApplicationSubmissionFactory()
revision = ApplicationRevisionFactory(submission=submission)
ApplicationRevision.objects.filter(id=revision.id).update(timestamp=datetime.now() - timedelta(days=1))
revision_older = ApplicationRevisionFactory(submission=submission)
ApplicationRevision.objects.filter(id=revision_older.id).update(timestamp=datetime.now() - timedelta(days=2))
response = self.get_page(submission)
self.assertSequenceEqual(
response.context['object_list'],
[submission.live_revision, revision, revision_older],
)
class TestStaffSealedView(BaseSubmissionViewTestCase):
user_factory = StaffFactory
def test_redirected_to_sealed(self):
submission = SealedSubmissionFactory()
response = self.get_page(submission)
url = self.url_from_pattern('funds:submissions:sealed', kwargs={'pk': submission.id})
self.assertRedirects(response, url)
def test_cant_post_to_sealed(self):
submission = SealedSubmissionFactory()
response = self.post_page(submission, {'some': 'data'}, 'sealed')
# Because of the redirect chain the url returned is not absolute
url = self.url_from_pattern('funds:submissions:sealed', kwargs={'pk': submission.id}, absolute=False)
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
self.assertRedirects(response, url)
def test_non_sealed_unaffected(self):
submission = ApplicationSubmissionFactory()
response = self.get_page(submission)
self.assertEqual(response.status_code, 200)
def test_non_sealed_redirected_away(self):
submission = ApplicationSubmissionFactory()
response = self.get_page(submission, 'sealed')
url = self.url_from_pattern('funds:submissions:detail', kwargs={'pk': submission.id})
self.assertRedirects(response, url)
class TestSuperUserSealedView(BaseSubmissionViewTestCase):
user_factory = SuperUserFactory
def test_redirected_to_sealed(self):
submission = SealedSubmissionFactory()
response = self.get_page(submission)
url = self.url_from_pattern('funds:submissions:sealed', kwargs={'pk': submission.id})
self.assertRedirects(response, url)
def test_can_post_to_sealed(self):
submission = SealedSubmissionFactory()
response = self.post_page(submission, {}, 'sealed')
url = self.url_from_pattern('funds:submissions:detail', kwargs={'pk': submission.id})
self.assertRedirects(response, url)
def test_peeking_is_logged(self):
submission = SealedSubmissionFactory()
self.post_page(submission, {}, 'sealed')
self.assertTrue('peeked' in self.client.session)
self.assertTrue(str(submission.id) in self.client.session['peeked'])
self.assertEqual(Activity.objects.count(), 1)
self.assertTrue('sealed' in Activity.objects.first().message)
def test_not_asked_again(self):
submission = SealedSubmissionFactory()
self.post_page(submission, {}, 'sealed')
# Now request the page again
response = self.get_page(submission)
self.assertEqual(response.status_code, 200)
def test_can_view_multiple_sealed(self):
sealed_round = SealedRoundFactory()
first, second = SealedSubmissionFactory.create_batch(2, round=sealed_round)
self.post_page(first, {}, 'sealed')
self.post_page(second, {}, 'sealed')
self.assertTrue('peeked' in self.client.session)
self.assertTrue(str(first.id) in self.client.session['peeked'])
self.assertTrue(str(second.id) in self.client.session['peeked'])
class TestSuperUserSubmissionView(BaseSubmissionViewTestCase):
user_factory = SuperUserFactory
@classmethod
def setUpTestData(cls):
cls.submission = ApplicationSubmissionFactory()
super().setUpTestData()
def __setUp__(self):
self.refresh(self.submission)
def test_can_screen_submission(self):
screening_outcome = ScreeningStatusFactory()
self.post_page(self.submission, {'form-submitted-screening_form': '', 'screening_status': screening_outcome.id})
submission = self.refresh(self.submission)
self.assertEqual(submission.screening_status, screening_outcome)
def test_can_screen_applications_in_final_status(self):
"""
Now that the submission has been rejected (final determination),
we can still screen it because we are super user
"""
submission = ApplicationSubmissionFactory(rejected=True)
screening_outcome = ScreeningStatusFactory()
response = self.post_page(submission, {'form-submitted-screening_form': '', 'screening_status': screening_outcome.id})
submission = self.refresh(submission)
self.assertEqual(response.context_data['screening_form'].should_show, True)
self.assertEqual(submission.screening_status, screening_outcome)
# Check that an activity was created that should only be viewable internally
activity = Activity.objects.filter(message__contains='Screening status').first()
self.assertEqual(activity.visibility, INTERNAL)