Newer
Older
from opentech.apply.activity.models import Activity
from opentech.apply.funds.tests.factories import (
ApplicationSubmissionFactory,
ApplicationRevisionFactory,
LabSubmissionFactory,
SealedRoundFactory,
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.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.must_include['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):
next_status = list(self.submission.get_actions_for_user(self.user))[0][0]
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_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_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)
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
class TestReviewersUpdateView(BaseSubmissionViewTestCase):
user_factory = StaffFactory
def post_form(self, submission, staff=list(), reviewers=list()):
return self.post_page(submission, {
'form-submitted-reviewer_form': '',
'staff_reviewers': [s.id for s in staff],
'reviewer_reviewers': [r.id for r in reviewers]
})
def test_lead_can_add_staff_single(self):
submission = ApplicationSubmissionFactory(lead=self.user)
staff = StaffFactory.create_batch(4)
self.post_form(submission, staff)
self.assertCountEqual(submission.reviewers.all(), staff)
def test_lead_can_remove_staff_single(self):
staff = StaffFactory.create_batch(4)
submission = ApplicationSubmissionFactory(lead=self.user, reviewers=staff)
self.assertCountEqual(submission.reviewers.all(), staff)
self.post_form(submission, [])
self.assertCountEqual(submission.reviewers.all(), [])
def test_lead_can_remove_some_staff(self):
staff = StaffFactory.create_batch(4)
submission = ApplicationSubmissionFactory(lead=self.user, reviewers=staff)
self.assertCountEqual(submission.reviewers.all(), staff)
self.post_form(submission, staff[0:2])
self.assertCountEqual(submission.reviewers.all(), staff[0:2])
def test_lead_cant_add_reviewers_single(self):
submission = ApplicationSubmissionFactory(lead=self.user)
reviewers = ReviewerFactory.create_batch(4)
self.post_form(submission, reviewers=reviewers)
self.assertCountEqual(submission.reviewers.all(), [])
def test_lead_can_add_staff_and_reviewers_for_proposal(self):
submission = InvitedToProposalFactory(lead=self.user)
staff = StaffFactory.create_batch(4)
reviewers = ReviewerFactory.create_batch(4)
self.post_form(submission, staff, reviewers)
self.assertCountEqual(submission.reviewers.all(), staff + reviewers)
def test_lead_can_remove_staff_and_reviewers_for_proposal(self):
staff = StaffFactory.create_batch(4)
reviewers = ReviewerFactory.create_batch(4)
submission = InvitedToProposalFactory(lead=self.user, reviewers=staff + reviewers)
self.assertCountEqual(submission.reviewers.all(), staff + reviewers)
self.post_form(submission)
self.assertCountEqual(submission.reviewers.all(), [])
def test_lead_can_remove_some_staff_and_reviewers_for_proposal(self):
staff = StaffFactory.create_batch(4)
reviewers = ReviewerFactory.create_batch(4)
submission = InvitedToProposalFactory(lead=self.user, reviewers=staff + reviewers)
self.assertCountEqual(submission.reviewers.all(), staff + reviewers)
self.post_form(submission, staff[0:2], reviewers[0:2])
self.assertCountEqual(submission.reviewers.all(), staff[0:2] + reviewers[0:2])
def test_staff_can_add_staff_single(self):
submission = ApplicationSubmissionFactory()
staff = StaffFactory.create_batch(4)
self.post_form(submission, staff)
self.assertCountEqual(submission.reviewers.all(), staff)
def test_staff_can_remove_staff_single(self):
staff = StaffFactory.create_batch(4)
submission = ApplicationSubmissionFactory(reviewers=staff)
self.assertCountEqual(submission.reviewers.all(), staff)
self.post_form(submission, [])
self.assertCountEqual(submission.reviewers.all(), [])
def test_staff_cant_add_reviewers_proposal(self):
submission = ApplicationSubmissionFactory()
reviewers = ReviewerFactory.create_batch(4)
self.post_form(submission, reviewers=reviewers)
self.assertCountEqual(submission.reviewers.all(), [])
def test_staff_cant_remove_reviewers_proposal(self):
reviewers = ReviewerFactory.create_batch(4)
submission = ApplicationSubmissionFactory(reviewers=reviewers)
self.assertCountEqual(submission.reviewers.all(), reviewers)
self.post_form(submission, reviewers=[])
self.assertCountEqual(submission.reviewers.all(), reviewers)
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)
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)
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
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'])