Skip to content

Commit

Permalink
Grants Review score and ranking in recap
Browse files Browse the repository at this point in the history
  • Loading branch information
marcoacierno committed Jan 24, 2024
1 parent e6dd338 commit fd0291e
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 41 deletions.
48 changes: 34 additions & 14 deletions backend/reviews/admin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from django.contrib.postgres.expressions import ArraySubquery
from django.db.models.expressions import ExpressionWrapper
from django.db.models import FloatField
from django.db.models.functions import Cast
from users.admin_mixins import ConferencePermissionMixin
from django.core.exceptions import PermissionDenied
from django.db.models import Q, Exists
Expand Down Expand Up @@ -280,30 +282,37 @@ def _review_grants_recap_view(self, request, review_session):

items = (
review_session.conference.grants.annotate(
total_score=Sum(
"userreview__score__numeric_value",
filter=Q(userreview__review_session_id=review_session_id),
total_score=Cast(
Sum(
"userreview__score__numeric_value",
filter=Q(userreview__review_session_id=review_session_id),
),
output_field=FloatField(),
),
vote_count=Count(
"userreview",
filter=Q(userreview__review_session_id=review_session_id),
vote_count=Cast(
Count(
"userreview",
filter=Q(userreview__review_session_id=review_session_id),
),
output_field=FloatField(),
),
score=ExpressionWrapper(
F("total_score") / F("vote_count"),
output_field=FloatField(),
),
is_a_speaker=Exists(
has_sent_a_proposal=Exists(
Submission.objects.non_cancelled().filter(
speaker_id=OuterRef("user_id"),
conference_id=review_session.conference_id,
)
),
user_private_comment=Subquery(
UserReview.objects.filter(
review_session_id=review_session_id,
grant_id=OuterRef("id"),
user_id=request.user.id,
).values("private_comment")[:1]
proposals_ids=ArraySubquery(
Submission.objects.non_cancelled()
.filter(
speaker_id=OuterRef("user_id"),
conference_id=review_session.conference_id,
)
.values("id")
),
)
.order_by(F("score").desc(nulls_last=True))
Expand All @@ -319,10 +328,21 @@ def _review_grants_recap_view(self, request, review_session):
.all()
)

proposals = {
submission.id: submission
for submission in Submission.objects.non_cancelled()
.filter(
conference_id=review_session.conference_id,
speaker_id__in=items.values_list("user_id"),
)
.prefetch_related("rankings", "rankings__tag")
}

context = dict(
self.admin_site.each_context(request),
request=request,
items=items,
proposals=proposals,
review_session_id=review_session_id,
review_session_repr=str(review_session),
all_statuses=[
Expand Down Expand Up @@ -592,7 +612,7 @@ def _render_grant_review(
context = dict(
self.admin_site.each_context(request),
grant=grant,
is_speaker=Submission.objects.non_cancelled()
has_sent_proposal=Submission.objects.non_cancelled()
.filter(
speaker_id=grant.user_id,
conference_id=grant.conference_id,
Expand Down
4 changes: 2 additions & 2 deletions backend/reviews/templates/grant-review.html
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,8 @@ <h2>Grant</h2>
</div>

<div class="review-row">
<strong>Is Speaker?</strong>
<div>{{is_speaker|yesno}}</div>
<strong>Has sent a proposal?</strong>
<div>{{has_sent_proposal|yesno}}</div>
</div>

<div class="review-row">
Expand Down
55 changes: 48 additions & 7 deletions backend/reviews/templates/grants-recap.html
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,39 @@
list-style-position: inside;
}

.results-item {
max-width: 500px;
}

.results-item ul li {
list-style: none;
}

.hidden {
display: none;
}

.grant-proposal-ranking {
display: inline;
}

.grant-proposal-ranking li {
display: inline;
}

.grant-proposal-ranking li:after {
content: ',';
}
.grant-proposal-ranking li:last-child:after {
display: none;
}

ul.proposals-ranking {
margin-left: 30px;
}
ul.proposals-ranking li {
list-style: square;
}
</style>
<script>
window.onload = () => {
Expand Down Expand Up @@ -177,7 +203,7 @@
</li>
<li>
<strong>Travelling From:</strong>
<span>{{item.travelling_from}}</span>
<span>{{item.get_travelling_from_display}}</span>
</li>
<li>
<strong>Country type:</strong>
Expand Down Expand Up @@ -209,9 +235,28 @@
<span>{{item.get_interested_in_volunteering_display}}</span>
</li>
<li>
<strong>Is a speaker?</strong>
<span>{{item.is_a_speaker|yesno}}</span>
<strong>Has sent a proposal?</strong>
<span>{{item.has_sent_a_proposal|yesno}}</span>
</li>
{% if item.has_sent_a_proposal %}
<li>
<strong>Proposals Ranking:</strong>
<ul class="proposals-ranking">
{% for proposal_id in item.proposals_ids %}
{% with proposal=proposals|get_item:proposal_id %}
<li>
<strong><a target="_blank" href="{% url 'admin:submissions_submission_change' proposal.id %}">{{proposal.title}}:</a></strong>
<ul class="grant-proposal-ranking">
{% for ranking in proposal.rankings.all %}
<li>{{ ranking.tag.name }} {{ ranking.rank }}/{{ ranking.total_submissions_per_tag }}</li>
{% endfor %}
</ul>
</li>
{% endwith %}
{% endfor %}
</ul>
</li>
{% endif %}
</ul>
</td>

Expand All @@ -235,10 +280,6 @@
</a>
</li>
</ul>
{% if item.user_private_comment %}
<strong>Your private comment</strong>
<p>{{ item.user_private_comment }}</p>
{% endif %}
</td>

<td>
Expand Down
133 changes: 116 additions & 17 deletions backend/reviews/tests/test_admin.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,44 @@
from conferences.tests.factories import ConferenceFactory
from django.contrib.admin import AdminSite
from grants.tests.factories import GrantFactory
import pytest
from reviews.tests.factories import (
AvailableScoreOptionFactory,
ReviewSessionFactory,
UserReviewFactory,
)
from submissions.tests.factories import SubmissionFactory, SubmissionTagFactory
from users.tests.factories import UserFactory

from reviews.admin import get_next_to_review_item_id
from reviews.admin import ReviewSessionAdmin, get_next_to_review_item_id
from reviews.models import ReviewSession

pytestmark = pytest.mark.django_db


def test_next_item_to_review_prefers_items_with_fewer_votes(
review_session_factory,
available_score_option_factory,
user_review_factory,
submission_factory,
conference_factory,
submission_tag_factory,
):
tag = submission_tag_factory()
def test_next_item_to_review_prefers_items_with_fewer_votes():
tag = SubmissionTagFactory()

user_1 = UserFactory(is_staff=True, is_superuser=True)
user_2 = UserFactory(is_staff=True, is_superuser=True)

conference = conference_factory()
conference = ConferenceFactory()

review_session = review_session_factory(
review_session = ReviewSessionFactory(
conference=conference,
session_type=ReviewSession.SessionType.PROPOSALS,
)
score_0 = available_score_option_factory(
score_0 = AvailableScoreOptionFactory(
review_session=review_session, numeric_value=0
)
available_score_option_factory(review_session=review_session, numeric_value=1)
AvailableScoreOptionFactory(review_session=review_session, numeric_value=1)

submission_1 = submission_factory(conference=conference)
submission_1 = SubmissionFactory(conference=conference)
submission_1.tags.add(tag)
submission_2 = submission_factory(conference=conference)
submission_2 = SubmissionFactory(conference=conference)
submission_2.tags.add(tag)

user_review_factory(
UserReviewFactory(
review_session=review_session,
proposal=submission_1,
user=user_1,
Expand All @@ -45,3 +47,100 @@ def test_next_item_to_review_prefers_items_with_fewer_votes(

next_to_review = get_next_to_review_item_id(review_session, user_2)
assert next_to_review == submission_2.id


@pytest.mark.parametrize(
"scores, avg",
[
(
[
{"user": 0, "score": 2},
{"user": 1, "score": 2},
{"user": 2, "score": 2},
{"user": 3, "score": -1},
{"user": 4, "score": -2},
],
0.6,
),
(
[
{"user": 0, "score": -2},
{"user": 1, "score": -2},
{"user": 2, "score": -2},
{"user": 3, "score": -2},
{"user": 4, "score": -2},
],
-2.0,
),
(
[
{"user": 0, "score": 1},
],
1.0,
),
([], None),
],
)
def test_grants_review_scores(rf, scores, avg):
conference = ConferenceFactory()
review_session = ReviewSessionFactory(
conference=conference,
session_type=ReviewSession.SessionType.GRANTS,
status=ReviewSession.Status.COMPLETED,
)

users = UserFactory.create_batch(10, is_staff=True, is_superuser=True)
all_scores = {
-2: AvailableScoreOptionFactory(
review_session=review_session, numeric_value=-2, label="Rejected"
),
-1: AvailableScoreOptionFactory(
review_session=review_session, numeric_value=-1, label="Not convinced"
),
0: AvailableScoreOptionFactory(
review_session=review_session, numeric_value=0, label="Maybe"
),
1: AvailableScoreOptionFactory(
review_session=review_session, numeric_value=1, label="Yes"
),
2: AvailableScoreOptionFactory(
review_session=review_session, numeric_value=2, label="Absolutely"
),
}

grant_1 = GrantFactory(conference=conference)
for score in scores:
UserReviewFactory(
review_session=review_session,
grant=grant_1,
user=users[score["user"]],
score=all_scores[score["score"]],
)

grant_2 = GrantFactory(conference=conference)

UserReviewFactory(
review_session=review_session,
grant=grant_2,
user=users[9],
score=all_scores[-2],
)

UserReviewFactory(
review_session=review_session,
grant=grant_2,
user=users[8],
score=all_scores[-1],
)

request = rf.get("/")
request.user = users[5]

admin = ReviewSessionAdmin(ReviewSession, AdminSite())
response = admin._review_grants_recap_view(request, review_session)
context_data = response.context_data
items = context_data["items"]
grant_to_check = next(item for item in items if item.id == grant_1.id)

assert grant_to_check.id == grant_1.id
assert grant_to_check.score == avg
4 changes: 3 additions & 1 deletion backend/users/management/commands/sync_admin_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from grants.models import Grant
from reviews.models import ReviewSession
from reviews.models import ReviewSession, UserReview

Check warning on line 6 in backend/users/management/commands/sync_admin_groups.py

View check run for this annotation

Codecov / codecov/patch

backend/users/management/commands/sync_admin_groups.py#L6

Added line #L6 was not covered by tests
from submissions.models import Submission


Expand All @@ -23,6 +23,7 @@ def grants_reviewers(self):
self.get_permission("view_grant", Grant),
self.get_permission("view_reviewsession", ReviewSession),
self.get_permission("review_reviewsession", ReviewSession),
self.get_permission("view_userreview", UserReview),
]
)

Expand All @@ -36,6 +37,7 @@ def proposals_reviewers(self):
self.get_permission("view_submission", Submission),
self.get_permission("view_reviewsession", ReviewSession),
self.get_permission("review_reviewsession", ReviewSession),
self.get_permission("view_userreview", UserReview),
]
)

Expand Down

0 comments on commit fd0291e

Please sign in to comment.