From d6e4c42c4ce63a271b4a448b43a21f3c85bc491d Mon Sep 17 00:00:00 2001 From: Todd Dembrey <todd.dembrey@torchbox.com> Date: Mon, 1 Apr 2019 09:19:11 +0100 Subject: [PATCH] GH-985: De-duplicate authors from opinions and reviews --- opentech/apply/funds/models/submissions.py | 36 ++++++++++++-------- opentech/apply/funds/tests/test_models.py | 39 ++++++++++++++++++++-- 2 files changed, 59 insertions(+), 16 deletions(-) diff --git a/opentech/apply/funds/models/submissions.py b/opentech/apply/funds/models/submissions.py index 26b709591..6e233fd4f 100644 --- a/opentech/apply/funds/models/submissions.py +++ b/opentech/apply/funds/models/submissions.py @@ -53,6 +53,11 @@ from ..workflow import ( ) +class SubqueryCount(Subquery): + template = "(SELECT count(*) FROM (%(subquery)s) _count)" + output_field = models.IntegerField() + + class JSONOrderable(models.QuerySet): json_field = '' @@ -126,6 +131,7 @@ class ApplicationSubmissionQueryset(JSONOrderable): return self.exclude(next__isnull=False) def for_table(self, user): + User = get_user_model() activities = self.model.activities.field.model latest_activity = activities.objects.filter(submission=OuterRef('id')).select_related('user') comments = activities.comments.filter(submission=OuterRef('id')).visible_to(user) @@ -146,24 +152,26 @@ class ApplicationSubmissionQueryset(JSONOrderable): ), 0, ), - review_count=Coalesce( - Subquery( - reviews.values('submission').annotate(count=Count('pk')).values('count'), - output_field=IntegerField(), - ), - 0, - ), opinion_disagree=Subquery( - opinions.filter(opinion=DISAGREE).values('review').annotate(count=Count('pk')).values('count'), + opinions.filter(opinion=DISAGREE).values( + 'review__submission' + ).annotate(count=Count('*')).values('count')[:1], output_field=IntegerField(), ), - review_staff_count=Subquery( - reviews.by_staff().values('submission').annotate(count=Count('pk')).values('count'), - output_field=IntegerField(), + review_staff_count=SubqueryCount( + User.objects.staff().filter( + Q(submissions_reviewer=OuterRef('id')) | Q(reviewopinion__review__submission=OuterRef('id')) + ).distinct().values('pk') ), - review_submitted_count=Subquery( - reviews.submitted().values('submission').annotate(count=Count('pk')).values('count'), - output_field=IntegerField(), + review_count=SubqueryCount( + User.objects.filter( + Q(submissions_reviewer=OuterRef('id')) | Q(reviewopinion__review__submission=OuterRef('id')) + ).distinct().values('pk') + ), + review_submitted_count=SubqueryCount( + User.objects.filter( + Q(review__submission=OuterRef('id')) | Q(reviewopinion__review__submission=OuterRef('id')) + ).distinct().values('pk') ), review_recommendation=Case( When(opinion_disagree__gt=0, then=MAYBE), diff --git a/opentech/apply/funds/tests/test_models.py b/opentech/apply/funds/tests/test_models.py index 37e1ce9f9..2022f4b73 100644 --- a/opentech/apply/funds/tests/test_models.py +++ b/opentech/apply/funds/tests/test_models.py @@ -19,6 +19,7 @@ from opentech.apply.users.tests.factories import StaffFactory from .factories import ( ApplicationSubmissionFactory, + AssignedReviewersFactory, CustomFormFieldsFactory, FundTypeFactory, LabFactory, @@ -502,6 +503,18 @@ class TestRequestForPartners(TestCase): class TestForTableQueryset(TestCase): + def test_assigned_but_not_reviewed(self): + staff = StaffFactory() + submission = ApplicationSubmissionFactory() + AssignedReviewersFactory(submission=submission, reviewer=staff) + + qs = ApplicationSubmission.objects.for_table(user=staff) + submission = qs[0] + self.assertEqual(submission.opinion_disagree, None) + self.assertEqual(submission.review_count, 1) + self.assertEqual(submission.review_submitted_count, 0) + self.assertEqual(submission.review_recommendation, None) + def test_review_outcome(self): staff = StaffFactory() submission = ApplicationSubmissionFactory() @@ -510,6 +523,7 @@ class TestForTableQueryset(TestCase): submission = qs[0] self.assertEqual(submission.opinion_disagree, None) self.assertEqual(submission.review_count, 1) + self.assertEqual(submission.review_submitted_count, 1) self.assertEqual(submission.review_recommendation, NO) def test_disagree_review_is_maybe(self): @@ -520,7 +534,26 @@ class TestForTableQueryset(TestCase): qs = ApplicationSubmission.objects.for_table(user=staff) submission = qs[0] self.assertEqual(submission.opinion_disagree, 1) - self.assertEqual(submission.review_count, 1) + self.assertEqual(submission.review_count, 2) + self.assertEqual(submission.review_submitted_count, 2) + self.assertEqual(submission.review_recommendation, MAYBE) + + def test_dont_double_count_review_and_opinion(self): + staff = StaffFactory() + submission = ApplicationSubmissionFactory() + + review = ReviewFactory(submission=submission, author=staff) + opinion = ReviewOpinionFactory(opinion_disagree=True, review=review) + + # Another pair of review/opinion + review_two = ReviewFactory(author=opinion.author, submission=submission) + ReviewOpinionFactory(opinion_disagree=True, author=staff, review=review_two) + + qs = ApplicationSubmission.objects.for_table(user=staff) + submission = qs[0] + self.assertEqual(submission.opinion_disagree, 2) + self.assertEqual(submission.review_count, 2) + self.assertEqual(submission.review_submitted_count, 2) self.assertEqual(submission.review_recommendation, MAYBE) def test_submissions_dont_conflict(self): @@ -535,10 +568,12 @@ class TestForTableQueryset(TestCase): qs = ApplicationSubmission.objects.for_table(user=staff) submission = qs[0] self.assertEqual(submission.opinion_disagree, 1) - self.assertEqual(submission.review_count, 1) + self.assertEqual(submission.review_count, 2) + self.assertEqual(submission.review_submitted_count, 2) self.assertEqual(submission.review_recommendation, MAYBE) submission = qs[1] self.assertEqual(submission.opinion_disagree, None) self.assertEqual(submission.review_count, 1) + self.assertEqual(submission.review_submitted_count, 1) self.assertEqual(submission.review_recommendation, NO) -- GitLab