Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions backend/api/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,12 @@
from django.http.request import HttpRequest
from strawberry.types import Info as StrawberryInfo

from voting.models.vote import Vote


@dataclass
class Context:
request: HttpRequest
response: Any
_user_can_vote: bool | None = None
_my_votes: dict[int, Vote] | None = None


type Info = StrawberryInfo[Context, Any]
49 changes: 26 additions & 23 deletions backend/api/submissions/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

import strawberry
import strawberry_django
from django.db.models import Case, IntegerField, When

from api.context import Info
from api.permissions import CanSeeSubmissions, IsAuthenticated
from api.submissions.permissions import CanSeeSubmissionRestrictedFields
from api.types import Paginated
from conferences import models as conference_models
from submissions import models as submission_models
from voting import models as voting_models
from voting.helpers import check_if_user_can_vote

from .types import Submission, SubmissionTag
Expand Down Expand Up @@ -72,14 +72,7 @@ def submissions(
):
raise PermissionError("You need to have a ticket to see submissions")

qs = conference.submissions.prefetch_related(
"type",
"duration",
"schedule_items",
"languages",
"audience_level",
"tags",
)
qs = conference.submissions.all()

if only_accepted:
qs = qs.filter(status=submission_models.Submission.STATUS.accepted)
Expand All @@ -103,21 +96,31 @@ def submissions(
if audience_levels:
qs = qs.filter(audience_level__id__in=audience_levels)

qs = qs.order_by("id").distinct()

all_submissions = list(qs)
random.Random(user.id).shuffle(all_submissions)

total_items = len(all_submissions)
submissions = list(all_submissions[(page - 1) * page_size : page * page_size])

info.context._my_votes = {
vote.submission_id: vote
for vote in voting_models.Vote.objects.filter(
user_id=user.id,
submission__in=submissions,
submission_ids = list(
qs.order_by("id").distinct().values_list("id", flat=True)
)
random.Random(user.id).shuffle(submission_ids)

total_items = len(submission_ids)
page_submission_ids = submission_ids[
(page - 1) * page_size : page * page_size
]
submissions = conference.submissions.filter(id__in=page_submission_ids)
if not only_accepted:
# This relation is used by a permission check, so it is invisible to
# Strawberry Django's selection-based optimizer.
submissions = submissions.prefetch_related("schedule_items")

if page_submission_ids:
submissions = submissions.order_by(
Case(
*(
When(id=submission_id, then=position)
for position, submission_id in enumerate(page_submission_ids)
),
output_field=IntegerField(),
)
)
}

return Paginated.paginate_list(
items=submissions,
Expand Down
4 changes: 2 additions & 2 deletions backend/api/submissions/tests/test_frontend_queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@

@pytest.mark.parametrize(
("submission_count", "expected_queries"),
[(1, 16), (4, 19)],
[(1, 14), (4, 14)],
)
def test_voting_submissions_frontend_query(
graphql_client,
Expand Down Expand Up @@ -148,7 +148,7 @@ def test_voting_submissions_frontend_query(

@pytest.mark.parametrize(
("submission_count", "expected_queries"),
[(1, 12), (4, 21)],
[(1, 6), (4, 6)],
)
def test_dynamic_content_proposals_frontend_query(
graphql_client,
Expand Down
29 changes: 18 additions & 11 deletions backend/api/submissions/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import strawberry
import strawberry_django
from django.db.models import Prefetch
from strawberry.types import Info
from strawberry.types.field import StrawberryField

Expand Down Expand Up @@ -181,28 +182,34 @@ def id(self, info: Info) -> strawberry.ID:
def can_edit(self, info: Info) -> bool:
return self.can_edit(info.context.request)

@strawberry.field
@strawberry_django.field(
prefetch_related=lambda info: Prefetch(
"votes",
queryset=(
voting_models.Vote.objects.filter(
user_id=info.context.request.user.id,
)
if info.context.request.user.is_authenticated
else voting_models.Vote.objects.none()
),
)
)
def my_vote(self, info: Info) -> VoteType | None:
request = info.context.request

if not request.user.is_authenticated:
return None

if info.context._my_votes is not None:
return info.context._my_votes.get(self.id)

try:
return self.votes.get(user_id=request.user.id)
except voting_models.Vote.DoesNotExist:
return None
return next(
(vote for vote in self.votes.all() if vote.user_id == request.user.id),
None,
)

@strawberry_django.field(prefetch_related=["languages"])
def languages(self, info: Info) -> list[Language] | None:
return list(self.languages.all())

@strawberry_django.field
def tags(self, info: Info) -> list[SubmissionTag] | None:
return self.tags.all()
tags: list[SubmissionTag] | None = strawberry_django.field()

@strawberry_django.field
def materials(self) -> list[ProposalMaterial]:
Expand Down
2 changes: 1 addition & 1 deletion backend/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -1459,6 +1459,7 @@ type Submission {
notes: String
doNotRecord: Boolean
scheduleItems: [ScheduleItem!]!
tags: [SubmissionTag!]
multilingualElevatorPitch: MultiLingualString
multilingualAbstract: MultiLingualString
multilingualTitle: MultiLingualString
Expand All @@ -1469,7 +1470,6 @@ type Submission {
canEdit: Boolean!
myVote: VoteType
languages: [Language!]
tags: [SubmissionTag!]
materials: [ProposalMaterial!]!
}

Expand Down
Loading