import urllib from django.contrib.messages.storage.fallback import FallbackStorage from django.contrib.sessions.middleware import SessionMiddleware from django.test import RequestFactory from django.urls import reverse_lazy from opentech.apply.activity.models import Activity from opentech.apply.determinations.models import ACCEPTED, REJECTED from opentech.apply.determinations.views import BatchDeterminationCreateView from opentech.apply.users.tests.factories import StaffFactory, UserFactory from opentech.apply.funds.models import ApplicationSubmission from opentech.apply.funds.tests.factories import ApplicationSubmissionFactory from opentech.apply.utils.testing import BaseViewTestCase from .factories import DeterminationFactory class StaffDeterminationsTestCase(BaseViewTestCase): user_factory = StaffFactory url_name = 'funds:submissions:determinations:{}' base_view_name = 'detail' def get_kwargs(self, instance): return {'submission_pk': instance.submission.id, 'pk': instance.pk} def test_can_access_determination(self): submission = ApplicationSubmissionFactory(status='in_discussion') determination = DeterminationFactory(submission=submission, author=self.user, submitted=True) response = self.get_page(determination) self.assertContains(response, determination.submission.title) self.assertContains(response, self.user.full_name) self.assertContains(response, submission.get_absolute_url()) def test_lead_can_access_determination(self): submission = ApplicationSubmissionFactory(status='in_discussion', lead=self.user) determination = DeterminationFactory(submission=submission, author=self.user, submitted=True) response = self.get_page(determination) self.assertContains(response, determination.submission.title) self.assertContains(response, self.user.full_name) self.assertContains(response, submission.get_absolute_url()) class DeterminationFormTestCase(BaseViewTestCase): user_factory = StaffFactory url_name = 'funds:submissions:determinations:{}' base_view_name = 'detail' def get_kwargs(self, instance): return {'submission_pk': instance.id, 'pk': instance.determinations.first().id} def get_form_kwargs(self, instance): return {'submission_pk': instance.id} def test_can_access_form_if_lead(self): submission = ApplicationSubmissionFactory(status='in_discussion', lead=self.user) response = self.get_page(submission, 'form') self.assertContains(response, submission.title) self.assertContains(response, submission.get_absolute_url()) def test_cant_access_wrong_status(self): submission = ApplicationSubmissionFactory(status='rejected') response = self.get_page(submission, 'form') self.assertRedirects(response, self.absolute_url(submission.get_absolute_url())) def test_cant_resubmit_determination(self): submission = ApplicationSubmissionFactory(status='in_discussion', lead=self.user) determination = DeterminationFactory(submission=submission, author=self.user, accepted=True, submitted=True) response = self.post_page(submission, {'data': 'value', 'outcome': determination.outcome}, 'form') self.assertRedirects(response, self.absolute_url(submission.get_absolute_url())) def test_can_edit_draft_determination(self): submission = ApplicationSubmissionFactory(status='post_review_discussion', lead=self.user) response = self.post_page(submission, { 'data': 'value', 'outcome': ACCEPTED, 'message': 'Accepted determination draft message', 'save_draft': True, }, 'form') self.assertContains(response, '[Draft] Approved') self.assertContains(response, self.url(submission, 'form', absolute=False)) self.assertNotContains(response, 'Accepted determination draft message') def test_cant_edit_submitted_more_info(self): submission = ApplicationSubmissionFactory(status='in_discussion', lead=self.user) DeterminationFactory(submission=submission, author=self.user, submitted=True) response = self.get_page(submission, 'form') self.assertNotContains(response, 'Update ') def test_can_edit_draft_determination_if_not_lead(self): submission = ApplicationSubmissionFactory(status='in_discussion') determination = DeterminationFactory(submission=submission, author=self.user, accepted=True) response = self.post_page(submission, {'data': 'value', 'outcome': determination.outcome}, 'form') self.assertContains(response, 'Approved') self.assertRedirects(response, self.absolute_url(submission.get_absolute_url())) def test_sends_message_if_requires_more_info(self): submission = ApplicationSubmissionFactory(status='in_discussion', lead=self.user) determination = DeterminationFactory(submission=submission, author=self.user) determination_message = 'This is the message' self.post_page( submission, {'data': 'value', 'outcome': determination.outcome, 'message': determination_message}, 'form', ) self.assertEqual(Activity.comments.count(), 1) self.assertEqual(Activity.comments.first().message, determination_message) def test_can_progress_stage_via_determination(self): submission = ApplicationSubmissionFactory(status='concept_review_discussion', workflow_stages=2, lead=self.user) response = self.post_page(submission, { 'data': 'value', 'outcome': ACCEPTED, 'message': 'You are invited to submit a proposal', }, 'form') # Cant use refresh from DB with FSM submission_original = self.refresh(submission) submission_next = submission_original.next # Cannot use self.url() as that uses a different base. url = submission_next.get_absolute_url() self.assertRedirects(response, self.factory.get(url, secure=True).build_absolute_uri(url)) self.assertEqual(submission_original.status, 'invited_to_proposal') self.assertEqual(submission_next.status, 'draft_proposal') class BatchDeterminationTestCase(BaseViewTestCase): user_factory = StaffFactory url_name = 'funds:submissions:determinations:{}' base_view_name = 'batch' def dummy_request(self, path): request = RequestFactory().get(path) middleware = SessionMiddleware() middleware.process_request(request) request.session.save() request.user = StaffFactory() request._messages = FallbackStorage(request) return request def test_cant_access_without_submissions(self): url = self.url(None) + '?action=rejected' response = self.client.get(url, follow=True, secure=True) self.assertRedirects(response, self.url_from_pattern('apply:submissions:list')) self.assertEqual(len(response.context['messages']), 1) def test_cant_access_without_action(self): submission = ApplicationSubmissionFactory() url = self.url(None) + '?submissions=' + str(submission.id) response = self.client.get(url, follow=True, secure=True) self.assertRedirects(response, self.url_from_pattern('apply:submissions:list')) self.assertEqual(len(response.context['messages']), 1) def test_can_submit_batch_determination(self): submissions = ApplicationSubmissionFactory.create_batch(4) url = self.url(None) + '?submissions=' + ','.join([str(submission.id) for submission in submissions]) + '&action=rejected' data = { 'submissions': [submission.id for submission in submissions], 'data': 'some data', 'outcome': REJECTED, 'message': 'Sorry', 'author': self.user.id, } response = self.client.post(url, data, secure=True, follow=True) for submission in submissions: submission = self.refresh(submission) self.assertEqual(submission.status, 'rejected') self.assertEqual(submission.determinations.count(), 1) self.assertRedirects(response, self.url_from_pattern('apply:submissions:list')) def test_sets_next_on_redirect(self): test_path = '/a/path/?with=query&a=sting' request = RequestFactory().get('', PATH_INFO=test_path) redirect = BatchDeterminationCreateView.should_redirect( request, ApplicationSubmission.objects.none(), ['rejected'], ) url = urllib.parse.urlparse(redirect.url) query = urllib.parse.parse_qs(url.query) next_path = urllib.parse.unquote_plus(query['next'][0]) self.assertEqual(next_path, test_path) def test_success_redirects_if_exists(self): test_path = '/a/path/?with=query&a=sting' view = BatchDeterminationCreateView() view.request = self.dummy_request('?next=' + urllib.parse.quote_plus(test_path)) redirect_url = view.get_success_url() self.assertEqual(redirect_url, test_path) def test_success_if_no_next(self): view = BatchDeterminationCreateView() view.request = self.dummy_request('') redirect_url = view.get_success_url() self.assertEqual(redirect_url, reverse_lazy('apply:submissions:list')) def test_message_created_if_determination_exists(self): submissions = ApplicationSubmissionFactory.create_batch(2) DeterminationFactory(submission=submissions[0], accepted=True, is_draft=False) url = self.url(None) + '?submissions=' + ','.join([str(submission.id) for submission in submissions]) + '&action=rejected' data = { 'submissions': [submission.id for submission in submissions], 'data': 'some data', 'outcome': REJECTED, 'message': 'Sorry', 'author': self.user.id, } response = self.client.post(url, data, secure=True, follow=True) self.assertEqual(submissions[0].determinations.count(), 1) self.assertEqual(submissions[0].determinations.first().outcome, ACCEPTED) self.assertEqual(submissions[1].determinations.count(), 1) self.assertEqual(submissions[1].determinations.first().outcome, REJECTED) # 5 base - 2 x django messages, 1 x activity feed, 1 x email, 1 x slack # plus 1 extra for unable to determine self.assertEqual(len(response.context['messages']), 6) class UserDeterminationFormTestCase(BaseViewTestCase): user_factory = UserFactory url_name = 'funds:submissions:determinations:{}' base_view_name = 'detail' def get_kwargs(self, instance): return {'submission_pk': instance.id} def test_cant_access_form(self): submission = ApplicationSubmissionFactory(status='in_discussion') response = self.get_page(submission, 'form') self.assertEqual(response.status_code, 403)