Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix serialization error for returning participants #1377

Merged
merged 4 commits into from
Nov 22, 2024
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
6 changes: 4 additions & 2 deletions backend/experiment/serializers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from random import shuffle
from typing import Optional
from typing import Optional, Union

from django_markup.markup import formatter
from django.utils.translation import activate, get_language
Expand Down Expand Up @@ -137,7 +137,9 @@ def serialize_block(block_object: Block, language: str = "en") -> dict:
}


def get_upcoming_block(phase: Phase, participant: Participant, times_played: int):
def get_upcoming_block(
phase: Phase, participant: Participant, times_played: int
) -> dict:
"""return next block with minimum finished sessions for this participant
if all blocks have been played an equal number of times, return None

Expand Down
26 changes: 26 additions & 0 deletions backend/experiment/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,32 @@ def test_get_experiment(self):
self.assertIsNotNone(response_json)
self.assertIn(response_json.get("nextBlock").get("slug"), ("block2", "block3"))

def test_get_experiment_returning_participant(self):
Session.objects.bulk_create(
self._get_session_objects(
[
self.block1,
self.block2,
self.block3,
self.block4,
self.block1,
self.block2,
self.block3,
self.block4,
]
)
)
response = self.client.get("/experiment/test_series/")
self.assertEqual(response.json().get("nextBlock").get("slug"), "block1")

def _get_session_objects(self, block_list: list[Block]) -> list[Session]:
return [
Session(
block=block, participant=self.participant, finished_at=timezone.now()
)
for block in block_list
]

def test_experiment_not_found(self):
# if Experiment does not exist, return 404
response = self.client.get("/experiment/not_found/")
Expand Down
32 changes: 24 additions & 8 deletions backend/experiment/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from django.utils.translation import gettext_lazy as _, get_language
from django_markup.markup import formatter

from .models import Block, Experiment, Phase, Feedback, Session
from .models import Block, Experiment, Feedback, Session
from section.models import Playlist
from experiment.serializers import (
serialize_block,
Expand All @@ -14,7 +14,7 @@
)
from experiment.rules import BLOCK_RULES
from experiment.actions.utils import EXPERIMENT_KEY
from image.serializers import serialize_image
from participant.models import Participant
from participant.utils import get_participant
from theme.serializers import serialize_theme

Expand Down Expand Up @@ -122,13 +122,29 @@ def get_experiment(
serialized_phase = serialize_phase(phase, participant, times_played)
if serialized_phase:
return JsonResponse(
{**serialize_experiment(experiment), **serialized_phase}
{
**serialize_experiment(experiment),
**serialized_phase,
}
)
# if no phase was found, start from scratch by incrementing times_pleyd
times_played += 1
request.session[times_played_key] = times_played
serialized_phase = serialize_phase(phases[0], participant, times_played)
return JsonResponse({**serialize_experiment(experiment), **serialized_phase})
# if no phase was found, start from scratch with the minimum session count
request.session[times_played_key] = _get_min_session_count(experiment, participant)
return get_experiment(request, slug)


def _get_min_session_count(experiment: Experiment, participant: Participant) -> int:
phases = experiment.phases.all()
session_counts = []
for phase in phases:
session_counts.extend(
[
Session.objects.exclude(finished_at__isnull=True)
.filter(block=block, participant=participant)
.count()
for block in phase.blocks.all()
]
)
return min(session_counts)


def get_associated_blocks(pk_list):
Expand Down