diff --git a/backend/experiment/actions/consent.py b/backend/experiment/actions/consent.py
index e027d5a08..732913c45 100644
--- a/backend/experiment/actions/consent.py
+++ b/backend/experiment/actions/consent.py
@@ -38,7 +38,7 @@ def render_html_or_markdown(dry_text: str, render_format: str) -> str:
class Consent(BaseAction): # pylint: disable=too-few-public-methods
"""
Provide data for a view that ask consent for using the experiment data
- - text: Uploaded file via experiment.consent (fileField)
+ - text: Uploaded file via block.consent (fileField)
- title: The title to be displayed
- confirm: The text on the confirm button
- deny: The text on the deny button
@@ -49,7 +49,7 @@ class Consent(BaseAction): # pylint: disable=too-few-public-methods
Relates to client component: Consent.js
"""
- # default consent text, that can be used for multiple experiments
+ # default consent text, that can be used for multiple blocks
ID = 'CONSENT'
default_text = "Lorem ipsum dolor sit amet, nec te atqui scribentur. Diam \
@@ -62,11 +62,11 @@ class Consent(BaseAction): # pylint: disable=too-few-public-methods
contentiones, vix ex maiorum denique! Lorem ipsum dolor sit \
amet, nec te atqui scribentur. Diam molestie posidonium te sit, \
ea sea expetenda suscipiantur contentiones."
-
+
def __init__(self, text, title='Informed consent', confirm='I agree', deny='Stop', url=''):
# Determine which text to use
if text!='':
- # Uploaded consent via file field: experiment.consent (High priority)
+ # Uploaded consent via file field: block.consent (High priority)
with text.open('r') as f:
dry_text = f.read()
render_format = get_render_format(text.url)
diff --git a/backend/experiment/actions/score.py b/backend/experiment/actions/score.py
index 79930bd1e..26baa64cc 100644
--- a/backend/experiment/actions/score.py
+++ b/backend/experiment/actions/score.py
@@ -29,7 +29,7 @@ def __init__(self, session, title: str = None, score=None, score_message=None, c
self.session = session
self.title = title or _('Round {rounds_passed} / {total_rounds}').format(
rounds_passed=session.rounds_passed(),
- total_rounds=self.session.experiment.rounds
+ total_rounds=self.session.block.rounds
)
self.score = score or session.last_score()
self.score_message = score_message or self.default_score_message
diff --git a/backend/experiment/actions/tests/test_actions_consent.py b/backend/experiment/actions/tests/test_actions_consent.py
index ff85828cf..c45aeb537 100644
--- a/backend/experiment/actions/tests/test_actions_consent.py
+++ b/backend/experiment/actions/tests/test_actions_consent.py
@@ -1,25 +1,25 @@
from django.test import TestCase
from django.core.files.uploadedfile import SimpleUploadedFile
-from experiment.models import Experiment
+from experiment.models import Block
from experiment.actions.consent import Consent
class ConsentTest(TestCase):
@classmethod
- def setUpTestData(cls):
- Experiment.objects.create(
+ def setUpTestData(cls):
+ Block.objects.create(
name='test_md',
slug='MARKDOWN',
consent=SimpleUploadedFile('consent.md', b'#test', content_type='text/html')
)
- Experiment.objects.create(
+ Block.objects.create(
name='test_html',
slug='HTML',
consent=SimpleUploadedFile('consent.html', b'
test ', content_type='text/html')
)
- Experiment.objects.create(
+ Block.objects.create(
name='test_template',
slug='TEMPLATE',
consent=SimpleUploadedFile('template.html', b'{% load i18n %}{% blocktranslate %}test
{% endblocktranslate %}', content_type='text/html')
@@ -34,16 +34,16 @@ def test_html_rendering(self):
self.assertEqual(consent.text, 'test ')
def test_uploaded_markdown_rendering(self):
- experiment = Experiment.objects.get(slug='MARKDOWN')
- consent = Consent(experiment.consent)
+ block = Block.objects.get(slug='MARKDOWN')
+ consent = Consent(block.consent)
self.assertEqual(consent.text, 'test ')
def test_uploaded_html_rendering(self):
- experiment = Experiment.objects.get(slug='HTML')
- consent = Consent(experiment.consent)
+ block = Block.objects.get(slug='HTML')
+ consent = Consent(block.consent)
self.assertEqual(consent.text, 'test ')
def test_template_language_rendering(self):
- experiment = Experiment.objects.get(slug='TEMPLATE')
- consent = Consent(experiment.consent)
+ block = Block.objects.get(slug='TEMPLATE')
+ consent = Consent(block.consent)
self.assertEqual(consent.text, 'test
')
diff --git a/backend/experiment/actions/tests/test_actions_score.py b/backend/experiment/actions/tests/test_actions_score.py
index f37d76d1c..7c5e3b400 100644
--- a/backend/experiment/actions/tests/test_actions_score.py
+++ b/backend/experiment/actions/tests/test_actions_score.py
@@ -12,7 +12,7 @@ def setUp(self):
self.mock_session.last_song.return_value = "Test Song"
self.mock_session.total_score.return_value = 50
self.mock_session.rounds_passed.return_value = 2
- self.mock_session.experiment.rounds = 5
+ self.mock_session.block.rounds = 5
def test_initialization_full_parameters(self):
score = Score(
diff --git a/backend/experiment/actions/tests/test_wrappers.py b/backend/experiment/actions/tests/test_wrappers.py
index ccc1ed382..d635e77d7 100644
--- a/backend/experiment/actions/tests/test_wrappers.py
+++ b/backend/experiment/actions/tests/test_wrappers.py
@@ -3,7 +3,7 @@
from experiment.actions import Trial
from experiment.actions.wrappers import song_sync
-from experiment.models import Experiment
+from experiment.models import Block
from participant.models import Participant
from section.models import Playlist, Section
from session.models import Session
@@ -15,9 +15,9 @@ def setUp(self):
self.participant = Participant.objects.create()
self.section = Section.objects.create(
filename='some/audio/file.mp3', playlist=self.playlist)
- self.experiment = Experiment.objects.create(name='TestExperiment')
+ self.block = Block.objects.create(name='TestBlock')
self.session = Session.objects.create(
- experiment=self.experiment, participant=self.participant, playlist=self.playlist)
+ block=self.block, participant=self.participant, playlist=self.playlist)
def test_song_sync(self):
actions = song_sync(self.session, self.section, 'HookedTest')
diff --git a/backend/experiment/actions/toontjehoger.py b/backend/experiment/actions/toontjehoger.py
index f19f14327..9e733a0d9 100644
--- a/backend/experiment/actions/toontjehoger.py
+++ b/backend/experiment/actions/toontjehoger.py
@@ -10,7 +10,7 @@ class ToontjeHoger(BaseAction): # pylint: disable=too-few-public-methods
ID = "TOONTJEHOGER"
- def __init__(self, config, experiments=[]):
+ def __init__(self, config, blocks=[]):
"""
ToontjeHoger shows the ToontjeHoger homepage
@@ -21,7 +21,7 @@ def __init__(self, config, experiments=[]):
- main_button_url
- score_label
- supporters_intro
- experiments: A list of ExperimentData objects
+ blocks: A list of ExperimentData objects
"""
self.config = config
- self.experiments = [vars(i) for i in self.experiments]
+ self.blocks = [vars(i) for i in self.blocks]
diff --git a/backend/experiment/actions/trial.py b/backend/experiment/actions/trial.py
index f4108ae83..5e6b27627 100644
--- a/backend/experiment/actions/trial.py
+++ b/backend/experiment/actions/trial.py
@@ -66,7 +66,7 @@ def __init__(
def action(self):
"""
- Serialize data for experiment action
+ Serialize data for a block action
"""
# Create action
diff --git a/backend/experiment/actions/utils.py b/backend/experiment/actions/utils.py
index b1994cc97..5a82c6921 100644
--- a/backend/experiment/actions/utils.py
+++ b/backend/experiment/actions/utils.py
@@ -11,8 +11,8 @@
def final_action_with_optional_button(session, final_text='', title=_('End'), button_text=_('Continue')):
- """ given a session, a score message and an optional session dictionary from an experiment series,
- return a Final.action, which has a button to continue to the next experiment if series is defined
+ """ given a session, a score message and an optional session dictionary from an experiment collection,
+ return a Final.action, which has a button to continue to the next block if series is defined
"""
collection_slug = session.load_json_data().get(COLLECTION_KEY)
@@ -49,7 +49,7 @@ def render_feedback_trivia(feedback, trivia):
def get_average_difference(session, num_turnpoints, initial_value):
- """
+ """
return the average difference in milliseconds participants could hear
"""
last_turnpoints = get_last_n_turnpoints(session, num_turnpoints)
@@ -58,8 +58,8 @@ def get_average_difference(session, num_turnpoints, initial_value):
if last_result:
return float(last_result.section.song.name)
else:
- # this cannot happen in DurationDiscrimination style experiments
- # for future compatibility, still catch the condition that there may be no results
+ # this cannot happen in DurationDiscrimination style blocks
+ # for future compatibility, still catch the condition that there may be no results
return initial_value
return (sum([int(result.section.song.name) for result in last_turnpoints]) / last_turnpoints.count())
@@ -78,7 +78,7 @@ def get_average_difference_level_based(session, num_turnpoints, initial_value):
# no results right after the practice rounds
return initial_value
# Difference by level starts at initial value (which is level 1, so 20/(2^0)) and then halves for every next level
- return sum([initial_value / (2 ** (int(result.section.song.name.split('_')[-1]) - 1)) for result in last_turnpoints]) / last_turnpoints.count()
+ return sum([initial_value / (2 ** (int(result.section.song.name.split('_')[-1]) - 1)) for result in last_turnpoints]) / last_turnpoints.count()
def get_fallback_result(session):
diff --git a/backend/experiment/admin.py b/backend/experiment/admin.py
index 215b4090e..53ebe2277 100644
--- a/backend/experiment/admin.py
+++ b/backend/experiment/admin.py
@@ -26,7 +26,7 @@
from question.admin import QuestionSeriesInline
from experiment.forms import (
ExperimentCollectionForm,
- ExperimentForm,
+ BlockForm,
ExportForm,
TemplateForm,
SocialMediaConfigForm,
@@ -46,9 +46,9 @@ class FeedbackInline(admin.TabularInline):
extra = 0
-class ExperimentAdmin(InlineActionsModelAdminMixin, admin.ModelAdmin):
- list_display = ('image_preview', 'experiment_name_link',
- 'experiment_slug_link', 'rules',
+class BlockAdmin(InlineActionsModelAdminMixin, admin.ModelAdmin):
+ list_display = ('image_preview', 'block_name_link',
+ 'block_slug_link', 'rules',
'rounds', 'playlist_count',
'session_count', 'active')
list_filter = ['active']
@@ -60,7 +60,7 @@ class ExperimentAdmin(InlineActionsModelAdminMixin, admin.ModelAdmin):
'rounds', 'bonus_points', 'playlists',
'consent']
inlines = [QuestionSeriesInline, FeedbackInline]
- form = ExperimentForm
+ form = BlockForm
# make playlists fields a list of checkboxes
formfield_overrides = {
@@ -68,7 +68,7 @@ class ExperimentAdmin(InlineActionsModelAdminMixin, admin.ModelAdmin):
}
def export(self, request, obj, parent_obj=None):
- """Export experiment JSON data as zip archive, force download"""
+ """Export block JSON data as zip archive, force download"""
# Init empty querysets
all_results = Result.objects.none()
@@ -112,7 +112,7 @@ def export(self, request, obj, parent_obj=None):
export.short_description = "Export JSON"
def export_csv(self, request, obj, parent_obj=None):
- """Export experiment data in CSV, force download"""
+ """Export block data in CSV, force download"""
# Handle export command from intermediate form
if '_export' in request.POST:
session_keys = []
@@ -130,16 +130,16 @@ def export_csv(self, request, obj, parent_obj=None):
response['Content-Disposition'] = 'attachment; filename="{}.csv"'.format(
obj.slug)
# Get filtered data
- experiment_table, fieldnames = obj.export_table(
+ block_table, fieldnames = obj.export_table(
session_keys, result_keys, export_options)
fieldnames.sort()
writer = csv.DictWriter(response, fieldnames)
writer.writeheader()
- writer.writerows(experiment_table)
+ writer.writerows(block_table)
return response
- # Go back to admin experiment overview
+ # Go back to admin block overview
if '_back' in request.POST:
- return redirect('/admin/experiment/experiment')
+ return redirect('/admin/experiment/block')
# Load a template in the export form
if '_template' in request.POST:
selected_template = request.POST.get('select_template')
@@ -170,26 +170,26 @@ def image_preview(self, obj):
return mark_safe(f' ')
return ""
- def experiment_name_link(self, obj):
- """Generate a link to the experiment's admin change page."""
- url = reverse("admin:experiment_experiment_change", args=[obj.pk])
+ def block_name_link(self, obj):
+ """Generate a link to the block's admin change page."""
+ url = reverse("admin:experiment_block_change", args=[obj.pk])
name = obj.name or obj.slug or "No name"
return format_html('{} ', url, name)
- def experiment_slug_link(self, obj):
+ def block_slug_link(self, obj):
dev_mode = settings.DEBUG is True
url = f"http://localhost:3000/{obj.slug}" if dev_mode else f"/{obj.slug}"
return format_html(
- f'{obj.slug} ↗ ')
+ f'{obj.slug} ↗ ')
# Name the columns
image_preview.short_description = "Image"
- experiment_name_link.short_description = "Name"
- experiment_slug_link.short_description = "Slug"
+ block_name_link.short_description = "Name"
+ block_slug_link.short_description = "Slug"
-admin.site.register(Block, ExperimentAdmin)
+admin.site.register(Block, BlockAdmin)
class GroupedBlockInline(admin.StackedInline):
@@ -245,7 +245,7 @@ def phases(self, obj):
def dashboard(self, request, obj, parent_obj=None):
"""Open researchers dashboard for a collection"""
- all_experiments = obj.associated_experiments()
+ all_blocks = obj.associated_blocks()
all_participants = obj.current_participants()
all_sessions = obj.export_sessions()
collect_data = {
@@ -253,23 +253,23 @@ def dashboard(self, request, obj, parent_obj=None):
'session_count': len(all_sessions)
}
- experiments = [{
- 'id': exp.id,
- 'name': exp.name,
- 'started': len(all_sessions.filter(experiment=exp)),
+ blocks = [{
+ 'id': block.id,
+ 'name': block.name,
+ 'started': len(all_sessions.filter(block=block)),
'finished': len(all_sessions.filter(
- experiment=exp,
+ block=block,
finished_at__isnull=False,
)),
- 'participant_count': len(exp.current_participants()),
- 'participants': exp.current_participants()
- } for exp in all_experiments]
+ 'participant_count': len(block.current_participants()),
+ 'participants': block.current_participants()
+ } for block in all_blocks]
return render(
request,
'collection-dashboard.html',
context={'collection': obj,
- 'experiments': experiments,
+ 'blocks': blocks,
'sessions': all_sessions,
'participants': all_participants,
'collect_data': collect_data}
@@ -280,7 +280,7 @@ def dashboard(self, request, obj, parent_obj=None):
class PhaseAdmin(InlineActionsModelAdminMixin, admin.ModelAdmin):
- list_display = ('name_link', 'related_series', 'index', 'dashboard', 'randomize', 'experiments')
+ list_display = ('name_link', 'related_series', 'index', 'dashboard', 'randomize', 'blocks')
fields = ['name', 'series', 'index', 'dashboard', 'randomize']
inlines = [GroupedBlockInline]
@@ -295,13 +295,13 @@ def related_series(self, obj):
"admin:experiment_experimentcollection_change", args=[obj.series.pk])
return format_html('{} ', url, obj.series.name)
- def experiments(self, obj):
- experiments = GroupedBlock.objects.filter(phase=obj)
+ def blocks(self, obj):
+ blocks = GroupedBlock.objects.filter(phase=obj)
- if not experiments:
- return "No experiments"
+ if not blocks:
+ return "No blocks"
- return format_html(', '.join([f'{experiment.block.name} ' for experiment in experiments]))
+ return format_html(', '.join([f'{block.block.name} ' for block in blocks]))
admin.site.register(Phase, PhaseAdmin)
diff --git a/backend/experiment/fixtures/experiment.json b/backend/experiment/fixtures/experiment.json
index aa1bff627..f80e841c7 100644
--- a/backend/experiment/fixtures/experiment.json
+++ b/backend/experiment/fixtures/experiment.json
@@ -1,283 +1,283 @@
[
-{
- "model": "experiment.ExperimentCollection",
- "pk": 1,
- "fields": {
- "slug": "RhythmTestSeries",
- "first_experiments": [
- "10"
- ],
- "random_experiments": [
- "7",
- "3",
- "1",
- "2",
- "5",
- "4",
- "6",
- "8"
- ],
- "last_experiments": [
- "9"
- ]
- }
-},
-{
- "model": "experiment.experiment",
- "pk": 1,
- "fields": {
- "name": "DurationDiscrimination",
- "slug": "ddi",
- "active": true,
- "rounds": 100,
- "bonus_points": 0,
- "rules": "DURATION_DISCRIMINATION",
- "language": "",
- "playlists": [
- 5
- ]
- }
-},
-{
- "model": "experiment.experiment",
- "pk": 2,
- "fields": {
- "name": "DurationDiscriminationTone",
- "slug": "ddit",
- "active": true,
- "rounds": 100,
- "bonus_points": 0,
- "rules": "DURATION_DISCRIMINATION_TONE",
- "language": "",
- "playlists": [
- 4
- ]
- }
-},
-{
- "model": "experiment.experiment",
- "pk": 3,
- "fields": {
- "name": "BeatAlignment",
- "slug": "bat",
- "active": true,
- "rounds": 17,
- "bonus_points": 0,
- "rules": "BEAT_ALIGNMENT",
- "language": "",
- "playlists": [
- 7
- ]
- }
-},
-{
- "model": "experiment.experiment",
- "pk": 4,
- "fields": {
- "name": "HBAT-BIT",
- "slug": "hbat_bit",
- "active": true,
- "rounds": 100,
- "bonus_points": 0,
- "rules": "H_BAT",
- "language": "",
- "playlists": [
- 9
- ]
- }
-},
-{
- "model": "experiment.experiment",
- "pk": 5,
- "fields": {
- "name": "HBAT-BFIT",
- "slug": "hbat_bfit",
- "active": true,
- "rounds": 100,
- "bonus_points": 0,
- "rules": "H_BAT_BFIT",
- "language": "",
- "playlists": [
- 8
- ]
- }
-},
-{
- "model": "experiment.experiment",
- "pk": 6,
- "fields": {
- "name": "HBAT-BST",
- "slug": "hbat_bst",
- "active": true,
- "rounds": 100,
- "bonus_points": 0,
- "rules": "BST",
- "language": "",
- "playlists": [
- 10
- ]
- }
-},
-{
- "model": "experiment.experiment",
- "pk": 7,
- "fields": {
- "name": "Anisochrony",
- "slug": "anis",
- "active": true,
- "rounds": 100,
- "bonus_points": 0,
- "rules": "ANISOCHRONY",
- "language": "",
- "playlists": [
- 3
- ]
- }
-},
-{
- "model": "experiment.experiment",
- "pk": 8,
- "fields": {
- "name": "RhythmDiscrimination",
- "slug": "rhdis",
- "active": true,
- "rounds": 40,
- "bonus_points": 0,
- "rules": "RHYTHM_DISCRIMINATION",
- "language": "",
- "playlists": [
- 6
- ]
- }
-},
-{
- "model": "experiment.experiment",
- "pk": 9,
- "fields": {
- "name": "Rhythm Battery Final",
- "slug": "rhythm_outro",
- "active": true,
- "rounds": 10,
- "bonus_points": 0,
- "rules": "RHYTHM_BATTERY_FINAL",
- "language": "",
- "playlists": [
- 3
- ]
- }
-},
-{
- "model": "experiment.experiment",
- "pk": 10,
- "fields": {
- "name": "Rhythm Battery Intro",
- "slug": "rhythm_intro",
- "active": true,
- "rounds": 10,
- "bonus_points": 0,
- "rules": "RHYTHM_BATTERY_INTRO",
- "language": "",
- "playlists": [
- 11
- ]
- }
-},
-{
- "model": "experiment.experiment",
- "pk": 14,
- "fields": {
- "name": "Hooked-China",
- "slug": "huang_2022",
- "active": true,
- "rounds": 30,
- "bonus_points": 0,
- "rules": "HUANG_2022",
- "language": "zh",
- "playlists": [
- 13,
- 2,
- 1
- ]
- }
-},
-{
- "model": "experiment.experiment",
- "pk": 16,
- "fields": {
- "name": "Categorization",
- "slug": "cat",
- "active": true,
- "rounds": 10,
- "bonus_points": 0,
- "rules": "CATEGORIZATION",
- "language": "en",
- "playlists": [
- 12
- ]
- }
-},
-{
- "model": "experiment.experiment",
- "pk": 17,
- "fields": {
- "name": "TuneTwins",
- "slug": "tunetwins",
- "active": true,
- "rounds": 10,
- "bonus_points": 0,
- "rules": "MATCHING_PAIRS",
- "language": "en",
- "playlists": [
- 14
- ]
- }
-},
-{
- "model": "experiment.experiment",
- "pk": 18,
- "fields": {
- "name": "Hooked-Eurovision",
- "slug": "eurovision_2021",
- "active": true,
- "rounds": 30,
- "bonus_points": 0,
- "rules": "EUROVISION_2020",
- "language": "en",
- "playlists": [
- 16
- ]
- }
-},
-{
- "model": "experiment.experiment",
- "pk": 19,
- "fields": {
- "name": "Hooked-Christmas",
- "slug": "christmas_2020",
- "active": true,
- "rounds": 30,
- "bonus_points": 0,
- "rules": "KUIPER_2020",
- "language": "en",
- "playlists": [
- 17
- ]
- }
-},
-{
- "model": "experiment.experiment",
- "pk": 20,
- "fields": {
- "name": "ThatsMySong",
- "slug": "thats_my_song",
- "active": false,
- "rounds": 10,
- "bonus_points": 0,
- "rules": "THATS_MY_SONG",
- "language": "",
- "playlists": [
- 18
- ]
- }
-}
+ {
+ "model": "experiment.ExperimentCollection",
+ "pk": 1,
+ "fields": {
+ "slug": "RhythmTestSeries",
+ "first_experiments": [
+ "10"
+ ],
+ "random_experiments": [
+ "7",
+ "3",
+ "1",
+ "2",
+ "5",
+ "4",
+ "6",
+ "8"
+ ],
+ "last_experiments": [
+ "9"
+ ]
+ }
+ },
+ {
+ "model": "experiment.Block",
+ "pk": 1,
+ "fields": {
+ "name": "DurationDiscrimination",
+ "slug": "ddi",
+ "active": true,
+ "rounds": 100,
+ "bonus_points": 0,
+ "rules": "DURATION_DISCRIMINATION",
+ "language": "",
+ "playlists": [
+ 5
+ ]
+ }
+ },
+ {
+ "model": "experiment.Block",
+ "pk": 2,
+ "fields": {
+ "name": "DurationDiscriminationTone",
+ "slug": "ddit",
+ "active": true,
+ "rounds": 100,
+ "bonus_points": 0,
+ "rules": "DURATION_DISCRIMINATION_TONE",
+ "language": "",
+ "playlists": [
+ 4
+ ]
+ }
+ },
+ {
+ "model": "experiment.Block",
+ "pk": 3,
+ "fields": {
+ "name": "BeatAlignment",
+ "slug": "bat",
+ "active": true,
+ "rounds": 17,
+ "bonus_points": 0,
+ "rules": "BEAT_ALIGNMENT",
+ "language": "",
+ "playlists": [
+ 7
+ ]
+ }
+ },
+ {
+ "model": "experiment.Block",
+ "pk": 4,
+ "fields": {
+ "name": "HBAT-BIT",
+ "slug": "hbat_bit",
+ "active": true,
+ "rounds": 100,
+ "bonus_points": 0,
+ "rules": "H_BAT",
+ "language": "",
+ "playlists": [
+ 9
+ ]
+ }
+ },
+ {
+ "model": "experiment.Block",
+ "pk": 5,
+ "fields": {
+ "name": "HBAT-BFIT",
+ "slug": "hbat_bfit",
+ "active": true,
+ "rounds": 100,
+ "bonus_points": 0,
+ "rules": "H_BAT_BFIT",
+ "language": "",
+ "playlists": [
+ 8
+ ]
+ }
+ },
+ {
+ "model": "experiment.Block",
+ "pk": 6,
+ "fields": {
+ "name": "HBAT-BST",
+ "slug": "hbat_bst",
+ "active": true,
+ "rounds": 100,
+ "bonus_points": 0,
+ "rules": "BST",
+ "language": "",
+ "playlists": [
+ 10
+ ]
+ }
+ },
+ {
+ "model": "experiment.Block",
+ "pk": 7,
+ "fields": {
+ "name": "Anisochrony",
+ "slug": "anis",
+ "active": true,
+ "rounds": 100,
+ "bonus_points": 0,
+ "rules": "ANISOCHRONY",
+ "language": "",
+ "playlists": [
+ 3
+ ]
+ }
+ },
+ {
+ "model": "experiment.Block",
+ "pk": 8,
+ "fields": {
+ "name": "RhythmDiscrimination",
+ "slug": "rhdis",
+ "active": true,
+ "rounds": 40,
+ "bonus_points": 0,
+ "rules": "RHYTHM_DISCRIMINATION",
+ "language": "",
+ "playlists": [
+ 6
+ ]
+ }
+ },
+ {
+ "model": "experiment.Block",
+ "pk": 9,
+ "fields": {
+ "name": "Rhythm Battery Final",
+ "slug": "rhythm_outro",
+ "active": true,
+ "rounds": 10,
+ "bonus_points": 0,
+ "rules": "RHYTHM_BATTERY_FINAL",
+ "language": "",
+ "playlists": [
+ 3
+ ]
+ }
+ },
+ {
+ "model": "experiment.Block",
+ "pk": 10,
+ "fields": {
+ "name": "Rhythm Battery Intro",
+ "slug": "rhythm_intro",
+ "active": true,
+ "rounds": 10,
+ "bonus_points": 0,
+ "rules": "RHYTHM_BATTERY_INTRO",
+ "language": "",
+ "playlists": [
+ 11
+ ]
+ }
+ },
+ {
+ "model": "experiment.Block",
+ "pk": 14,
+ "fields": {
+ "name": "Hooked-China",
+ "slug": "huang_2022",
+ "active": true,
+ "rounds": 30,
+ "bonus_points": 0,
+ "rules": "HUANG_2022",
+ "language": "zh",
+ "playlists": [
+ 13,
+ 2,
+ 1
+ ]
+ }
+ },
+ {
+ "model": "experiment.Block",
+ "pk": 16,
+ "fields": {
+ "name": "Categorization",
+ "slug": "cat",
+ "active": true,
+ "rounds": 10,
+ "bonus_points": 0,
+ "rules": "CATEGORIZATION",
+ "language": "en",
+ "playlists": [
+ 12
+ ]
+ }
+ },
+ {
+ "model": "experiment.Block",
+ "pk": 17,
+ "fields": {
+ "name": "TuneTwins",
+ "slug": "tunetwins",
+ "active": true,
+ "rounds": 10,
+ "bonus_points": 0,
+ "rules": "MATCHING_PAIRS",
+ "language": "en",
+ "playlists": [
+ 14
+ ]
+ }
+ },
+ {
+ "model": "experiment.Block",
+ "pk": 18,
+ "fields": {
+ "name": "Hooked-Eurovision",
+ "slug": "eurovision_2021",
+ "active": true,
+ "rounds": 30,
+ "bonus_points": 0,
+ "rules": "EUROVISION_2020",
+ "language": "en",
+ "playlists": [
+ 16
+ ]
+ }
+ },
+ {
+ "model": "experiment.Block",
+ "pk": 19,
+ "fields": {
+ "name": "Hooked-Christmas",
+ "slug": "christmas_2020",
+ "active": true,
+ "rounds": 30,
+ "bonus_points": 0,
+ "rules": "KUIPER_2020",
+ "language": "en",
+ "playlists": [
+ 17
+ ]
+ }
+ },
+ {
+ "model": "experiment.Block",
+ "pk": 20,
+ "fields": {
+ "name": "ThatsMySong",
+ "slug": "thats_my_song",
+ "active": false,
+ "rounds": 10,
+ "bonus_points": 0,
+ "rules": "THATS_MY_SONG",
+ "language": "",
+ "playlists": [
+ 18
+ ]
+ }
+ }
]
diff --git a/backend/experiment/forms.py b/backend/experiment/forms.py
index 0f9350abe..7c41f2599 100644
--- a/backend/experiment/forms.py
+++ b/backend/experiment/forms.py
@@ -4,8 +4,8 @@
# session_keys for Export CSV
-SESSION_CHOICES = [('experiment_id', 'Experiment ID'),
- ('experiment_name', 'Experiment name'),
+SESSION_CHOICES = [('block_id', 'Block ID'),
+ ('block_name', 'Block name'),
('participant_id', 'Participant ID'),
('participant_country', 'Participant Country'),
('participant_access_info', 'Participant access info'),
@@ -36,61 +36,61 @@
# Export templates for Export CSV
EXPORT_TEMPLATES = {'wide':
- [['experiment_id', 'experiment_name', 'participant_id',
+ [['block_id', 'block_name', 'participant_id',
'participant_country', 'participant_access_info', 'session_start', 'session_end', 'final_score'],
['section_name', 'result_created_at', 'result_score', 'result_comment',
'expected_response', 'given_response'],
['export_profile', 'session_data', 'convert_session_json', 'decision_time', 'result_config',
'convert_result_json', 'wide_format']],
'wide_json':
- [['experiment_id', 'experiment_name', 'participant_id',
+ [['block_id', 'block_name', 'participant_id',
'participant_country', 'participant_access_info', 'session_start', 'session_end', 'final_score'],
['section_name', 'result_created_at', 'result_score', 'result_comment',
'expected_response', 'given_response'],
['export_profile', 'session_data', 'decision_time', 'result_config', 'wide_format']],
'wide_results':
- [['experiment_name', 'participant_id', 'session_start', 'session_end', 'final_score'],
+ [['block_name', 'participant_id', 'session_start', 'session_end', 'final_score'],
['section_name', 'result_created_at', 'result_score', 'result_comment',
'expected_response', 'given_response'],
['session_data', 'convert_session_json', 'decision_time', 'wide_format']],
'wide_results_json':
- [['experiment_name', 'participant_id', 'session_start', 'session_end', 'final_score'],
+ [['block_name', 'participant_id', 'session_start', 'session_end', 'final_score'],
['section_name', 'result_created_at', 'result_score', 'result_comment',
'expected_response', 'given_response'],
['session_data', 'decision_time', 'result_config', 'wide_format']],
'wide_profile':
- [['experiment_name', 'participant_id',
+ [['block_name', 'participant_id',
'participant_country', 'participant_access_info'],
[],
['export_profile', 'wide_format']],
'long':
- [['experiment_id', 'experiment_name', 'participant_id',
+ [['block_id', 'block_name', 'participant_id',
'participant_country', 'participant_access_info', 'session_start', 'session_end', 'final_score'],
['section_name', 'result_created_at', 'result_score', 'result_comment',
'expected_response', 'given_response'],
['export_profile', 'session_data', 'convert_session_json', 'decision_time', 'result_config',
'convert_result_json']],
'long_json':
- [['experiment_id', 'experiment_name', 'participant_id',
+ [['block_id', 'block_name', 'participant_id',
'participant_country', 'participant_access_info', 'session_start', 'session_end', 'final_score'],
['section_name', 'result_created_at', 'result_score', 'result_comment',
'expected_response', 'given_response'],
['export_profile', 'session_data', 'decision_time', 'result_config'
]],
'long_results':
- [['experiment_name', 'participant_id', 'session_start', 'session_end', 'final_score'],
+ [['block_name', 'participant_id', 'session_start', 'session_end', 'final_score'],
['section_name', 'result_created_at', 'result_score', 'result_comment',
'expected_response', 'given_response'],
['session_data', 'convert_session_json', 'decision_time']],
'long_results_json':
- [['experiment_name', 'participant_id', 'session_start', 'session_end', 'final_score'],
+ [['block_name', 'participant_id', 'session_start', 'session_end', 'final_score'],
['section_name', 'result_created_at', 'result_score', 'result_comment',
'expected_response', 'given_response'],
['session_data', 'decision_time', 'result_config']],
'long_profile':
- [['experiment_name', 'participant_id',
+ [['block_name', 'participant_id',
'participant_country', 'participant_access_info'],
[],
['export_profile']]
@@ -134,7 +134,7 @@ def __init__(self, *args, **kwargs):
'This field will be deprecated in the nearby future. '
'Please use experiment phases for dashboard configuration. (see bottom of form). '
'Legacy behavior: If you check "dashboard", the experiment collection will have a '
- 'dashboard that shows all or a subgroup of related experiments along '
+ 'dashboard that shows all or a subgroup of related blocks along '
'with a description, footer, and about page. If you leave it unchecked, '
'the experiment collection will redirect to the first experiment.')
self.fields['about_content'].widget = MarkdownPreviewTextInput()
@@ -149,7 +149,7 @@ class Media:
css = {"all": ["experiment_series_admin.css"]}
-class ExperimentForm(ModelForm):
+class BlockForm(ModelForm):
def __init__(self, *args, **kwargs):
super(ModelForm, self).__init__(*args, **kwargs)
@@ -198,19 +198,19 @@ class Meta:
fields = ['name', 'slug', 'active', 'rules',
'rounds', 'bonus_points', 'playlists',]
help_texts = {
- 'description': 'A short description of the experiment that will be displayed on the experiment collection page and as a meta description in search engines.',
+ 'description': 'A short description of the block that will be displayed on the experiment collection page and as a meta description in search engines.',
'image': 'An image that will be displayed on the experiment collection page and as a meta image in search engines.',
'consent': 'Upload an HTML (.html) or MARKDOWN (.md) file with a text to ask a user its consent \
- for using the experiment data for this instance of the experiment. \
+ for using the block data for this instance of the block. \
This field will override any consent text loaded from the rules file. \
HTML files also allow django template tags so that the text can be translated',
- 'slug': 'The slug is used to identify the experiment in the URL so you can access it on the web as follows: app.amsterdammusiclab.nl/{slug} \
- It must be unique, lowercase and contain only letters, numbers, and hyphens. Nor can it start with any of the following reserved words: admin, server, experiment, participant, result, section, session, static.',
+ 'slug': 'The slug is used to identify the block in the URL so you can access it on the web as follows: app.amsterdammusiclab.nl/{slug} \
+ It must be unique, lowercase and contain only letters, numbers, and hyphens. Nor can it start with any of the following reserved words: admin, server, block, participant, result, section, session, static.',
}
class Media:
- js = ["experiment_admin.js"]
- css = {"all": ["experiment_admin.css"]}
+ js = ["block_admin.js"]
+ css = {"all": ["block_admin.css"]}
class ExportForm(Form):
diff --git a/backend/experiment/management/commands/bootstrap.py b/backend/experiment/management/commands/bootstrap.py
index e99839991..03ce018b8 100644
--- a/backend/experiment/management/commands/bootstrap.py
+++ b/backend/experiment/management/commands/bootstrap.py
@@ -2,13 +2,13 @@
from django.core.management.base import BaseCommand
from django.contrib.auth.models import User
-from experiment.models import Experiment
+from experiment.models import Block
from section.models import Playlist
from question.questions import create_default_questions
class Command(BaseCommand):
- """ Command for creating a superuser and an experiment if they do not yet exist """
+ """ Command for creating a superuser and an block if they do not yet exist """
def handle(self, *args, **options):
@@ -17,16 +17,15 @@ def handle(self, *args, **options):
if User.objects.count() == 0:
management.call_command('createsuperuser', '--no-input')
print('Created superuser')
- if Experiment.objects.count() == 0:
+ if Block.objects.count() == 0:
playlist = Playlist.objects.create(
name='Empty Playlist'
)
- experiment = Experiment.objects.create(
+ block = Block.objects.create(
name='Goldsmiths Musical Sophistication Index',
rules='RHYTHM_BATTERY_FINAL',
slug='gold-msi',
)
- experiment.playlists.add(playlist)
- experiment.add_default_question_series()
- print('Created default experiment')
-
+ block.playlists.add(playlist)
+ block.add_default_question_series()
+ print('Created default block')
diff --git a/backend/experiment/management/commands/compileplaylist.py b/backend/experiment/management/commands/compileplaylist.py
index 7646f6c61..46e6c3f0e 100644
--- a/backend/experiment/management/commands/compileplaylist.py
+++ b/backend/experiment/management/commands/compileplaylist.py
@@ -49,7 +49,7 @@ def handle(self, *args, **options):
if song_names_option:
with open(join(playlist_dir, song_names_option)) as json_file:
song_names = json.load(json_file)
- experiment_option = options.get('experiment')
+ block_option = options.get('experiment')
with open(join(playlist_dir, 'audiofiles.csv'), 'w+') as f:
csv_writer = csv.writer(f)
for i, audio_file in enumerate(search_critera):
@@ -62,8 +62,8 @@ def handle(self, *args, **options):
if song_names_option:
artist_name = song_names[audio_file_clean]
song_name = basename(audio_file)[:-4]
- elif experiment_option:
- rules = BLOCK_RULES.get(experiment_option)
+ elif block_option:
+ rules = BLOCK_RULES.get(block_option)
info = rules.get_info_playlist(rules, audio_file_clean)
artist_name = info.get('artist')
song_name = info.get('song')
@@ -84,34 +84,34 @@ def handle(self, *args, **options):
csv_writer.writerow(row)
-def calculate_group_tag(filename, experiment, index):
+def calculate_group_tag(filename, block, index):
identifier = splitext(pathsplit(filename)[-1])[0]
- if experiment == 'huang2022':
+ if block == 'huang2022':
parts = identifier.split('.')
group = parts[-1]
tag = None
else:
parts = identifier.split('_')
- if experiment == 'hbat':
- # H-BAT style experiments:
+ if block == 'hbat':
+ # H-BAT style blocks:
# level gets encoded as group
# slower (1) or faster (0) gets encoded as tag
group = int(parts[-1])
tag = 1 if parts[-3] == 'S' else 0
- elif experiment == 'bst':
- # BST experiments:
+ elif block == 'bst':
+ # BST blocks:
# level gets encoded as group
# duple (1) / triple (0) gets encoded as tag
group = int(parts[-1])
tag = 1 if parts[-3] == 'D' else 0
- elif experiment == 'rhdi':
- # rhythm discrimination experiment:
+ elif block == 'rhdi':
+ # rhythm discrimination block:
# standard (1) / deviant (0) gets encoded as group
# tempo (160 - 200) gets encoded as tag
group = 1 if parts[-2] == 'Standard' else 0
tag = int(parts[-1])
- elif experiment == 'cat':
- # categorization experiment
+ elif block == 'cat':
+ # categorization block
# Pair1: 1A, 1B / Pair2: 2A, 2B gets encodes as tag
# Same direction: SAME, Crossed direction: CROSSED gets encoded as group
if identifier[-2:] == '1A':
@@ -123,7 +123,7 @@ def calculate_group_tag(filename, experiment, index):
elif identifier[-2:] == '2B':
tag = '2B'
group = 'SAME' if identifier[0] == 'S' else 'CROSSED'
- elif experiment == 'matching_pairs':
+ elif block == 'matching_pairs':
group = index
tag = pathsplit(pathsplit(filename)[0])[1]
return group, tag
diff --git a/backend/experiment/management/commands/createruleset.py b/backend/experiment/management/commands/createruleset.py
index 7342fbfa3..bc3e22948 100644
--- a/backend/experiment/management/commands/createruleset.py
+++ b/backend/experiment/management/commands/createruleset.py
@@ -4,47 +4,47 @@
class Command(BaseCommand):
- help = 'Creates a new experiment rules class'
+ help = 'Creates a new block rules class'
def handle(self, *args, **options):
- # Ask for the experiment name
- ruleset_name = input("What is the name of your experiment ruleset? (ex. Musical Preferences): ")
+ # Ask for the block name
+ ruleset_name = input("What is the name of your block ruleset? (ex. Musical Preferences): ")
- # Create the experiment rule class
- success = self.create_experiment_rule_class(ruleset_name)
+ # Create the block rule class
+ success = self.create_block_rule_class(ruleset_name)
if not success:
return
- # Add the new experiment to ./experiment/rules/__init__.py
+ # Add the new block to ./experiment/rules/__init__.py
self.register_experiment_rule(ruleset_name, './experiment/rules/__init__.py')
- # Create a basic test file for the experiment
+ # Create a basic test file for the block
self.create_test_file(ruleset_name)
- def create_experiment_rule_class(self, ruleset_name):
- # Get the experiment name in different cases
+ def create_block_rule_class(self, ruleset_name):
+ # Get the block name in different cases
ruleset_name_snake_case, ruleset_name_snake_case_upper, ruleset_name_pascal_case = self.get_ruleset_name_cases(ruleset_name)
- # Create a new file for the experiment rules class
+ # Create a new file for the block rules class
filename = f"./experiment/rules/{ruleset_name_snake_case}.py"
# Check if the file already exists
if os.path.isfile(filename):
- self.stdout.write(self.style.ERROR(f"Experiment ruleset \"{ruleset_name}\" already exists. Exiting without creating file(s)."))
+ self.stdout.write(self.style.ERROR(f"Experiment block ruleset \"{ruleset_name}\" already exists. Exiting without creating file(s)."))
return
# Create the file by copying ./experiment/management/commands/templates/experiment.py
with open(filename, 'w') as f:
with open('./experiment/management/commands/templates/experiment.py', 'r') as template:
f.write(template.read()
- .replace('NewExperimentRuleset', ruleset_name_pascal_case)
+ .replace('NewBlockRuleset', ruleset_name_pascal_case)
.replace('new_block_ruleset', ruleset_name_snake_case)
.replace('NEW_BLOCK_RULESET', ruleset_name_snake_case_upper)
- .replace('New Experiment Ruleset', ruleset_name.title())
+ .replace('New Block Ruleset', ruleset_name.title())
)
- self.stdout.write(self.style.SUCCESS(f"Created {filename} for experiment ruleset \"{ruleset_name}\""))
+ self.stdout.write(self.style.SUCCESS(f"Created {filename} for block ruleset \"{ruleset_name}\""))
return True
@@ -77,10 +77,10 @@ def register_experiment_rule(self, ruleset_name, file_path):
self.stdout.write(self.style.SUCCESS(f"Registered ruleset \"{ruleset_name}\" in {file_path}"))
def create_test_file(self, ruleset_name):
- # Get the experiment name in different cases
+ # Get the block name in different cases
ruleset_name_snake_case, ruleset_name_snake_case_upper, ruleset_name_pascal_case = self.get_ruleset_name_cases(ruleset_name)
- # Create a new file for the experiment class
+ # Create a new file for the block class
filename = f"./experiment/rules/tests/test_{ruleset_name_snake_case}.py"
# Check if the file already exists
@@ -92,20 +92,20 @@ def create_test_file(self, ruleset_name):
with open(filename, 'w') as f:
with open('./experiment/management/commands/templates/test_experiment.py', 'r') as template:
f.write(template.read()
- .replace('NewExperimentRuleset', ruleset_name_pascal_case)
+ .replace('NewBlockRuleset', ruleset_name_pascal_case)
.replace('new_block_ruleset', ruleset_name_snake_case)
.replace('NEW_BLOCK_RULESET', ruleset_name_snake_case_upper)
- .replace('New Experiment Ruleset', ruleset_name.title())
+ .replace('New Block Ruleset', ruleset_name.title())
)
- self.stdout.write(self.style.SUCCESS(f"Created {filename} for experiment {ruleset_name}"))
+ self.stdout.write(self.style.SUCCESS(f"Created {filename} for experiment block {ruleset_name}"))
def get_ruleset_name_cases(self, ruleset_name):
- # Convert experiment name to snake_case and lowercase every word and replace spaces with underscores
+ # Convert block name to snake_case and lowercase every word and replace spaces with underscores
ruleset_name_snake_case = ruleset_name.lower().replace(' ', '_')
ruleset_name_snake_case_upper = ruleset_name_snake_case.upper()
- # Convert experiment name to PascalCase and capitalize every word and remove spaces
+ # Convert block name to PascalCase and capitalize every word and remove spaces
ruleset_name_pascal_case = ruleset_name.title().replace(' ', '')
return ruleset_name_snake_case, ruleset_name_snake_case_upper, ruleset_name_pascal_case
diff --git a/backend/experiment/management/commands/exportexperiment.py b/backend/experiment/management/commands/exportexperiment.py
index 3be6ee15a..43ba79029 100644
--- a/backend/experiment/management/commands/exportexperiment.py
+++ b/backend/experiment/management/commands/exportexperiment.py
@@ -1,19 +1,19 @@
import json
from django.core.management.base import BaseCommand, CommandError
-from experiment.models import Experiment
+from experiment.models import Block
class Command(BaseCommand):
- """Command for exporting experiments using the manage.py script"""
+ """Command for exporting blocks using the manage.py script"""
- help = 'Export experiment data'
+ help = 'Export block data'
def add_arguments(self, parser):
# Positional arguments
- parser.add_argument('experiment_slug',
+ parser.add_argument('block_slug',
type=str,
- help="Experiment slug")
+ help="Block slug")
# Named (optional) arguments
parser.add_argument(
@@ -24,17 +24,17 @@ def add_arguments(self, parser):
)
def handle(self, *args, **options):
- experiment_slug = options['experiment_slug']
+ block_slug = options['block_slug']
indent = options['indent']
try:
- experiment = Experiment.objects.get(slug=experiment_slug)
- except Experiment.DoesNotExist:
+ block = Block.objects.get(slug=block_slug)
+ except Block.DoesNotExist:
raise CommandError(
- 'Experiment "%s" does not exist with slug' % experiment_slug)
+ 'Block "%s" does not exist with slug' % block_slug)
# Optional indent
options = {}
if indent > 0:
options = {'indent': indent}
- self.stdout.write(json.dumps(experiment.export_admin(), **options))
+ self.stdout.write(json.dumps(block.export_admin(), **options))
diff --git a/backend/experiment/management/commands/templates/experiment.py b/backend/experiment/management/commands/templates/experiment.py
index 55e22d631..b26be140b 100644
--- a/backend/experiment/management/commands/templates/experiment.py
+++ b/backend/experiment/management/commands/templates/experiment.py
@@ -10,8 +10,8 @@
from result.utils import prepare_result
-class NewExperimentRuleset(Base):
- ''' An experiment type that could be used to test musical preferences '''
+class NewBlockRuleset(Base):
+ ''' An block type that could be used to test musical preferences '''
ID = 'NEW_BLOCK_RULESET'
contact_email = 'info@example.com'
@@ -32,20 +32,20 @@ def __init__(self):
},
]
- def first_round(self, experiment):
- ''' Provide the first rounds of the experiment,
+ def first_round(self, block):
+ ''' Provide the first rounds of the block,
before session creation
The first_round must return at least one Info or Explainer action
Consent and Playlist are often desired, but optional
'''
# 1. Informed consent (optional)
- consent = Consent(experiment.consent,
+ consent = Consent(block.consent,
title=_('Informed consent'),
confirm=_('I agree'),
deny=_('Stop'))
# 2. Choose playlist (optional, only relevant if there are multiple playlists the participant can choose from)
- playlist = Playlist(experiment.playlists.all())
+ playlist = Playlist(block.playlists.all())
# 3. Explainer (optional)
explainer = Explainer(
@@ -71,7 +71,7 @@ def next_round(self, session):
return actions
elif session.rounds_complete():
- # we have as many results as rounds in this experiment
+ # we have as many results as rounds in this block
# finish session and show Final view
session.finish()
session.save()
@@ -102,7 +102,7 @@ def get_trial(self, session):
view = Trial(
playback=playback,
feedback_form=form,
- title=_('Test experiment'),
+ title=_('Test block'),
config={
'response_time': section.duration,
'listen_first': True
diff --git a/backend/experiment/migrations/0036_add_question_model_data.py b/backend/experiment/migrations/0036_add_question_model_data.py
index ebaba6b0d..b5cc214c3 100644
--- a/backend/experiment/migrations/0036_add_question_model_data.py
+++ b/backend/experiment/migrations/0036_add_question_model_data.py
@@ -1,11 +1,11 @@
-
from django.db import migrations
-from experiment.models import Block as Experiment
from experiment.rules import BLOCK_RULES as EXPERIMENT_RULES
def add_default_question_series(apps, schema_editor):
+ Experiment = apps.get_model("experiment", "Experiment")
+
for experiment in Experiment.objects.all():
if EXPERIMENT_RULES.get(experiment.rules) and not experiment.questionseries_set.all():
experiment.add_default_question_series()
diff --git a/backend/experiment/migrations/0046_alter_socialmediaconfig_content.py b/backend/experiment/migrations/0046_alter_socialmediaconfig_content.py
new file mode 100644
index 000000000..36e37c03c
--- /dev/null
+++ b/backend/experiment/migrations/0046_alter_socialmediaconfig_content.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.11 on 2024-07-03 10:54
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('experiment', '0042_rename_experiment_to_block_squashed_0045_rename_experiment_feedback_block'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='socialmediaconfig',
+ name='content',
+ field=models.TextField(blank=True, default='I scored {points} points in {block_name}!', help_text='Content for social media sharing. Use {points} and {block_name} as placeholders.'),
+ ),
+ ]
diff --git a/backend/experiment/models.py b/backend/experiment/models.py
index 2917d83b8..9274c9ad0 100644
--- a/backend/experiment/models.py
+++ b/backend/experiment/models.py
@@ -11,7 +11,7 @@
from session.models import Session
from typing import Optional
-from .validators import markdown_html_validator, experiment_slug_validator
+from .validators import markdown_html_validator, block_slug_validator
language_choices = [(key, ISO_LANGUAGES[key]) for key in ISO_LANGUAGES.keys()]
language_choices[0] = ('', 'Unset')
@@ -52,15 +52,15 @@ def __str__(self):
class Meta:
verbose_name_plural = "Experiment Collections"
- def associated_experiments(self):
+ def associated_blocks(self):
phases = self.phases.all()
return [
- experiment.experiment for phase in phases for experiment in list(phase.experiments.all())]
+ experiment.block for phase in phases for experiment in list(phase.blocks.all())]
def export_sessions(self):
"""export sessions for this collection"""
all_sessions = Session.objects.none()
- for exp in self.associated_experiments():
+ for exp in self.associated_blocks():
all_sessions |= Session.objects.filter(block=exp).order_by('-started_at')
return all_sessions
@@ -122,7 +122,7 @@ class Block(models.Model):
blank=True,
null=True
)
- slug = models.SlugField(db_index=True, max_length=64, unique=True, validators=[experiment_slug_validator])
+ slug = models.SlugField(db_index=True, max_length=64, unique=True, validators=[block_slug_validator])
url = models.CharField(verbose_name='URL with more information about the block', max_length=100, blank=True, default='')
hashtag = models.CharField(verbose_name='hashtag for social media', max_length=20, blank=True, default='')
active = models.BooleanField(default=True)
@@ -348,8 +348,8 @@ class SocialMediaConfig(models.Model):
content = models.TextField(
blank=True,
- help_text=_("Content for social media sharing. Use {points} and {experiment_name} as placeholders."),
- default="I scored {points} points in {experiment_name}!"
+ help_text=_("Content for social media sharing. Use {points} and {block_name} as placeholders."),
+ default="I scored {points} points in {block_name}!"
)
SOCIAL_MEDIA_CHANNELS = [
@@ -368,17 +368,17 @@ class SocialMediaConfig(models.Model):
)
def get_content(
- self, score: int | None = None, experiment_name: str | None = None
+ self, score: int | None = None, block_name: str | None = None
) -> str:
if self.content:
return self.content
- if not score or not experiment_name:
- raise ValueError("score and experiment_name are required")
+ if not score or not block_name:
+ raise ValueError("score and block_name are required")
- return _("I scored {points} points in {experiment_name}").format(
+ return _("I scored {points} points in {block_name}").format(
score=score,
- experiment_name=experiment_name
+ block_name=block_name
)
def __str__(self):
diff --git a/backend/experiment/rules/base.py b/backend/experiment/rules/base.py
index acf2df4fe..180a1242f 100644
--- a/backend/experiment/rules/base.py
+++ b/backend/experiment/rules/base.py
@@ -56,10 +56,10 @@ def calculate_score(self, result, data):
def get_play_again_url(self, session: Session):
participant_id_url_param = f'?participant_id={session.participant.participant_id_url}' if session.participant.participant_id_url else ""
- return f'/{session.experiment.slug}{participant_id_url_param}'
+ return f'/{session.block.slug}{participant_id_url_param}'
def calculate_intermediate_score(self, session, result):
- """ process result data during a trial (i.e., between next_round calls)
+ """ process result data during a trial (i.e., between next_round calls)
return score
"""
return 0
@@ -128,7 +128,7 @@ def get_single_question(self, session, randomize=False):
Participants will not continue to the next question set until they
have completed their current one.
"""
- questionnaire = unanswered_questions(session.participant, get_questions_from_series(session.experiment.questionseries_set.all()), randomize)
+ questionnaire = unanswered_questions(session.participant, get_questions_from_series(session.block.questionseries_set.all()), randomize)
try:
question = next(questionnaire)
return Trial(
@@ -141,7 +141,7 @@ def get_questionnaire(self, session, randomize=False, cutoff_index=None):
''' Get a list of questions to be asked in succession '''
trials = []
- questions = list(unanswered_questions(session.participant, get_questions_from_series(session.experiment.questionseries_set.all()), randomize, cutoff_index))
+ questions = list(unanswered_questions(session.participant, get_questions_from_series(session.block.questionseries_set.all()), randomize, cutoff_index))
open_questions = len(questions)
if not open_questions:
return None
@@ -152,29 +152,29 @@ def get_questionnaire(self, session, randomize=False, cutoff_index=None):
))
return trials
- def social_media_info(self, experiment, score):
- current_url = f"{settings.RELOAD_PARTICIPANT_TARGET}/{experiment.slug}"
+ def social_media_info(self, block, score):
+ current_url = f"{settings.RELOAD_PARTICIPANT_TARGET}/{block.slug}"
return {
'apps': ['facebook', 'twitter'],
'message': _("I scored %(score)i points on %(url)s") % {
'score': score,
'url': current_url
},
- 'url': experiment.url or current_url,
- 'hashtags': [experiment.hashtag or experiment.slug, "amsterdammusiclab", "citizenscience"]
+ 'url': block.url or current_url,
+ 'hashtags': [block.hashtag or block.slug, "amsterdammusiclab", "citizenscience"]
}
def validate_playlist(self, playlist: None):
errors = []
- # Common validations across experiments
+ # Common validations across blocks
if not playlist:
- errors.append('The experiment must have a playlist.')
+ errors.append('The block must have a playlist.')
return errors
sections = playlist.section_set.all()
if not sections:
- errors.append('The experiment must have at least one section.')
+ errors.append('The block must have at least one section.')
try:
playlist.clean_csv()
diff --git a/backend/experiment/rules/beat_alignment.py b/backend/experiment/rules/beat_alignment.py
index c4e7036bf..deb43c0e4 100644
--- a/backend/experiment/rules/beat_alignment.py
+++ b/backend/experiment/rules/beat_alignment.py
@@ -18,8 +18,8 @@ class BeatAlignment(Base):
ID = 'BEAT_ALIGNMENT'
- def first_round(self, experiment):
- """Create data for the first experiment rounds"""
+ def first_round(self, block):
+ """Create data for the first block rounds"""
# 1. General explainer
explainer = Explainer(
@@ -45,21 +45,21 @@ def first_round(self, experiment):
def next_round(self, session):
"""Get action data for the next round"""
- # If the number of results equals the number of experiment.rounds
+ # If the number of results equals the number of block.rounds
# Close the session and return data for the final_score view
if session.rounds_complete():
# Finish session
session.finish()
session.save()
percentage = int(
- (sum([r.score for r in session.result_set.all()]) / session.experiment.rounds) * 100)
+ (sum([r.score for r in session.result_set.all()]) / session.block.rounds) * 100)
feedback = _('Well done! You’ve answered {} percent correctly!').format(
percentage)
trivia = _('In the UK, over 140.000 people did \
this test when it was first developed?')
final_text = render_feedback_trivia(feedback, trivia)
return final_action_with_optional_button(session, final_text)
-
+
# Next round number, can be used to return different actions
next_round_number = session.get_next_round()
diff --git a/backend/experiment/rules/categorization.py b/backend/experiment/rules/categorization.py
index dd1971fac..eacb195f7 100644
--- a/backend/experiment/rules/categorization.py
+++ b/backend/experiment/rules/categorization.py
@@ -29,7 +29,7 @@ def __init__(self):
},
]
- def first_round(self, experiment):
+ def first_round(self, block):
explainer = Explainer(
instruction="This is a listening experiment in which you have to respond to short sound sequences.",
steps=[],
@@ -37,7 +37,7 @@ def first_round(self, experiment):
)
# Add consent from file or admin (admin has priority)
consent = Consent(
- experiment.consent,
+ block.consent,
title='Informed consent',
confirm='I agree',
deny='Stop',
@@ -80,7 +80,7 @@ def next_round(self, session):
# Calculate round number from passed training rounds
rounds_passed = (session.rounds_passed() -
- int(json_data['training_rounds']))
+ int(json_data['training_rounds']))
# Change phase to enable collecting results of second half of training-1
if session.rounds_passed() == 10:
json_data['phase'] = 'training-1B'
@@ -185,8 +185,8 @@ def next_round(self, session):
feedback = self.get_feedback(session)
return [feedback, explainer]
- elif json_data['phase'] == 'testing':
- if rounds_passed < len(json_data['sequence']):
+ elif json_data['phase'] == 'testing':
+ if rounds_passed < len(json_data['sequence']):
# Determine wether this round has feedback
if rounds_passed in json_data['feedback_sequence']:
return self.get_trial_with_feedback(session)
@@ -258,7 +258,7 @@ def plan_experiment(self, session):
"""
# Check for unfinished sessions older then 24 hours caused by closed browser
- all_sessions = session.experiment.session_set.filter(
+ all_sessions = session.block.session_set.filter(
finished_at=None).filter(
started_at__lte=timezone.now()-timezone.timedelta(hours=24)).exclude(
json_data__contains='ABORTED').exclude(
@@ -276,18 +276,18 @@ def plan_experiment(self, session):
# Count sessions per assigned group
used_groups = [
- session.experiment.session_set.filter(
+ session.block.session_set.filter(
json_data__contains='S1').count(),
- session.experiment.session_set.filter(
+ session.block.session_set.filter(
json_data__contains='S2').count(),
- session.experiment.session_set.filter(
+ session.block.session_set.filter(
json_data__contains='C1').count(),
- session.experiment.session_set.filter(
+ session.block.session_set.filter(
json_data__contains='C2').count()
]
# Get sessions for current participant
- current_sessions = session.experiment.session_set.filter(
+ current_sessions = session.block.session_set.filter(
participant=session.participant)
# Check if this participant already has a previous session
diff --git a/backend/experiment/rules/congosamediff.py b/backend/experiment/rules/congosamediff.py
index f19128a76..c6f11c520 100644
--- a/backend/experiment/rules/congosamediff.py
+++ b/backend/experiment/rules/congosamediff.py
@@ -13,31 +13,31 @@
class CongoSameDiff(Base):
- """ A micro-PROMS inspired experiment that tests the participant's ability to distinguish between different sounds. """
+ """ A micro-PROMS inspired experiment block that tests the participant's ability to distinguish between different sounds. """
ID = 'CONGOSAMEDIFF'
contact_email = 'aml.tunetwins@gmail.com'
def __init__(self):
pass
- def first_round(self, experiment: Block):
- """ Provide the first rounds of the experiment,
+ def first_round(self, block: Block):
+ """ Provide the first rounds of the block,
before session creation
The first_round must return at least one Info or Explainer action
Consent and Playlist are often desired, but optional
"""
- # Do a validity check on the experiment
- errors = self.validate_playlist(experiment.playlists.first())
+ # Do a validity check on the block
+ errors = self.validate_playlist(block.playlists.first())
if errors:
- raise ValueError('The experiment playlist is not valid: \n- ' + '\n- '.join(errors))
+ raise ValueError('The block playlist is not valid: \n- ' + '\n- '.join(errors))
# 1. Playlist
- playlist = Playlist(experiment.playlists.all())
+ playlist = Playlist(block.playlists.all())
# 2. Explainer
explainer = Explainer(
- instruction='Welcome to this Musicality Battery experiment',
+ instruction='Welcome to this Musicality Battery block',
steps=[],
)
@@ -206,11 +206,11 @@ def get_next_trial(
)
form = Form([question])
playback = PlayButton([section], play_once=False)
- experiment_name = session.experiment.name if session.experiment else 'Musicality Battery Block'
+ block_name = session.block.name if session.block else 'Musicality Battery Block'
view = Trial(
playback=playback,
feedback_form=form,
- title=_(experiment_name),
+ title=_(block_name),
config={
'response_time': section.duration,
'listen_first': False,
diff --git a/backend/experiment/rules/duration_discrimination.py b/backend/experiment/rules/duration_discrimination.py
index ea1016486..a80800850 100644
--- a/backend/experiment/rules/duration_discrimination.py
+++ b/backend/experiment/rules/duration_discrimination.py
@@ -30,8 +30,8 @@ class DurationDiscrimination(Base):
increase_difficulty_multiplier = .5
decrease_difficulty_multiplier = 1.5
- def first_round(self, experiment):
- """Create data for the first experiment rounds"""
+ def first_round(self, block):
+ """Create data for the first block rounds"""
explainer = self.intro_explanation()
explainer2 = practice_explainer()
@@ -131,7 +131,7 @@ def next_trial_action(self, session, trial_condition, difficulty):
submits=True
)
# create Result object and save expected result to database
-
+
playback = Autoplay([section])
form = Form([question])
view = Trial(
@@ -172,7 +172,7 @@ def get_task_explanation(self):
def get_introduction(self):
return _('In this test you will hear two time durations for each trial, which are marked by two tones.')
- def finalize_experiment(self, session):
+ def finalize_block(self, session):
''' After 8 turnpoints, finalize experiment
Give participant feedback
'''
@@ -273,7 +273,7 @@ def staircasing_blocks(self, session, trial_action_callback):
difficulty)
if not action:
# action is None if the audio file doesn't exist
- return self.finalize_experiment(session)
+ return self.finalize_block(session)
return action
def get_difficulty(self, session, multiplier=1.0):
@@ -291,7 +291,7 @@ def get_difficulty(self, session, multiplier=1.0):
# return rounded difficulty
# this uses the decimal module, since round() does not work entirely as expected
return int(Decimal(str(current_difficulty)).quantize(Decimal('0'), rounding=ROUND_HALF_UP))
-
+
def last_non_catch_correct(self, previous_results):
""" check if previous responses (before the current one, which is correct)
have been catch or non-catch, and if non-catch, if they were correct
diff --git a/backend/experiment/rules/eurovision_2020.py b/backend/experiment/rules/eurovision_2020.py
index 3b832f9fd..80cb15661 100644
--- a/backend/experiment/rules/eurovision_2020.py
+++ b/backend/experiment/rules/eurovision_2020.py
@@ -29,9 +29,9 @@ def plan_sections(self, session):
old_new_song_set = set(session.playlist.song_ids({'tag__gt': 0}))
# How many sections do we need?
- n_old = round(0.17 * session.experiment.rounds)
- n_new = round(0.33 * session.experiment.rounds) - n_old
- n_free = session.experiment.rounds - 2 * n_old - n_new
+ n_old = round(0.17 * session.block.rounds)
+ n_new = round(0.33 * session.block.rounds) - n_old
+ n_free = session.block.rounds - 2 * n_old - n_new
# Assign songs.
old_songs = random.sample(list(old_new_song_set), k=n_old)
diff --git a/backend/experiment/rules/h_bat.py b/backend/experiment/rules/h_bat.py
index d17f8daf5..1cd895a0b 100644
--- a/backend/experiment/rules/h_bat.py
+++ b/backend/experiment/rules/h_bat.py
@@ -48,19 +48,19 @@ def next_round(self, session):
action = self.next_trial_action(session, trial_condition, 1)
if not action:
# participant answered first trial incorrectly (outlier)
- action = self.finalize_experiment(session)
+ action = self.finalize_block(session)
else:
action = staircasing(session, self.next_trial_action)
if not action:
# action is None if the audio file doesn't exist
- action = self.finalize_experiment(session)
+ action = self.finalize_block(session)
if session.final_score == MAX_TURNPOINTS+1:
# delete result created before this check
session.result_set.order_by('-created_at').first().delete()
- action = self.finalize_experiment(session)
+ action = self.finalize_block(session)
return action
-
- def first_round(self, experiment):
+
+ def first_round(self, block):
explainer = self.intro_explainer()
# Consent with admin text or default text
explainer2 = practice_explainer()
@@ -71,7 +71,7 @@ def first_round(self, experiment):
def next_trial_action(self, session, trial_condition, level=1, *kwargs):
"""
- Get the next actions for the experiment
+ Get the next actions for the block
trial_condition is either 1 or 0
level can be 1 (20 ms) or higher (10, 5, 2.5 ms...)
"""
@@ -111,7 +111,7 @@ def next_trial_action(self, session, trial_condition, level=1, *kwargs):
}
)
return view
-
+
def intro_explainer(self):
return Explainer(
instruction=_(
@@ -132,7 +132,7 @@ def intro_explainer(self):
step_numbers=True,
button_label='Ok'
)
-
+
def response_explainer(self, correct, slower, button_label=_('Next fragment')):
if correct:
if slower:
@@ -153,8 +153,8 @@ def response_explainer(self, correct, slower, button_label=_('Next fragment')):
steps=[],
button_label=button_label
)
-
- def finalize_experiment(self, session):
+
+ def finalize_block(self, session):
""" if either the max_turnpoints have been reached,
or if the section couldn't be found (outlier), stop the experiment
"""
@@ -169,7 +169,7 @@ def finalize_experiment(self, session):
session.finish()
session.save()
return final_action_with_optional_button(session, final_text)
-
+
def get_trivia(self):
return _("When people listen to music, they often perceive an underlying regular pulse, like the woodblock \
in this task. This allows us to clap along with the music at a concert and dance together in synchrony.")
diff --git a/backend/experiment/rules/hbat_bst.py b/backend/experiment/rules/hbat_bst.py
index 5e7ffcdc5..2d7f8d9f6 100644
--- a/backend/experiment/rules/hbat_bst.py
+++ b/backend/experiment/rules/hbat_bst.py
@@ -34,7 +34,7 @@ def intro_explainer(self):
],
button_label='Ok'
)
-
+
def next_trial_action(self, session, trial_condition, level=1):
"""
Get the next actions for the experiment
@@ -73,7 +73,7 @@ def next_trial_action(self, session, trial_condition, level=1):
}
)
return view
-
+
def response_explainer(self, correct, in2, button_label=_('Next fragment')):
if correct:
if in2:
@@ -94,8 +94,8 @@ def response_explainer(self, correct, in2, button_label=_('Next fragment')):
steps=[],
button_label=button_label
)
-
- def finalize_experiment(self, session):
+
+ def finalize_block(self, session):
""" if either the max_turnpoints have been reached,
or if the section couldn't be found (outlier), stop the experiment
"""
diff --git a/backend/experiment/rules/hooked.py b/backend/experiment/rules/hooked.py
index 1b78b130f..186e7ffca 100644
--- a/backend/experiment/rules/hooked.py
+++ b/backend/experiment/rules/hooked.py
@@ -44,8 +44,8 @@ def __init__(self):
{"name": "TIPI", "keys": QUESTION_GROUPS["TIPI"], "randomize": True}, # 5. TIPI (10 questions)
]
- def first_round(self, experiment):
- """Create data for the first experiment rounds."""
+ def first_round(self, block):
+ """Create data for the first block rounds."""
# 1. Explain game.
explainer = Explainer(
@@ -63,15 +63,15 @@ def first_round(self, experiment):
# 2. Add consent from file or admin (admin has priority)
consent = Consent(
- experiment.consent,
+ block.consent,
title=_('Informed consent'),
confirm=_('I agree'),
deny=_('Stop'),
url=self.consent_file
)
-
+
# 3. Choose playlist.
- playlist = Playlist(experiment.playlists.all())
+ playlist = Playlist(block.playlists.all())
return [
consent,
@@ -84,9 +84,9 @@ def next_round(self, session):
json_data = session.load_json_data()
round_number = self.get_current_round(session)
- # If the number of results equals the number of experiment.rounds,
+ # If the number of results equals the number of block.rounds,
# close the session and return data for the final_score view.
- if round_number == session.experiment.rounds:
+ if round_number == session.block.rounds:
# Finish session.
session.finish()
@@ -101,7 +101,7 @@ def next_round(self, session):
final_text=self.final_score_message(session),
rank=self.rank(session),
social=self.social_media_info(
- session.experiment, total_score),
+ session.block, total_score),
show_profile_link=True,
button={
'text': _('Play again'),
@@ -202,7 +202,7 @@ def final_score_message(self, session):
def get_trial_title(self, session, round_number):
return _("Round %(number)d / %(total)d") %\
- {'number': round_number+1, 'total': session.experiment.rounds}
+ {'number': round_number+1, 'total': session.block.rounds}
def plan_sections(self, session, filter_by={}):
"""Set the plan of tracks for a session.
@@ -216,7 +216,7 @@ def plan_sections(self, session, filter_by={}):
# 2/3 of the rounds are SongSync, of which 1/4 old songs, 3/4 "free"
# 1/3 of the rounds are "heard before", of which 1/2 old songs
# e.g. 30 rounds -> 20 SongSync with 5 songs to be repeated later
- n_rounds = session.experiment.rounds
+ n_rounds = session.block.rounds
n_old = round(0.17 * n_rounds)
n_new = round(0.17 * n_rounds)
n_free = n_rounds - 2 * n_old - n_new
diff --git a/backend/experiment/rules/huang_2022.py b/backend/experiment/rules/huang_2022.py
index 216855755..bf595a64d 100644
--- a/backend/experiment/rules/huang_2022.py
+++ b/backend/experiment/rules/huang_2022.py
@@ -48,17 +48,17 @@ def __init__(self):
},
]
- def first_round(self, experiment):
- """Create data for the first experiment rounds."""
+ def first_round(self, block):
+ """Create data for the first block rounds."""
# Add consent from file or admin (admin has priority)
consent = Consent(
- experiment.consent,
+ block.consent,
title=_('Informed consent'),
confirm=_('I agree'),
deny=_('Stop'),
url='consent/consent_huang2021.html'
)
- playlist = Playlist(experiment.playlists.all())
+ playlist = Playlist(block.playlists.all())
return [
consent,
@@ -70,17 +70,17 @@ def feedback_info(self):
info['header'] = _("Any remarks or questions (optional):")
info['thank_you'] = _("Thank you for your feedback!")
return info
-
+
def next_round(self, session):
"""Get action data for the next round"""
- # If the number of results equals the number of experiment.rounds,
+ # If the number of results equals the number of block.rounds,
# close the session and return data for the final_score view.
json_data = session.load_json_data()
# Get next round number and initialise actions list. Two thirds of
# rounds will be song_sync; the remainder heard_before.
round_number = self.get_current_round(session)
- total_rounds = session.experiment.rounds
+ total_rounds = session.block.rounds
# Collect actions.
actions = []
@@ -94,7 +94,7 @@ def next_round(self, session):
form = Form(form=[BooleanQuestion(
key='audio_check1',
choices={'no': _('No'), 'yes': _('Yes')},
- result_id=prepare_result('audio_check1', session,
+ result_id=prepare_result('audio_check1', session,
scoring_rule='BOOLEAN'),
submits=True,
style=STYLE_BOOLEAN_NEGATIVE_FIRST)])
@@ -123,7 +123,7 @@ def next_round(self, session):
session.save()
return Redirect(settings.HOMEPAGE)
if last_result.score == 1:
- # Start experiment: plan sections and show explainers
+ # Start block: plan sections and show explainers
self.plan_sections(session)
# Show explainers and go to SongSync
explainer = Explainer(
@@ -157,10 +157,10 @@ def next_round(self, session):
heard_before_offset = len(plan['song_sync_sections'])
- # show score
+ # show score
score = self.get_score(session, round_number)
actions.append(score)
-
+
# SongSync rounds
if round_number < heard_before_offset:
actions.extend(self.next_song_sync_action(session))
@@ -172,7 +172,7 @@ def next_round(self, session):
self.next_heard_before_action(session))
elif heard_before_offset < round_number < total_rounds:
actions.append(
- self.next_heard_before_action(session))
+ self.next_heard_before_action(session))
else:
questionnaire = self.get_questionnaire(session)
if questionnaire:
@@ -185,7 +185,7 @@ def next_round(self, session):
else:
return [self.finalize(session)]
return actions
-
+
def finalize(self, session):
session.finish()
session.save()
@@ -196,7 +196,7 @@ def finalize(self, session):
show_profile_link=True,
feedback_info=self.feedback_info()
)
-
+
def final_score_message(self, session):
"""Create final score message for given session"""
@@ -248,4 +248,3 @@ def get_test_playback():
show_animation=True
)
return playback
-
\ No newline at end of file
diff --git a/backend/experiment/rules/kuiper_2020.py b/backend/experiment/rules/kuiper_2020.py
index 95731f92c..12123493f 100644
--- a/backend/experiment/rules/kuiper_2020.py
+++ b/backend/experiment/rules/kuiper_2020.py
@@ -30,9 +30,9 @@ def plan_sections(self, session):
old_new_song_set = set(session.playlist.song_ids({'tag__gt': 0}))
# How many sections do we need?
- n_old = round(0.17 * session.experiment.rounds)
- n_new = round(0.33 * session.experiment.rounds) - n_old
- n_free = session.experiment.rounds - 2 * n_old - n_new
+ n_old = round(0.17 * session.block.rounds)
+ n_new = round(0.33 * session.block.rounds) - n_old
+ n_free = session.block.rounds - 2 * n_old - n_new
# Assign songs.
old_songs = random.sample(old_new_song_set, k=n_old)
diff --git a/backend/experiment/rules/matching_pairs.py b/backend/experiment/rules/matching_pairs.py
index 0ef6e6426..93f399407 100644
--- a/backend/experiment/rules/matching_pairs.py
+++ b/backend/experiment/rules/matching_pairs.py
@@ -36,17 +36,17 @@ def __init__(self):
},
]
- def first_round(self, experiment):
+ def first_round(self, block):
# Add consent from file or admin (admin has priority)
consent = Consent(
- experiment.consent,
+ block.consent,
title=_('Informed consent'),
confirm=_('I agree'),
deny=_('Stop'),
url='consent/consent_matching_pairs.html'
)
# 2. Choose playlist.
- playlist = Playlist(experiment.playlists.all())
+ playlist = Playlist(block.playlists.all())
explainer = Explainer(
instruction='',
@@ -64,7 +64,7 @@ def first_round(self, experiment):
playlist,
explainer
]
-
+
def next_round(self, session):
if session.rounds_passed() < 1:
trials = self.get_questionnaire(session)
@@ -79,7 +79,7 @@ def next_round(self, session):
return [trial]
else:
# final score saves the result from the cleared board into account
- social_info = self.social_media_info(session.experiment, session.final_score)
+ social_info = self.social_media_info(session.block, session.final_score)
social_info['apps'].append('clipboard')
score = Final(
session,
@@ -104,7 +104,7 @@ def select_sections(self, session):
random.shuffle(pairs)
selected_pairs = pairs[:self.num_pairs]
session.save_json_data({'pairs': pairs[self.num_pairs:]})
- originals = session.playlist.section_set.filter(group__in=selected_pairs, tag='Original')
+ originals = session.playlist.section_set.filter(group__in=selected_pairs, tag='Original')
degradations = json_data.get('degradations')
if not degradations:
degradations = ['Original', '1stDegradation', '2ndDegradation']
@@ -141,7 +141,7 @@ def get_matching_pairs_trial(self, session):
def calculate_score(self, result, data):
''' not used in this experiment '''
pass
-
+
def calculate_intermediate_score(self, session, result):
''' will be called every time two cards have been turned '''
result_data = json.loads(result)
@@ -168,5 +168,3 @@ def calculate_intermediate_score(self, session, result):
prepare_result('move', session, json_data=result_data,
score=score, given_response=given_response)
return score
-
-
diff --git a/backend/experiment/rules/matching_pairs_lite.py b/backend/experiment/rules/matching_pairs_lite.py
index 4f4a53a15..4542012ad 100644
--- a/backend/experiment/rules/matching_pairs_lite.py
+++ b/backend/experiment/rules/matching_pairs_lite.py
@@ -3,7 +3,7 @@
from django.utils.translation import gettext_lazy as _
from .matching_pairs import MatchingPairsGame
-from experiment.actions import Final, Playlist, Info
+from experiment.actions import Playlist, Info
from experiment.actions.utils import final_action_with_optional_button
@@ -14,9 +14,9 @@ class MatchingPairsLite(MatchingPairsGame):
score_feedback_display = 'small-bottom-right'
contact_email = 'aml.tunetwins@gmail.com'
- def first_round(self, experiment):
+ def first_round(self, block):
# 2. Choose playlist.
- playlist = Playlist(experiment.playlists.all())
+ playlist = Playlist(block.playlists.all())
info = Info('',
heading='Press start to enter the game',
button_label='Start')
diff --git a/backend/experiment/rules/musical_preferences.py b/backend/experiment/rules/musical_preferences.py
index 6b39050ea..e07b0fa35 100644
--- a/backend/experiment/rules/musical_preferences.py
+++ b/backend/experiment/rules/musical_preferences.py
@@ -52,16 +52,16 @@ def __init__(self):
},
]
- def first_round(self, experiment):
-
+ def first_round(self, block):
+
consent = Consent(
- experiment.consent,
+ block.consent,
title=_('Informed consent'),
confirm=_('I consent and continue.'),
deny=_('I do not consent.'),
url=self.consent_file
)
- playlist = Playlist(experiment.playlists.all())
+ playlist = Playlist(block.playlists.all())
explainer = Explainer(
instruction=_('Welcome to the Musical Preferences experiment!'),
steps=[
@@ -118,7 +118,7 @@ def next_round(self, session):
else:
session.decrement_round()
if last_result.question_key == 'audio_check1':
- playback = get_test_playback()
+ playback = get_test_playback()
html = HTML(body=render_to_string('html/huang_2022/audio_check.html'))
form = Form(form=[BooleanQuestion(
key='audio_check2',
@@ -175,7 +175,7 @@ def next_round(self, session):
}))
)
actions = [feedback]
- elif n_songs == session.experiment.rounds + 1:
+ elif n_songs == session.block.rounds + 1:
like_results = session.result_set.filter(question_key='like_song')
known_songs = session.result_set.filter(
question_key='know_song', score=2).count()
@@ -231,7 +231,7 @@ def next_round(self, session):
playback=playback,
feedback_form=form,
title=_('Song %(round)s/%(total)s') % {
- 'round': n_songs, 'total': session.experiment.rounds},
+ 'round': n_songs, 'total': session.block.rounds},
config={
'response_time': section.duration + .1,
}
@@ -245,9 +245,9 @@ def calculate_score(self, result, data):
else:
return super().calculate_score(result, data)
- def social_media_info(self, experiment, top_participant, known_songs, n_songs, top_all):
+ def social_media_info(self, block, top_participant, known_songs, n_songs, top_all):
current_url = "{}/{}".format(settings.RELOAD_PARTICIPANT_TARGET,
- experiment.slug
+ block.slug
)
def format_songs(songs): return ', '.join(
@@ -261,14 +261,14 @@ def format_songs(songs): return ', '.join(
'n_songs': n_songs,
'top_all': format_songs(top_all)
},
- 'url': experiment.url or current_url,
- 'hashtags': [experiment.hashtag or experiment.slug, "amsterdammusiclab", "citizenscience"]
+ 'url': block.url or current_url,
+ 'hashtags': [block.hashtag or block.slug, "amsterdammusiclab", "citizenscience"]
}
def get_final_view(self, session, top_participant, known_songs, n_songs, top_all):
- # finalize experiment
+ # finalize block
social_info = self.social_media_info(
- session.experiment,
+ session.block,
top_participant,
known_songs,
n_songs,
diff --git a/backend/experiment/rules/rhythm_battery_final.py b/backend/experiment/rules/rhythm_battery_final.py
index 1b9ce090b..87a61c90f 100644
--- a/backend/experiment/rules/rhythm_battery_final.py
+++ b/backend/experiment/rules/rhythm_battery_final.py
@@ -34,7 +34,7 @@ def __init__(self):
},
]
- def first_round(self, experiment):
+ def first_round(self, block):
explainer = Explainer(
_('Finally, we would like to ask you to answer some questions about your musical and demographic background.'),
steps=[
diff --git a/backend/experiment/rules/rhythm_battery_intro.py b/backend/experiment/rules/rhythm_battery_intro.py
index 6ae5a09d5..df98f60ad 100644
--- a/backend/experiment/rules/rhythm_battery_intro.py
+++ b/backend/experiment/rules/rhythm_battery_intro.py
@@ -127,7 +127,7 @@ def intro_explainer(self):
button_label=_("Continue")
)
- def first_round(self, experiment):
+ def first_round(self, block):
intro_explainer = self.intro_explainer()
explainer = Explainer(
instruction=_(
diff --git a/backend/experiment/rules/rhythm_discrimination.py b/backend/experiment/rules/rhythm_discrimination.py
index 9734cfcb4..64d8a4e7c 100644
--- a/backend/experiment/rules/rhythm_discrimination.py
+++ b/backend/experiment/rules/rhythm_discrimination.py
@@ -80,8 +80,8 @@
class RhythmDiscrimination(Base):
ID = 'RHYTHM_DISCRIMINATION'
- def first_round(self, experiment):
- """Create data for the first experiment rounds"""
+ def first_round(self, block):
+ """Create data for the first block rounds"""
explainer = intro_explainer()
explainer2 = practice_explainer()
@@ -112,7 +112,7 @@ def next_trial_actions(session, round_number):
return actions
if len(plan) == round_number-1:
- return [finalize_experiment(session)]
+ return [finalize_block(session)]
condition = plan[round_number-1]
@@ -213,10 +213,10 @@ def plan_stimuli(session):
{'rhythm': STIMULI['practice']['nonmetric']['deviant'],
'tag': random.choice(tempi), 'group': '0'},
]
- experiment = metric_deviants + metric_standard + \
+ block = metric_deviants + metric_standard + \
nonmetric_deviants + nonmetric_standard
- random.shuffle(experiment)
- plan = practice + experiment
+ random.shuffle(block)
+ plan = practice + block
session.save_json_data({'plan': plan})
session.save()
@@ -259,7 +259,7 @@ def response_explainer(correct, same, button_label=_('Next fragment')):
)
-def finalize_experiment(session):
+def finalize_block(session):
# we had 4 practice trials and 60 experiment trials
percentage = (sum([res.score for res in session.result_set.all()]
) / session.result_set.count()) * 100
diff --git a/backend/experiment/rules/speech2song.py b/backend/experiment/rules/speech2song.py
index 918b437e0..589007195 100644
--- a/backend/experiment/rules/speech2song.py
+++ b/backend/experiment/rules/speech2song.py
@@ -45,7 +45,7 @@ def __init__(self):
},
]
- def first_round(self, experiment):
+ def first_round(self, block):
explainer = Explainer(
instruction=_("This is an experiment about an auditory illusion."),
steps=[
@@ -57,14 +57,14 @@ def first_round(self, experiment):
)
# Add consent from file or admin (admin has priority)
consent = Consent(
- experiment.consent,
+ block.consent,
title=_('Informed consent'),
confirm=_('I agree'),
deny=_('Stop'),
url='consent/consent_speech2song.html'
)
- playlist = Playlist(experiment.playlists.all())
+ playlist = Playlist(block.playlists.all())
return [
consent,
diff --git a/backend/experiment/rules/tafc.py b/backend/experiment/rules/tafc.py
index 4651d280e..665fe791b 100644
--- a/backend/experiment/rules/tafc.py
+++ b/backend/experiment/rules/tafc.py
@@ -1,7 +1,7 @@
"""
-Setup experiment data in the admin panel
+Setup block data in the admin panel
-* Choose a slug for the experiment ('tafc')
+* Choose a slug for the block ('tafc')
* Upload sound files
* Find the root directory name of the uploaded sound files. It is backend/upload on your local machine. On a server, ask the administrator.
@@ -21,7 +21,7 @@
* Save
* Create experiment
- * Admin panel -> Experiments -> Add
+ * Admin panel -> Blocks -> Add
* Choose name: TwoAlternativeForced
* Slug: tafc
* Rules: TwoAlternativeForced
@@ -59,7 +59,7 @@ def __init__(self):
"randomize": False
}]
- def first_round(self, experiment):
+ def first_round(self, block):
"""
Returns a list of actions. Actions used here: Explainer, Consent.
"""
@@ -72,7 +72,7 @@ def first_round(self, experiment):
# Add consent, text in admin
consent = Consent(
- experiment.consent,
+ block.consent,
title='Informed consent',
confirm='I agree',
deny='Stop',
diff --git a/backend/experiment/rules/tests/test_base.py b/backend/experiment/rules/tests/test_base.py
index bf00bce89..0bf1eb559 100644
--- a/backend/experiment/rules/tests/test_base.py
+++ b/backend/experiment/rules/tests/test_base.py
@@ -1,6 +1,6 @@
from django.test import TestCase
from django.conf import settings
-from experiment.models import Experiment
+from experiment.models import Block
from session.models import Session
from participant.models import Participant
from section.models import Playlist
@@ -12,13 +12,13 @@ class BaseTest(TestCase):
def test_social_media_info(self):
reload_participant_target = settings.RELOAD_PARTICIPANT_TARGET
slug = 'music-lab'
- experiment = Experiment.objects.create(
+ block = Block.objects.create(
name='Music Lab',
slug=slug,
)
base = Base()
social_media_info = base.social_media_info(
- experiment=experiment,
+ block=block,
score=100,
)
@@ -32,12 +32,12 @@ def test_social_media_info(self):
self.assertEqual(social_media_info['hashtags'], ['music-lab', 'amsterdammusiclab', 'citizenscience'])
def test_get_play_again_url(self):
- experiment = Experiment.objects.create(
+ block = Block.objects.create(
name='Music Lab',
slug='music-lab',
)
session = Session.objects.create(
- experiment=experiment,
+ block=block,
participant=Participant.objects.create(),
)
base = Base()
@@ -45,7 +45,7 @@ def test_get_play_again_url(self):
self.assertEqual(play_again_url, '/music-lab')
def test_get_play_again_url_with_participant_id(self):
- experiment = Experiment.objects.create(
+ block = Block.objects.create(
name='Music Lab',
slug='music-lab',
)
@@ -53,7 +53,7 @@ def test_get_play_again_url_with_participant_id(self):
participant_id_url='42',
)
session = Session.objects.create(
- experiment=experiment,
+ block=block,
participant=participant,
)
base = Base()
@@ -64,8 +64,8 @@ def test_validate_playlist(self):
base = Base()
playlist = None
errors = base.validate_playlist(playlist)
- self.assertEqual(errors, ['The experiment must have a playlist.'])
+ self.assertEqual(errors, ['The block must have a playlist.'])
playlist = Playlist.objects.create()
errors = base.validate_playlist(playlist)
- self.assertEqual(errors, ['The experiment must have at least one section.'])
+ self.assertEqual(errors, ['The block must have at least one section.'])
diff --git a/backend/experiment/rules/tests/test_beat_alignment.py b/backend/experiment/rules/tests/test_beat_alignment.py
index 7a373134e..9c44d39e7 100644
--- a/backend/experiment/rules/tests/test_beat_alignment.py
+++ b/backend/experiment/rules/tests/test_beat_alignment.py
@@ -1,6 +1,6 @@
from django.test import TestCase
-from experiment.models import Experiment
+from experiment.models import Block
from result.models import Result
from section.models import Playlist
from session.models import Session
@@ -32,9 +32,9 @@ def setUpTestData(cls):
playlist.csv = csv
playlist.update_sections()
# rules is BeatAlignment.ID in beat_alignment.py
- cls.experiment = Experiment.objects.create(
+ cls.block = Block.objects.create(
rules='BEAT_ALIGNMENT', slug='ba', rounds=13)
- cls.experiment.playlists.add(playlist)
+ cls.block.playlists.add(playlist)
def load_json(self, response):
'''Asserts response status 200 OK, asserts content type json, loads and returns response.content json in a dictionary'''
@@ -42,7 +42,7 @@ def load_json(self, response):
self.assertEqual(response['content-type'], 'application/json')
return json.loads(response.content)
- def test_experiment(self):
+ def test_block(self):
response = self.client.get('/experiment/ba/')
response_json = self.load_json(response)
self.assertTrue({'id', 'slug', 'name', 'class_name', 'rounds',
@@ -70,7 +70,7 @@ def test_experiment(self):
self.assertTrue(response_json['status'], 'ok')
# Can throw an error if some of the tags in playlist not zero, cannot find a section to play
- data = {"experiment_id": self.experiment.id, "playlist_id": "",
+ data = {"block_id": self.block.id, "playlist_id": "",
"json_data": "", "csrfmiddlewaretoken": csrf_token}
response = self.client.post('/session/create/', data)
response_json = self.load_json(response)
@@ -84,7 +84,7 @@ def test_experiment(self):
rounds = response_json.get('next_round')
assert len(rounds) == 4
assert rounds[0].get('title') == 'Example 1'
- rounds_n = self.experiment.rounds # Default 10
+ rounds_n = self.block.rounds # Default 10
views_exp = ['TRIAL_VIEW']*(rounds_n)
for i in range(len(views_exp)):
response = self.client.post(
diff --git a/backend/experiment/rules/tests/test_congosamediff.py b/backend/experiment/rules/tests/test_congosamediff.py
index a5957b571..7af5d1d68 100644
--- a/backend/experiment/rules/tests/test_congosamediff.py
+++ b/backend/experiment/rules/tests/test_congosamediff.py
@@ -2,7 +2,7 @@
from django.test import TestCase
-from experiment.models import Experiment
+from experiment.models import Block
from participant.models import Participant
from result.models import Result
from section.models import Playlist as PlaylistModel, Section, Song
@@ -43,13 +43,13 @@ def setUpTestData(self):
self.playlist.csv = self.section_csv
self.playlist.update_sections()
self.participant = Participant.objects.create()
- self.experiment = Experiment.objects.create(
+ self.block = Block.objects.create(
name='CongoSameDiff',
slug='congosamediff',
rounds=4,
)
self.session = Session.objects.create(
- experiment=self.experiment,
+ block=self.block,
participant=self.participant,
playlist=self.playlist
)
@@ -61,10 +61,10 @@ def test_initializes_correctly(self):
def test_first_round(self):
congo_same_diff = CongoSameDiff()
- experiment = Experiment(id=1, name='CongoSameDiff', slug='congosamediff_first_round', rounds=4)
- experiment.save()
- experiment.playlists.set([self.playlist])
- actions = congo_same_diff.first_round(experiment)
+ block = Block(id=1, name='CongoSameDiff', slug='congosamediff_first_round', rounds=4)
+ block.save()
+ block.playlists.set([self.playlist])
+ actions = congo_same_diff.first_round(block)
assert len(actions) >= 1
assert isinstance(actions[0], PlaylistAction)
assert isinstance(actions[1], Explainer)
@@ -122,8 +122,8 @@ def test_get_final_round(self):
def test_throw_exception_if_trial_without_group(self):
congo_same_diff = CongoSameDiff()
- experiment = Experiment(id=1, name='CongoSameDiff', slug='congosamediff_first_round', rounds=4)
- experiment.save()
+ block = Block(id=1, name='CongoSameDiff', slug='congosamediff_first_round', rounds=4)
+ block.save()
playlist = PlaylistModel.objects.create(name='CongoSameDiff')
Section.objects.create(
playlist=playlist,
@@ -133,14 +133,14 @@ def test_throw_exception_if_trial_without_group(self):
tag='practice_contour',
group=''
)
- experiment.playlists.set([playlist])
+ block.playlists.set([playlist])
with self.assertRaisesRegex(ValueError, "Section no_group should have a group value"):
- congo_same_diff.first_round(experiment)
+ congo_same_diff.first_round(block)
def test_throw_exception_if_trial_group_not_int(self):
congo_same_diff = CongoSameDiff()
- experiment = Experiment(id=1, name='CongoSameDiff', slug='congosamediff_first_round', rounds=4)
- experiment.save()
+ block = Block(id=1, name='CongoSameDiff', slug='congosamediff_first_round', rounds=4)
+ block.save()
playlist = PlaylistModel.objects.create(name='CongoSameDiff')
Section.objects.create(
playlist=playlist,
@@ -150,14 +150,14 @@ def test_throw_exception_if_trial_group_not_int(self):
tag='practice_contour',
group='not_int_42'
)
- experiment.playlists.set([playlist])
+ block.playlists.set([playlist])
with self.assertRaisesRegex(ValueError, "Section group_not_int should have a group value containing only digits"):
- congo_same_diff.first_round(experiment)
+ congo_same_diff.first_round(block)
def test_throw_exception_if_no_practice_rounds(self):
congo_same_diff = CongoSameDiff()
- experiment = Experiment(id=1, name='CongoSameDiff', slug='congosamediff_first_round', rounds=4)
- experiment.save()
+ block = Block(id=1, name='CongoSameDiff', slug='congosamediff_first_round', rounds=4)
+ block.save()
playlist = PlaylistModel.objects.create(name='CongoSameDiff')
Section.objects.create(
playlist=playlist,
@@ -167,14 +167,14 @@ def test_throw_exception_if_no_practice_rounds(self):
tag='',
group='1'
)
- experiment.playlists.set([playlist])
+ block.playlists.set([playlist])
with self.assertRaisesRegex(ValueError, 'At least one section should have the tag "practice"'):
- congo_same_diff.first_round(experiment)
+ congo_same_diff.first_round(block)
def test_throw_exception_if_no_normal_rounds(self):
congo_same_diff = CongoSameDiff()
- experiment = Experiment(id=1, name='CongoSameDiff', slug='congosamediff_first_round', rounds=4)
- experiment.save()
+ block = Block(id=1, name='CongoSameDiff', slug='congosamediff_first_round', rounds=4)
+ block.save()
playlist = PlaylistModel.objects.create(name='CongoSameDiff')
Section.objects.create(
playlist=playlist,
@@ -184,14 +184,14 @@ def test_throw_exception_if_no_normal_rounds(self):
tag='practice_contour',
group='42'
)
- experiment.playlists.set([playlist])
+ block.playlists.set([playlist])
with self.assertRaisesRegex(ValueError, 'At least one section should not have the tag "practice"'):
- congo_same_diff.first_round(experiment)
+ congo_same_diff.first_round(block)
def test_throw_combined_exceptions_if_multiple_errors(self):
congo_same_diff = CongoSameDiff()
- experiment = Experiment(id=1, name='CongoSameDiff', slug='congosamediff_first_round', rounds=4)
- experiment.save()
+ block = Block(id=1, name='CongoSameDiff', slug='congosamediff_first_round', rounds=4)
+ block.save()
playlist = PlaylistModel.objects.create(name='CongoSameDiff')
Section.objects.create(
playlist=playlist,
@@ -217,9 +217,9 @@ def test_throw_combined_exceptions_if_multiple_errors(self):
tag='practice_contour',
group='42'
)
- experiment.playlists.set([playlist])
- with self.assertRaisesRegex(ValueError, "The experiment playlist is not valid: \n- Section group_not_int should have a group value containing only digits\n- Section no_group should have a group value containing only digits\n- At least one section should not have the tag \"practice\""):
- congo_same_diff.first_round(experiment)
+ block.playlists.set([playlist])
+ with self.assertRaisesRegex(ValueError, "The block playlist is not valid: \n- Section group_not_int should have a group value containing only digits\n- Section no_group should have a group value containing only digits\n- At least one section should not have the tag \"practice\""):
+ congo_same_diff.first_round(block)
def test_get_total_trials_count(self):
congo_same_diff = CongoSameDiff()
@@ -332,4 +332,4 @@ def test_invalid_parameters(self):
congo_same_diff.get_participant_group_variant(-1, 1, 3, 3) # Negative participant ID
congo_same_diff.get_participant_group_variant(1, -1, 3, 3) # Negative group number
congo_same_diff.get_participant_group_variant(1, 1, -1, 3) # Negative groups amount
- congo_same_diff.get_participant_group_variant(1, 1, 3, -1) # Negative variants amount
\ No newline at end of file
+ congo_same_diff.get_participant_group_variant(1, 1, 3, -1) # Negative variants amount
diff --git a/backend/experiment/rules/tests/test_duration_discrimination.py b/backend/experiment/rules/tests/test_duration_discrimination.py
index d509faf67..dd42ed713 100644
--- a/backend/experiment/rules/tests/test_duration_discrimination.py
+++ b/backend/experiment/rules/tests/test_duration_discrimination.py
@@ -1,6 +1,6 @@
from django.test import TestCase
-from experiment.models import Experiment
+from experiment.models import Block
from experiment.rules import Anisochrony, DurationDiscrimination
from participant.models import Participant
from section.models import Playlist, Section
@@ -15,9 +15,9 @@ def setUpTestData(cls):
cls.participant = Participant.objects.create()
cls.playlist = Playlist.objects.get(name='DurationDiscrimination')
cls.playlist.update_sections()
- cls.experiment = Experiment.objects.get(name='DurationDiscrimination')
+ cls.block = Block.objects.get(name='DurationDiscrimination')
cls.session = Session.objects.create(
- experiment=cls.experiment,
+ block=cls.block,
participant=cls.participant,
playlist=cls.playlist
)
@@ -47,9 +47,9 @@ def setUpTestData(cls):
cls.participant = Participant.objects.create()
cls.playlist = Playlist.objects.get(name='Anisochrony')
cls.playlist.update_sections()
- cls.experiment = Experiment.objects.get(name='Anisochrony')
+ cls.block = Block.objects.get(name='Anisochrony')
cls.session = Session.objects.create(
- experiment=cls.experiment,
+ block=cls.block,
participant=cls.participant,
playlist=cls.playlist
)
diff --git a/backend/experiment/rules/tests/test_hbat.py b/backend/experiment/rules/tests/test_hbat.py
index e73725700..a13231a41 100644
--- a/backend/experiment/rules/tests/test_hbat.py
+++ b/backend/experiment/rules/tests/test_hbat.py
@@ -1,6 +1,6 @@
from django.test import TestCase
-from experiment.models import Experiment
+from experiment.models import Block
from experiment.rules import HBat, BST
from participant.models import Participant
from result.models import Result
@@ -16,9 +16,9 @@ def setUpTestData(cls):
cls.participant = Participant.objects.create()
cls.playlist = Playlist.objects.get(name='HBAT-BIT')
cls.playlist.update_sections()
- cls.experiment = Experiment.objects.get(name='HBAT-BIT')
+ cls.block = Block.objects.get(name='HBAT-BIT')
cls.session = Session.objects.create(
- experiment=cls.experiment,
+ block=cls.block,
participant=cls.participant,
playlist=cls.playlist
)
@@ -48,9 +48,9 @@ def setUpTestData(cls):
cls.participant = Participant.objects.create()
cls.playlist = Playlist.objects.get(name='HBAT-BST')
cls.playlist.update_sections()
- cls.experiment = Experiment.objects.get(name='HBAT-BST')
+ cls.block = Block.objects.get(name='HBAT-BST')
cls.session = Session.objects.create(
- experiment=cls.experiment,
+ block=cls.block,
participant=cls.participant,
playlist=cls.playlist
)
diff --git a/backend/experiment/rules/tests/test_hooked.py b/backend/experiment/rules/tests/test_hooked.py
index 0430ee0f3..e13a1d7b2 100644
--- a/backend/experiment/rules/tests/test_hooked.py
+++ b/backend/experiment/rules/tests/test_hooked.py
@@ -1,6 +1,6 @@
from django.test import TestCase
-from experiment.models import Experiment
+from experiment.models import Block
from question.musicgens import MUSICGENS_17_W_VARIANTS
from participant.models import Participant
from result.models import Result
@@ -17,11 +17,11 @@ def setUpTestData(cls):
cls.participant = Participant.objects.create()
def test_hooked(self):
- experiment = Experiment.objects.create(name='Hooked', rules='HOOKED', rounds=3)
+ block = Block.objects.create(name='Hooked', rules='HOOKED', rounds=3)
playlist = Playlist.objects.get(name='Eurovision 2021')
playlist.update_sections()
session = Session.objects.create(
- experiment=experiment,
+ block=block,
participant=self.participant,
playlist=playlist
)
@@ -37,35 +37,35 @@ def test_hooked(self):
assert action is not None
def test_eurovision(self):
- experiment = Experiment.objects.get(name='Hooked-Eurovision')
+ block = Block.objects.get(name='Hooked-Eurovision')
playlist = Playlist.objects.get(name='Eurovision 2021')
playlist.update_sections()
session = Session.objects.create(
- experiment=experiment,
+ block=block,
participant=self.participant,
playlist=playlist
)
rules = session.block_rules()
- for i in range(0, experiment.rounds):
+ for i in range(0, block.rounds):
actions = rules.next_round(session)
assert actions
def test_thats_my_song(self):
musicgen_keys = [q.key for q in MUSICGENS_17_W_VARIANTS]
- experiment = Experiment.objects.get(name='ThatsMySong')
+ block = Block.objects.get(name='ThatsMySong')
playlist = Playlist.objects.get(name='ThatsMySong')
playlist.update_sections()
session = Session.objects.create(
- experiment=experiment,
+ block=block,
participant=self.participant,
playlist=playlist
)
rules = session.block_rules()
assert rules.feedback_info() is None
- for i in range(0, experiment.rounds):
+ for i in range(0, block.rounds):
actions = rules.next_round(session)
- if i == experiment.rounds + 1:
+ if i == block.rounds + 1:
assert len(actions) == 2
assert actions[1].ID == 'FINAL'
elif i == 0:
@@ -117,11 +117,11 @@ def test_thats_my_song(self):
assert actions[2].feedback_form.form[0].key == 'heard_before'
def test_hooked_china(self):
- experiment = Experiment.objects.get(name='Hooked-China')
+ block = Block.objects.get(name='Hooked-China')
playlist = Playlist.objects.get(name='普通话')
playlist.update_sections()
session = Session.objects.create(
- experiment=experiment,
+ block=block,
participant=self.participant,
playlist=playlist
)
diff --git a/backend/experiment/rules/tests/test_matching_pairs.py b/backend/experiment/rules/tests/test_matching_pairs.py
index f5576a476..1c3a3745d 100644
--- a/backend/experiment/rules/tests/test_matching_pairs.py
+++ b/backend/experiment/rules/tests/test_matching_pairs.py
@@ -2,7 +2,7 @@
from django.test import TestCase
-from experiment.models import Experiment
+from experiment.models import Block
from participant.models import Participant
from result.models import Result
from section.models import Playlist
@@ -34,9 +34,9 @@ def setUpTestData(cls):
cls.playlist.csv = section_csv
cls.playlist.update_sections()
cls.participant = Participant.objects.create()
- cls.experiment = Experiment.objects.create(rules='MATCHING_PAIRS', slug='mpairs', rounds=42)
+ cls.block = Block.objects.create(rules='MATCHING_PAIRS', slug='mpairs', rounds=42)
cls.session = Session.objects.create(
- experiment=cls.experiment,
+ block=cls.block,
participant=cls.participant,
playlist=cls.playlist
)
diff --git a/backend/experiment/rules/tests/test_matching_pairs_fixed.py b/backend/experiment/rules/tests/test_matching_pairs_fixed.py
index aff39b98b..e5c77a4c6 100644
--- a/backend/experiment/rules/tests/test_matching_pairs_fixed.py
+++ b/backend/experiment/rules/tests/test_matching_pairs_fixed.py
@@ -1,6 +1,6 @@
from django.test import TestCase
-from experiment.models import Experiment
+from experiment.models import Block
from participant.models import Participant
from section.models import Playlist, Section
from session.models import Session
@@ -10,7 +10,7 @@
class MatchingPairsFixedTest(TestCase):
@classmethod
def setUpTestData(self):
- self.experiment = Experiment.objects.create(
+ self.block = Block.objects.create(
name='Test Experiment Matching Pairs Fixed',
slug='test-experiment-matching-pairs-fixed',
rules='matching_pairs_lite'
@@ -73,7 +73,7 @@ def test_select_sections_original_degraded(self):
unique_hash='testhash'
)
self.session = Session.objects.create(
- experiment=self.experiment,
+ block=self.block,
participant=self.participant,
playlist=self.playlist,
)
@@ -158,7 +158,7 @@ def test_select_sections_original_original(self):
unique_hash='testhash'
)
self.session = Session.objects.create(
- experiment=self.experiment,
+ block=self.block,
participant=self.participant,
playlist=self.playlist,
)
diff --git a/backend/experiment/rules/tests/test_matching_pairs_variants.py b/backend/experiment/rules/tests/test_matching_pairs_variants.py
index e4091702d..e731d5875 100644
--- a/backend/experiment/rules/tests/test_matching_pairs_variants.py
+++ b/backend/experiment/rules/tests/test_matching_pairs_variants.py
@@ -1,7 +1,7 @@
from django.test import TestCase
from experiment.actions import Trial
-from experiment.models import Experiment
+from experiment.models import Block
from participant.models import Participant
from section.models import Playlist
from session.models import Session
@@ -28,17 +28,17 @@ def setUp(self):
self.participant = Participant.objects.create()
def test_lite_version(self):
- experiment = Experiment.objects.create(
+ block = Block.objects.create(
rules='MATCHING_PAIRS_LITE', slug='mpairs_lite'
)
session = Session.objects.create(
- experiment=experiment,
+ block=block,
participant=self.participant,
playlist=self.playlist
)
first_trial = session.block_rules().get_matching_pairs_trial(session)
another_session = Session.objects.create(
- experiment=experiment,
+ block=block,
participant=self.participant,
playlist=self.playlist
)
@@ -49,16 +49,16 @@ def test_lite_version(self):
assert first_trial.playback.sections != second_trial.playback.sections
def test_fixed_order_sections(self):
- experiment = Experiment.objects.create(
+ block = Block.objects.create(
rules='MATCHING_PAIRS_FIXED', slug='mpairs_fixed')
session = Session.objects.create(
- experiment=experiment,
+ block=block,
participant=self.participant,
playlist=self.playlist
)
first_trial = session.block_rules().get_matching_pairs_trial(session)
another_session = Session.objects.create(
- experiment=experiment,
+ block=block,
participant=self.participant,
playlist=self.playlist
)
diff --git a/backend/experiment/rules/tests/test_musical_preferences.py b/backend/experiment/rules/tests/test_musical_preferences.py
index ee70f1ae5..2c618e3cd 100644
--- a/backend/experiment/rules/tests/test_musical_preferences.py
+++ b/backend/experiment/rules/tests/test_musical_preferences.py
@@ -3,7 +3,7 @@
from experiment.rules.musical_preferences import MusicalPreferences
-from experiment.models import Experiment
+from experiment.models import Block
from participant.models import Participant
from result.models import Result
from section.models import Playlist
@@ -12,7 +12,7 @@
class MusicalPreferencesTest(TestCase):
fixtures = ['playlist', 'experiment']
-
+
@classmethod
def setUpTestData(cls):
cls.participant = Participant.objects.create()
@@ -24,9 +24,9 @@ def setUpTestData(cls):
"AwfulArtist,AwfulSong,0.0,10.0,bat/artist5.mp3,0,0,0\n")
cls.playlist.csv = csv
cls.playlist.update_sections()
- cls.experiment = Experiment.objects.create(name='MusicalPreferences', rounds=5)
+ cls.block = Block.objects.create(name='MusicalPreferences', rounds=5)
cls.session = Session.objects.create(
- experiment=cls.experiment,
+ block=cls.block,
participant=cls.participant,
playlist=cls.playlist
)
@@ -59,7 +59,7 @@ def test_preferred_songs_results_without_section(self):
)
other_session = Session.objects.create(
- experiment=self.experiment,
+ block=self.block,
participant=self.participant,
playlist=self.playlist
)
@@ -74,8 +74,8 @@ def test_preferred_songs_results_without_section(self):
mp = MusicalPreferences()
# Go to the last round (top_all = ... caused the error)
- for i in range(self.session.experiment.rounds + 1):
+ for i in range(self.session.block.rounds + 1):
self.session.increment_round()
-
+
# get_preferred_songs() called by top_all = ... in the final round should not raise an error
- mp.next_round(self.session)
\ No newline at end of file
+ mp.next_round(self.session)
diff --git a/backend/experiment/rules/tests/test_rhythm_battery_final.py b/backend/experiment/rules/tests/test_rhythm_battery_final.py
index 1f8577ae9..6c09a321a 100644
--- a/backend/experiment/rules/tests/test_rhythm_battery_final.py
+++ b/backend/experiment/rules/tests/test_rhythm_battery_final.py
@@ -1,14 +1,14 @@
from django.test import TestCase
from django.core.files.uploadedfile import SimpleUploadedFile
from experiment.actions import Explainer
-from experiment.models import Experiment
+from experiment.models import Block
from experiment.rules.rhythm_battery_final import RhythmBatteryFinal
class TestRhythmBatteryFinal(TestCase):
@classmethod
def setUpTestData(cls):
- Experiment.objects.create(
+ Block.objects.create(
name='test_md',
slug='MARKDOWN',
consent=SimpleUploadedFile(
@@ -20,8 +20,8 @@ def test_init(self):
self.assertEqual(rhythm_final.ID, 'RHYTHM_BATTERY_FINAL')
def test_first_round(self):
- experiment = Experiment.objects.first()
+ block = Block.objects.first()
goldMSI = RhythmBatteryFinal()
- actions = goldMSI.first_round(experiment)
+ actions = goldMSI.first_round(block)
self.assertIsInstance(actions[0], Explainer)
diff --git a/backend/experiment/rules/tests/test_rhythm_battery_intro.py b/backend/experiment/rules/tests/test_rhythm_battery_intro.py
index 8a7152953..ec5312e77 100644
--- a/backend/experiment/rules/tests/test_rhythm_battery_intro.py
+++ b/backend/experiment/rules/tests/test_rhythm_battery_intro.py
@@ -2,7 +2,7 @@
from section.models import Section, Song, Playlist as PlaylistModel
from participant.models import Participant
from session.models import Session
-from experiment.models import Experiment
+from experiment.models import Block
from experiment.rules.rhythm_battery_intro import RhythmBatteryIntro
from experiment.actions import Explainer, Final, Playback, Trial, Form
from experiment.actions.form import Form
@@ -25,25 +25,25 @@ def setUp(self):
filename="not/to_be_found.mp3",
tag=0
)
- self.experiment = Experiment.objects.create(
+ self.block = Block.objects.create(
name='test',
slug='TEST',
)
participant = Participant.objects.create()
self.session = Session.objects.create(
- experiment=Experiment.objects.first(),
+ block=Block.objects.first(),
participant=participant,
playlist=playlist
)
def test_first_round(self):
listening_conditions = RhythmBatteryIntro()
- actions = listening_conditions.first_round(self.experiment)
+ actions = listening_conditions.first_round(self.block)
self.assertIsInstance(actions[0], Explainer)
def test_next_round_first_round(self):
listening_conditions = RhythmBatteryIntro()
- listening_conditions.first_round(self.experiment)
+ listening_conditions.first_round(self.block)
actions = listening_conditions.next_round(self.session)
self.assertIsInstance(actions[0], Trial)
@@ -54,7 +54,7 @@ def test_next_round_first_round(self):
def test_next_round_final_round(self):
listening_conditions = RhythmBatteryIntro()
- listening_conditions.first_round(self.experiment)
+ listening_conditions.first_round(self.block)
listening_conditions.next_round(self.session)
listening_conditions.next_round(self.session)
listening_conditions.next_round(self.session)
diff --git a/backend/experiment/rules/tests/test_rhythm_discrimination.py b/backend/experiment/rules/tests/test_rhythm_discrimination.py
index bc4b935ab..c1461e1b6 100644
--- a/backend/experiment/rules/tests/test_rhythm_discrimination.py
+++ b/backend/experiment/rules/tests/test_rhythm_discrimination.py
@@ -1,6 +1,6 @@
from django.test import TestCase
-from experiment.models import Experiment
+from experiment.models import Block
from experiment.rules.rhythm_discrimination import next_trial_actions, plan_stimuli
from participant.models import Participant
from result.models import Result
@@ -16,16 +16,16 @@ def setUpTestData(cls):
cls.participant = Participant.objects.create()
cls.playlist = Playlist.objects.get(name='RhythmDiscrimination')
cls.playlist.update_sections()
- cls.experiment = Experiment.objects.get(name='RhythmDiscrimination')
+ cls.block = Block.objects.get(name='RhythmDiscrimination')
cls.session = Session.objects.create(
- experiment=cls.experiment,
+ block=cls.block,
participant=cls.participant,
playlist=cls.playlist
)
-
+
def test_next_trial_actions(self):
plan_stimuli(self.session)
self.session.final_score = 1
self.session.save()
trial = next_trial_actions(self.session, 6)
- assert trial
\ No newline at end of file
+ assert trial
diff --git a/backend/experiment/rules/tests/test_speech2song.py b/backend/experiment/rules/tests/test_speech2song.py
index 26118c58e..397ef86a2 100644
--- a/backend/experiment/rules/tests/test_speech2song.py
+++ b/backend/experiment/rules/tests/test_speech2song.py
@@ -1,6 +1,6 @@
from django.test import TestCase
-from experiment.models import Experiment
+from experiment.models import Block
from participant.models import Participant
from result.models import Result
from section.models import Playlist
@@ -29,10 +29,10 @@ def setUpTestData(cls):
cls.playlist.csv = section_csv
cls.playlist.update_sections()
cls.participant = Participant.objects.create()
- cls.experiment = Experiment.objects.create(
+ cls.block = Block.objects.create(
rules='SPEECH_TO_SONG', slug='s2s', rounds=42)
cls.session = Session.objects.create(
- experiment=cls.experiment,
+ block=cls.block,
participant=cls.participant,
playlist=cls.playlist
)
diff --git a/backend/experiment/rules/tests/test_visual_matching_pairs.py b/backend/experiment/rules/tests/test_visual_matching_pairs.py
index b417a9241..858eac9dd 100644
--- a/backend/experiment/rules/tests/test_visual_matching_pairs.py
+++ b/backend/experiment/rules/tests/test_visual_matching_pairs.py
@@ -1,6 +1,6 @@
from django.test import TestCase
-from experiment.models import Experiment
+from experiment.models import Block
from experiment.rules import VisualMatchingPairsGame
from participant.models import Participant
from section.models import Playlist
@@ -28,10 +28,10 @@ def setUpTestData(self):
self.sections = list(self.playlist.section_set.filter(tag__contains='vmp'))
self.participant = Participant.objects.create()
- self.experiment = Experiment.objects.create(rules='VISUAL_MATCHING_PAIRS', slug='vmpairs', rounds=3)
+ self.block = Block.objects.create(rules='VISUAL_MATCHING_PAIRS', slug='vmpairs', rounds=3)
self.session = Session.objects.create(
- experiment=self.experiment,
+ block=self.block,
participant=self.participant,
playlist=self.playlist
)
@@ -75,4 +75,4 @@ def test_next_round_logic(self):
self.session.increment_round()
next_round = self.rules.next_round(self.session)
self.assertEqual(len(next_round), 1)
- self.assertEqual(next_round[0].title, 'Visual Tune twins')
\ No newline at end of file
+ self.assertEqual(next_round[0].title, 'Visual Tune twins')
diff --git a/backend/experiment/rules/thats_my_song.py b/backend/experiment/rules/thats_my_song.py
index eec629657..aa67bb41e 100644
--- a/backend/experiment/rules/thats_my_song.py
+++ b/backend/experiment/rules/thats_my_song.py
@@ -50,26 +50,26 @@ def get_info_playlist(self, filename):
'group': decade
}
- def first_round(self, experiment):
- actions = super().first_round(experiment)
+ def first_round(self, block):
+ actions = super().first_round(block)
# skip Consent and Playlist action
return [actions[2]]
- def next_round(self, session):
+ def next_round(self, session):
"""Get action data for the next round"""
json_data = session.load_json_data()
round_number = self.get_current_round(session)
- # If the number of results equals the number of experiment.rounds,
+ # If the number of results equals the number of block.rounds,
# close the session and return data for the final_score view.
- if round_number == session.experiment.rounds + self.round_modifier:
+ if round_number == session.block.rounds + self.round_modifier:
# Finish session.
session.finish()
session.save()
# Return a score and final score action.
- social_info = self.social_media_info(session.experiment, session.final_score)
+ social_info = self.social_media_info(session.block, session.final_score)
return [
self.get_score(session, round_number - self.round_modifier),
Final(
diff --git a/backend/experiment/rules/toontjehoger_1_mozart.py b/backend/experiment/rules/toontjehoger_1_mozart.py
index d525cd429..e7117f113 100644
--- a/backend/experiment/rules/toontjehoger_1_mozart.py
+++ b/backend/experiment/rules/toontjehoger_1_mozart.py
@@ -37,8 +37,8 @@ class ToontjeHoger1Mozart(Base):
ANSWER_URL1 = "/images/experiments/toontjehoger/mozart-effect1-answer.webp"
ANSWER_URL2 = "/images/experiments/toontjehoger/mozart-effect2-answer.webp"
- def first_round(self, experiment):
- """Create data for the first experiment rounds."""
+ def first_round(self, block):
+ """Create data for the first block rounds."""
# 1. Explain game.
explainer = Explainer(
diff --git a/backend/experiment/rules/toontjehoger_2_preverbal.py b/backend/experiment/rules/toontjehoger_2_preverbal.py
index c71c912eb..82cb4d18a 100644
--- a/backend/experiment/rules/toontjehoger_2_preverbal.py
+++ b/backend/experiment/rules/toontjehoger_2_preverbal.py
@@ -58,8 +58,8 @@ def validate_playlist(self, playlist: Playlist):
return errors
- def first_round(self, experiment):
- """Create data for the first experiment rounds."""
+ def first_round(self, block):
+ """Create data for the first block rounds."""
# 1. Explain game.
explainer = Explainer(
@@ -97,7 +97,7 @@ def get_spectrogram_info(self):
button_label="Volgende",
)
return info
-
+
def next_round(self, session):
"""Get action data for the next round"""
@@ -114,7 +114,7 @@ def next_round(self, session):
# Final
return self.get_final_round(session)
-
+
def get_score(self, session, rounds_passed):
# Feedback
last_result = session.last_result()
@@ -139,7 +139,7 @@ def get_score(self, session, rounds_passed):
config = {'show_total_score': True}
score = Score(session, config=config, feedback=feedback)
return [score]
-
+
def get_round1(self, session):
# Question
key = 'expected_spectrogram'
@@ -212,7 +212,7 @@ def get_round1_playback(self, session):
title=self.TITLE
)
return [trial]
-
+
def get_round2(self, round, session):
# Get sections
@@ -260,10 +260,10 @@ def get_round2(self, round, session):
title=self.TITLE,
)
return [trial]
-
+
def calculate_score(self, result, data):
return self.SCORE_CORRECT if result.expected_response == result.given_response else self.SCORE_WRONG
-
+
def get_final_round(self, session):
# Finish session.
diff --git a/backend/experiment/rules/toontjehoger_3_plink.py b/backend/experiment/rules/toontjehoger_3_plink.py
index 6295bc483..0373c5880 100644
--- a/backend/experiment/rules/toontjehoger_3_plink.py
+++ b/backend/experiment/rules/toontjehoger_3_plink.py
@@ -61,15 +61,15 @@ def validate_era_and_mood(self, sections):
)
return errors
- def first_round(self, experiment):
- """Create data for the first experiment rounds."""
+ def first_round(self, block):
+ """Create data for the first block rounds."""
# 1. Explain game.
explainer = Explainer(
instruction="Muziekherkenning",
steps=[
Step("Je krijgt {} zeer korte muziekfragmenten te horen.".format(
- experiment.rounds)),
+ block.rounds)),
Step("Ken je het nummer? Noem de juiste artiest en titel!"),
Step(
"Weet je het niet? Beantwoord dan extra vragen over de tijdsperiode en emotie van het nummer.")
@@ -91,8 +91,8 @@ def next_round(self, session):
if rounds_passed == 0:
return self.get_plink_round(session)
- # Round 2-experiments.rounds
- if rounds_passed < session.experiment.rounds:
+ # Round 2-blocks.rounds
+ if rounds_passed < session.block.rounds:
return self.get_plink_round(session, present_score=True)
# Final
@@ -158,7 +158,7 @@ def get_score_view(self, session):
config = {'show_total_score': True}
round_number = session.get_relevant_results(['plink']).count() - 1
score_title = "Ronde %(number)d / %(total)d" %\
- {'number': round_number+1, 'total': session.experiment.rounds}
+ {'number': round_number+1, 'total': session.block.rounds}
return Score(session, config=config, feedback=feedback, score=score, title=score_title)
def get_plink_round(self, session, present_score=False):
diff --git a/backend/experiment/rules/toontjehoger_4_absolute.py b/backend/experiment/rules/toontjehoger_4_absolute.py
index c0cffea11..fc9689341 100644
--- a/backend/experiment/rules/toontjehoger_4_absolute.py
+++ b/backend/experiment/rules/toontjehoger_4_absolute.py
@@ -26,8 +26,8 @@ class ToontjeHoger4Absolute(Base):
# number of songs (each with a,b,c version) in the playlist
PLAYLIST_ITEMS = 13
- def first_round(self, experiment):
- """Create data for the first experiment rounds."""
+ def first_round(self, block):
+ """Create data for the first block rounds."""
# 1. Explain game.
explainer = Explainer(
@@ -57,7 +57,7 @@ def next_round(self, session):
return self.get_round(session)
# Round 2 - 4
- if rounds_passed < session.experiment.rounds:
+ if rounds_passed < session.block.rounds:
return [*self.get_score(session), *self.get_round(session)]
# Final
@@ -163,9 +163,9 @@ def get_final_round(self, session):
# Final
final_text = "Dat bleek toch even lastig!"
- if session.final_score >= session.experiment.rounds * 0.8 * self.SCORE_CORRECT:
+ if session.final_score >= session.block.rounds * 0.8 * self.SCORE_CORRECT:
final_text = "Goed gedaan! Jouw absolute gehoor is uitstekend!"
- elif session.final_score >= session.experiment.rounds * 0.5 * self.SCORE_CORRECT:
+ elif session.final_score >= session.block.rounds * 0.5 * self.SCORE_CORRECT:
final_text = "Goed gedaan! Jouw absolute gehoor is best OK!"
final = Final(
diff --git a/backend/experiment/rules/toontjehoger_5_tempo.py b/backend/experiment/rules/toontjehoger_5_tempo.py
index 3f0d965ac..89bbe7438 100644
--- a/backend/experiment/rules/toontjehoger_5_tempo.py
+++ b/backend/experiment/rules/toontjehoger_5_tempo.py
@@ -24,8 +24,8 @@ class ToontjeHoger5Tempo(Base):
SCORE_CORRECT = 20
SCORE_WRONG = 0
- def first_round(self, experiment):
- """Create data for the first experiment rounds."""
+ def first_round(self, block):
+ """Create data for the first block rounds."""
# 1. Explain game.
explainer = Explainer(
@@ -57,7 +57,7 @@ def next_round(self, session):
return self.get_round(session, rounds_passed)
# Round 2
- if rounds_passed < session.experiment.rounds:
+ if rounds_passed < session.block.rounds:
return [*self.get_score(session), *self.get_round(session, rounds_passed)]
# Final
@@ -232,9 +232,9 @@ def get_final_round(self, session):
# Final
final_text = "Dat bleek toch even lastig!"
- if session.final_score >= session.experiment.rounds * 0.8 * self.SCORE_CORRECT:
+ if session.final_score >= session.block.rounds * 0.8 * self.SCORE_CORRECT:
final_text = "Goed gedaan! Jouw timing is uitstekend!"
- elif session.final_score >= session.experiment.rounds * 0.5 * self.SCORE_CORRECT:
+ elif session.final_score >= session.block.rounds * 0.5 * self.SCORE_CORRECT:
final_text = "Goed gedaan! Jouw timing is best OK!"
final = Final(
diff --git a/backend/experiment/rules/toontjehoger_6_relative.py b/backend/experiment/rules/toontjehoger_6_relative.py
index 4b8f96a38..f4b734e94 100644
--- a/backend/experiment/rules/toontjehoger_6_relative.py
+++ b/backend/experiment/rules/toontjehoger_6_relative.py
@@ -38,8 +38,8 @@ def validate_playlist(self, playlist: Playlist):
errors.append('The sections should have the tags a, b, c')
return errors
- def first_round(self, experiment):
- """Create data for the first experiment rounds."""
+ def first_round(self, block):
+ """Create data for the first block rounds."""
# 1. Explain game.
explainer = Explainer(
diff --git a/backend/experiment/rules/toontjehoger_home.py b/backend/experiment/rules/toontjehoger_home.py
index 3189ddf2b..c655b8d40 100644
--- a/backend/experiment/rules/toontjehoger_home.py
+++ b/backend/experiment/rules/toontjehoger_home.py
@@ -70,12 +70,12 @@ class ToontjeHogerHome(Base):
),
]
- def first_round(self, experiment):
- """Create data for the first experiment round"""
+ def first_round(self, block):
+ """Create data for the first block round"""
# Session history
sessions = self.get_sessions(participant) # To be fixed in the future
- next_experiment_slug = self.get_next_experiment_slug(sessions)
+ next_block_slug = self.get_next_block_slug(sessions)
# Score
score = self.get_score(sessions)
@@ -95,10 +95,10 @@ def first_round(self, experiment):
score_class = "diamond"
# Main button shows
- # - 'next experiment' when user does not have completed all experiments yet
- # - 'random experiment' when user has completed all experiments
- main_button_label = "Volgende experiment" if next_experiment_slug else "Willekeurig experiment"
- main_button_url = "/{}".format(next_experiment_slug) if next_experiment_slug else random.choice([
+ # - 'next experiment' when user does not have completed all blocks yet
+ # - 'random experiment' when user has completed all blocks
+ main_button_label = "Volgende experiment" if next_block_slug else "Willekeurig experiment"
+ main_button_url = "/{}".format(next_block_slug) if next_block_slug else random.choice([
experiment.slug for experiment in self.EXPERIMENT_DATA])
# Home
@@ -143,25 +143,25 @@ def get_score(self, sessions):
def get_sessions(self, participant):
from session.models import Session
- from experiment.models import Experiment
+ from experiment.models import Block
- experiment_slugs = [
- experiment.slug for experiment in self.EXPERIMENT_DATA]
+ block_slugs = [
+ block.slug for block in self.EXPERIMENT_DATA]
- experiment_ids = Experiment.objects.filter(slug__in=experiment_slugs)
+ block_ids = Block.objects.filter(slug__in=block_slugs)
sessions = Session.objects.filter(participant=participant,
- experiment_id__in=experiment_ids)
+ block_id__in=block_ids)
return sessions
- def get_next_experiment_slug(self, sessions):
- experiment_slugs = [
- experiment.slug for experiment in self.EXPERIMENT_DATA]
+ def get_next_block_slug(self, sessions):
+ block_slugs = [
+ block.slug for block in self.EXPERIMENT_DATA]
for session in sessions:
- if session.experiment.slug in experiment_slugs:
- experiment_slugs.remove(session.experiment.slug)
+ if session.block.slug in block_slugs:
+ block_slugs.remove(session.block.slug)
- if len(experiment_slugs) > 0:
- return experiment_slugs[0]
+ if len(block_slugs) > 0:
+ return block_slugs[0]
return ''
diff --git a/backend/experiment/rules/toontjehogerkids_1_mozart.py b/backend/experiment/rules/toontjehogerkids_1_mozart.py
index 4ae595e83..0131bbd62 100644
--- a/backend/experiment/rules/toontjehogerkids_1_mozart.py
+++ b/backend/experiment/rules/toontjehogerkids_1_mozart.py
@@ -15,8 +15,8 @@ class ToontjeHogerKids1Mozart(ToontjeHoger1Mozart):
ANSWER_URL1 = "/images/experiments/toontjehogerkids/mozart-effect1-answer.webp"
ANSWER_URL2 = "/images/experiments/toontjehogerkids/mozart-effect2-answer.webp"
- def first_round(self, experiment):
- """Create data for the first experiment rounds."""
+ def first_round(self, block):
+ """Create data for the first block rounds."""
# 1. Explain game.
explainer = Explainer(
diff --git a/backend/experiment/rules/toontjehogerkids_2_preverbal.py b/backend/experiment/rules/toontjehogerkids_2_preverbal.py
index ad5c03fd9..044fe0b5a 100644
--- a/backend/experiment/rules/toontjehogerkids_2_preverbal.py
+++ b/backend/experiment/rules/toontjehogerkids_2_preverbal.py
@@ -12,8 +12,8 @@
class ToontjeHogerKids2Preverbal(ToontjeHoger2Preverbal):
ID = 'TOONTJE_HOGER_KIDS_2_PREVERBAL'
- def first_round(self, experiment):
- """Create data for the first experiment rounds."""
+ def first_round(self, block):
+ """Create data for the first block rounds."""
# 1. Explain game.
explainer = Explainer(
diff --git a/backend/experiment/rules/toontjehogerkids_3_plink.py b/backend/experiment/rules/toontjehogerkids_3_plink.py
index 047bea70f..655ada16b 100644
--- a/backend/experiment/rules/toontjehogerkids_3_plink.py
+++ b/backend/experiment/rules/toontjehogerkids_3_plink.py
@@ -27,14 +27,14 @@ class ToontjeHogerKids3Plink(ToontjeHoger3Plink):
def validate_era_and_mood(self, sections):
return []
- def first_round(self, experiment):
- """Create data for the first experiment rounds."""
+ def first_round(self, block):
+ """Create data for the first block rounds."""
explainer = Explainer(
instruction="Muziekherkenning",
steps=[
Step("Je hoort zo een heel kort stukje van {} liedjes.".format(
- experiment.rounds)),
+ block.rounds)),
Step("Herken je de liedjes? Kies dan steeds de juiste artiest en titel!"),
Step(
"Weet je het niet zeker? Doe dan maar een gok.")
@@ -73,7 +73,7 @@ def get_score_view(self, session):
config = {'show_total_score': True}
round_number = session.get_relevant_results(['plink']).count() - 1
score_title = "Ronde %(number)d / %(total)d" %\
- {'number': round_number+1, 'total': session.experiment.rounds}
+ {'number': round_number+1, 'total': session.block.rounds}
return Score(session, config=config, feedback=feedback, score=score, title=score_title)
def get_plink_round(self, session, present_score=False):
diff --git a/backend/experiment/rules/toontjehogerkids_4_absolute.py b/backend/experiment/rules/toontjehogerkids_4_absolute.py
index 97090ce7f..ae1df8d5f 100644
--- a/backend/experiment/rules/toontjehogerkids_4_absolute.py
+++ b/backend/experiment/rules/toontjehogerkids_4_absolute.py
@@ -9,8 +9,8 @@ class ToontjeHogerKids4Absolute(ToontjeHoger4Absolute):
ID = 'TOONTJE_HOGER_KIDS_4_ABSOLUTE'
PLAYLIST_ITEMS = 12
- def first_round(self, experiment):
- """Create data for the first experiment rounds."""
+ def first_round(self, block):
+ """Create data for the first block rounds."""
# 1. Explain game.
explainer = Explainer(
@@ -44,7 +44,7 @@ def get_final_round(self, session):
# Final
final_text = "Best lastig!"
- if session.final_score >= session.experiment.rounds * 0.5 * self.SCORE_CORRECT:
+ if session.final_score >= session.block.rounds * 0.5 * self.SCORE_CORRECT:
final_text = "Goed gedaan!"
final = Final(
diff --git a/backend/experiment/rules/toontjehogerkids_5_tempo.py b/backend/experiment/rules/toontjehogerkids_5_tempo.py
index b96c5fbdf..090ad71a5 100644
--- a/backend/experiment/rules/toontjehogerkids_5_tempo.py
+++ b/backend/experiment/rules/toontjehogerkids_5_tempo.py
@@ -13,8 +13,8 @@
class ToontjeHogerKids5Tempo(ToontjeHoger5Tempo):
ID = 'TOONTJE_HOGER_KIDS_5_TEMPO'
- def first_round(self, experiment):
- """Create data for the first experiment rounds."""
+ def first_round(self, block):
+ """Create data for the first block rounds."""
# 1. Explain game.
explainer = Explainer(
@@ -105,7 +105,7 @@ def get_final_round(self, session):
# Final
final_text = "Best lastig!"
- if session.final_score >= session.experiment.rounds * 0.5 * self.SCORE_CORRECT:
+ if session.final_score >= session.block.rounds * 0.5 * self.SCORE_CORRECT:
final_text = "Goed gedaan!"
final = Final(
diff --git a/backend/experiment/rules/toontjehogerkids_6_relative.py b/backend/experiment/rules/toontjehogerkids_6_relative.py
index b637e748c..35a1e0d8a 100644
--- a/backend/experiment/rules/toontjehogerkids_6_relative.py
+++ b/backend/experiment/rules/toontjehogerkids_6_relative.py
@@ -11,8 +11,8 @@
class ToontjeHogerKids6Relative(ToontjeHoger6Relative):
ID = 'TOONTJE_HOGER_KIDS_6_RELATIVE'
- def first_round(self, experiment):
- """Create data for the first experiment rounds."""
+ def first_round(self, block):
+ """Create data for the first block rounds."""
# 1. Explain game.
explainer = Explainer(
diff --git a/backend/experiment/rules/visual_matching_pairs.py b/backend/experiment/rules/visual_matching_pairs.py
index 493f5c596..1775ea681 100644
--- a/backend/experiment/rules/visual_matching_pairs.py
+++ b/backend/experiment/rules/visual_matching_pairs.py
@@ -33,17 +33,17 @@ def __init__(self):
},
]
- def first_round(self, experiment):
+ def first_round(self, block):
# Add consent from file or admin (admin has priority)
consent = Consent(
- experiment.consent,
+ block.consent,
title=_('Informed consent'),
confirm=_('I agree'),
deny=_('Stop'),
url='consent/consent_matching_pairs.html'
)
- playlist = Playlist(experiment.playlists.all())
+ playlist = Playlist(block.playlists.all())
explainer = Explainer(
instruction='',
@@ -63,7 +63,7 @@ def first_round(self, experiment):
]
def next_round(self, session):
- if session.rounds_passed() < 1:
+ if session.rounds_passed() < 1:
trials = self.get_questionnaire(session)
if trials:
intro_questions = Explainer(
@@ -78,7 +78,7 @@ def next_round(self, session):
session.final_score += session.result_set.filter(
question_key='visual_matching_pairs').last().score
session.save()
- social_info = self.social_media_info(session.experiment, session.final_score)
+ social_info = self.social_media_info(session.block, session.final_score)
social_info['apps'].append('clipboard')
score = Final(
session,
diff --git a/backend/experiment/serializers.py b/backend/experiment/serializers.py
index 58b49a531..d79247c65 100644
--- a/backend/experiment/serializers.py
+++ b/backend/experiment/serializers.py
@@ -67,66 +67,66 @@ def serialize_phase(
phase: Phase,
participant: Participant
) -> dict:
- grouped_experiments = list(GroupedBlock.objects.filter(
- phase_id=phase.id).order_by('order'))
+ grouped_blocks = list(GroupedBlock.objects.filter(
+ phase_id=phase.id).order_by('index'))
if phase.randomize:
- shuffle(grouped_experiments)
+ shuffle(grouped_blocks)
- next_experiment = get_upcoming_experiment(
- grouped_experiments, participant, phase.dashboard)
+ next_block = get_upcoming_block(
+ grouped_blocks, participant, phase.dashboard)
- total_score = get_total_score(grouped_experiments, participant)
+ total_score = get_total_score(grouped_blocks, participant)
- if not next_experiment:
+ if not next_block:
return None
return {
- 'dashboard': [serialize_experiment(experiment.block, participant) for experiment in grouped_experiments] if phase.dashboard else [],
- 'nextExperiment': next_experiment,
+ 'dashboard': [serialize_block(block.block, participant) for block in grouped_blocks] if phase.dashboard else [],
+ 'nextBlock': next_block,
'totalScore': total_score
}
-def serialize_experiment(experiment_object: Block, participant: Participant):
+def serialize_block(block_object: Block, participant: Participant):
return {
- 'slug': experiment_object.slug,
- 'name': experiment_object.name,
- 'description': experiment_object.description,
- 'image': serialize_image(experiment_object.image) if experiment_object.image else None,
+ 'slug': block_object.slug,
+ 'name': block_object.name,
+ 'description': block_object.description,
+ 'image': serialize_image(block_object.image) if block_object.image else None,
}
-def get_upcoming_experiment(experiment_list, participant, repeat_allowed=True):
- ''' return next experiment with minimum finished sessions for this participant
- if repeated experiments are not allowed (dashboard=False) and there are only finished sessions, return None '''
+def get_upcoming_block(block_list, participant, repeat_allowed=True):
+ ''' return next block with minimum finished sessions for this participant
+ if repeated blocks are not allowed (dashboard=False) and there are only finished sessions, return None '''
finished_session_counts = [get_finished_session_count(
- experiment.experiment, participant) for experiment in experiment_list]
+ block.block, participant) for block in block_list]
minimum_session_count = min(finished_session_counts)
if not repeat_allowed and minimum_session_count != 0:
return None
- return serialize_experiment(experiment_list[finished_session_counts.index(minimum_session_count)].experiment, participant)
+ return serialize_block(block_list[finished_session_counts.index(minimum_session_count)].block, participant)
-def get_started_session_count(experiment, participant):
- ''' Get the number of started sessions for this experiment and participant '''
+def get_started_session_count(block, participant):
+ ''' Get the number of started sessions for this block and participant '''
count = Session.objects.filter(
- experiment=experiment, participant=participant).count()
+ block=block, participant=participant).count()
return count
-def get_finished_session_count(experiment, participant):
- ''' Get the number of finished sessions for this experiment and participant '''
+def get_finished_session_count(block, participant):
+ ''' Get the number of finished sessions for this block and participant '''
count = Session.objects.filter(
- experiment=experiment, participant=participant, finished_at__isnull=False).count()
+ block=block, participant=participant, finished_at__isnull=False).count()
return count
-def get_total_score(grouped_experiments, participant):
- '''Calculate total score of all experiments on the dashboard'''
+def get_total_score(grouped_blocks, participant):
+ '''Calculate total score of all blocks on the dashboard'''
total_score = 0
- for grouped_experiment in grouped_experiments:
- sessions = Session.objects.filter(experiment=grouped_experiment.experiment, participant=participant)
+ for grouped_block in grouped_blocks:
+ sessions = Session.objects.filter(block=grouped_block.block, participant=participant)
for session in sessions:
total_score += session.final_score
return total_score
diff --git a/backend/experiment/static/experiment_admin.css b/backend/experiment/static/block_admin.css
similarity index 100%
rename from backend/experiment/static/experiment_admin.css
rename to backend/experiment/static/block_admin.css
diff --git a/backend/experiment/static/experiment_admin.js b/backend/experiment/static/block_admin.js
similarity index 100%
rename from backend/experiment/static/experiment_admin.js
rename to backend/experiment/static/block_admin.js
diff --git a/backend/experiment/templates/collection-dashboard-sessions.html b/backend/experiment/templates/collection-dashboard-sessions.html
index d99092397..6edf80b47 100644
--- a/backend/experiment/templates/collection-dashboard-sessions.html
+++ b/backend/experiment/templates/collection-dashboard-sessions.html
@@ -12,14 +12,14 @@
Finished
Final score
Results
- Preview
+ Preview
-
- {% for session in sessions %}
-
+
+ {% for session in sessions %}
+
@@ -30,9 +30,9 @@
-
- {{ session.experiment.name }}
-
+
+ {{ session.block.name }}
+
@@ -45,15 +45,15 @@
{{ session.participant.id }}
- {% endif %}
-
+ {% endif %}
+
{{ session.started_at }}
-
+
{% if session.finished_at %}
{{ session.finished_at }}
{% else %}
@@ -73,9 +73,9 @@
-
+
-
+
diff --git a/backend/experiment/templates/collection-dashboard.html b/backend/experiment/templates/collection-dashboard.html
index 55193aa43..583bd987b 100644
--- a/backend/experiment/templates/collection-dashboard.html
+++ b/backend/experiment/templates/collection-dashboard.html
@@ -16,8 +16,8 @@
background-color: var(--body-bg)
}
td, th {
- vertical-align: middle;
- width: auto;
+ vertical-align: middle;
+ width: auto;
}
td {
padding-left: 1rem;
@@ -30,7 +30,7 @@
width: 8rem;
}
td.participants-overview {
- max-width: 25vw;
+ max-width: 25vw;
}
pre {
color: black;
@@ -43,23 +43,23 @@
font-weight: 600;
margin: 2rem 0px 2rem 0px;
}
- .pop-up {
+ .pop-up {
background-color: var(--body-bg);
box-shadow: 0px 0px 10px var(--primary);
position: fixed;
-
- padding: 2rem;
+
+ padding: 2rem;
border-style: solid;
border-color: var(--primary);
- border-width: 1px;
+ border-width: 1px;
border-radius: 1px;
overflow-y: scroll;
}
.pop-up-big {
top: 4.2rem;
- left: 10vw;
+ left: 10vw;
width: calc(80vw - 34px);
- height: 80vh;
+ height: 80vh;
}
.pop-up-small {
@@ -73,10 +73,10 @@
Experiments in collection: {{ collection.name }}
+
@@ -89,19 +89,19 @@ Experiments in collection: {{ collection.name }}
Times finished
Participant count
Participants *
- Sessions
+ Sessions
-
+
- {% for exp in experiments %}
+ {% for exp in experiments %}
-
+
{{ exp.name }}
-
+
@@ -120,7 +120,7 @@ Experiments in collection: {{ collection.name }}
{% for participant in exp.participants %}
-
+
{% if participant.participant_id_url %}
{{ participant.participant_id_url }}
@@ -132,20 +132,20 @@ Experiments in collection: {{ collection.name }}
{% endif %}
,
{% endfor %}
-
+
-
+
-
+
{% endfor %}
-
+
* Click to edit in a new window
diff --git a/backend/experiment/tests/test_admin_experiment.py b/backend/experiment/tests/test_admin_experiment.py
index 7c7ffdad3..4e75717fa 100644
--- a/backend/experiment/tests/test_admin_experiment.py
+++ b/backend/experiment/tests/test_admin_experiment.py
@@ -6,15 +6,15 @@
from django.contrib.admin.sites import AdminSite
from django.urls import reverse
from django.utils.html import format_html
-from experiment.admin import ExperimentAdmin, ExperimentCollectionAdmin, PhaseAdmin
-from experiment.models import Experiment, ExperimentCollection, Phase, GroupedBlock
+from experiment.admin import BlockAdmin, ExperimentCollectionAdmin, PhaseAdmin
+from experiment.models import Block, ExperimentCollection, Phase, GroupedBlock
from participant.models import Participant
from result.models import Result
from session.models import Session
# Expected field count per model
-EXPECTED_EXPERIMENT_FIELDS = 15
+EXPECTED_BLOCK_FIELDS = 15
EXPECTED_SESSION_FIELDS = 9
EXPECTED_RESULT_FIELDS = 12
EXPECTED_PARTICIPANT_FIELDS = 5
@@ -31,13 +31,13 @@ class TestAdminExperiment(TestCase):
@classmethod
def setUpTestData(cls):
- Experiment.objects.create(
+ Block.objects.create(
name='test',
slug='TEST'
)
Participant.objects.create()
Session.objects.create(
- experiment=Experiment.objects.first(),
+ block=Block.objects.first(),
participant=Participant.objects.first()
)
Result.objects.create(
@@ -45,14 +45,15 @@ def setUpTestData(cls):
)
def setUp(self):
- self.admin = ExperimentAdmin(model=Experiment,
- admin_site=AdminSite
- )
+ self.admin = BlockAdmin(
+ model=Block,
+ admin_site=AdminSite,
+ )
- def test_experiment_model_fields(self):
- experiment = model_to_dict(Experiment.objects.first())
- experiment_fields = [key for key in experiment]
- self.assertEqual(len(experiment_fields), EXPECTED_EXPERIMENT_FIELDS)
+ def test_block_model_fields(self):
+ block = model_to_dict(Block.objects.first())
+ block_fields = [key for key in block]
+ self.assertEqual(len(block_fields), EXPECTED_BLOCK_FIELDS)
def test_session_model_fields(self):
session = model_to_dict(Session.objects.first())
@@ -69,31 +70,31 @@ def test_participant_model(self):
participant_fields = [key for key in participant]
self.assertEqual(len(participant_fields), EXPECTED_PARTICIPANT_FIELDS)
- def test_experiment_link(self):
- experiment = Experiment.objects.create(name="Test Experiment")
+ def test_block_link(self):
+ block = Block.objects.create(name="Test Block")
site = AdminSite()
- admin = ExperimentAdmin(experiment, site)
- link = admin.experiment_name_link(experiment)
+ admin = BlockAdmin(block, site)
+ link = admin.block_name_link(block)
expected_url = reverse(
- "admin:experiment_experiment_change", args=[experiment.pk])
- expected_name = "Test Experiment"
+ "admin:experiment_block_change", args=[block.pk])
+ expected_name = "Test Block"
expected_link = format_html(
'{} ', expected_url, expected_name)
self.assertEqual(link, expected_link)
-class TestAdminExperimentExport(TestCase):
+class TestAdminBlockExport(TestCase):
fixtures = ['playlist', 'experiment']
@classmethod
def setUpTestData(cls):
cls.participant = Participant.objects.create(unique_hash=42)
- cls.experiment = Experiment.objects.get(name='Hooked-China')
- for playlist in cls.experiment.playlists.all():
+ cls.block = Block.objects.get(name='Hooked-China')
+ for playlist in cls.block.playlists.all():
playlist.update_sections()
cls.session = Session.objects.create(
- experiment=cls.experiment,
+ block=cls.block,
participant=cls.participant,
)
for i in range(5):
@@ -111,12 +112,13 @@ def setUpTestData(cls):
def setUp(self):
self.client = Client()
- self.admin = ExperimentAdmin(model=Experiment,
- admin_site=AdminSite
- )
+ self.admin = BlockAdmin(
+ model=Block,
+ admin_site=AdminSite
+ )
def test_admin_export(self):
- response = self.admin.export(request, self.experiment)
+ response = self.admin.export(request, self.block)
zip_buffer = BytesIO(response.content)
with ZipFile(zip_buffer, 'r') as test_zip:
# Test files inside zip
@@ -145,7 +147,7 @@ def test_admin_export(self):
these_sessions = json.loads(test_zip.read('sessions.json').decode("utf-8"))
self.assertEqual(len(these_sessions), 1)
- self.assertEqual(these_sessions[0]['fields']['experiment'], 14)
+ self.assertEqual(these_sessions[0]['fields']['block'], 14)
these_songs = json.loads(test_zip.read('songs.json').decode("utf-8"))
self.assertEqual(len(these_songs), 100)
@@ -160,7 +162,7 @@ def test_export_table_includes_question_key(self):
export_options = ['convert_result_json'] # Adjust based on your needs
# Call the method under test
- rows, fieldnames = self.experiment.export_table(session_keys, result_keys, export_options)
+ rows, fieldnames = self.block.export_table(session_keys, result_keys, export_options)
# Assert that 'question_key' is in the fieldnames and check its value in rows
self.assertIn('question_key', fieldnames)
@@ -232,27 +234,27 @@ def test_related_series_with_series(self):
expected_related_series = format_html('{} ', expected_url, series.name)
self.assertEqual(related_series, expected_related_series)
- def test_experiments_with_no_experiments(self):
+ def test_blocks_with_no_blocks(self):
series = ExperimentCollection.objects.create(name='Test Series')
phase = Phase.objects.create(
name='Test Group', index=1, randomize=False, dashboard=True, series=series)
- experiments = self.admin.experiments(phase)
- self.assertEqual(experiments, "No experiments")
+ blocks = self.admin.blocks(phase)
+ self.assertEqual(blocks, "No blocks")
- def test_experiments_with_experiments(self):
+ def test_blocks_with_blocks(self):
series = ExperimentCollection.objects.create(name='Test Series')
phase = Phase.objects.create(
name='Test Group', index=1, randomize=False, dashboard=True, series=series)
- experiment1 = Experiment.objects.create(name='Experiment 1', slug='experiment-1')
- experiment2 = Experiment.objects.create(name='Experiment 2', slug='experiment-2')
- grouped_experiment1 = GroupedBlock.objects.create(phase=phase, experiment=experiment1)
- grouped_experiment2 = GroupedBlock.objects.create(phase=phase, experiment=experiment2)
+ block1 = Block.objects.create(name='Block 1', slug='block-1')
+ block2 = Block.objects.create(name='Block 2', slug='block-2')
+ grouped_block1 = GroupedBlock.objects.create(phase=phase, block=block1)
+ grouped_block2 = GroupedBlock.objects.create(phase=phase, block=block2)
- experiments = self.admin.experiments(phase)
- expected_experiments = format_html(
+ blocks = self.admin.blocks(phase)
+ expected_blocks = format_html(
', '.join([
- f'{experiment.experiment.name} '
- for experiment in [grouped_experiment1, grouped_experiment2]
+ f'{block.block.name} '
+ for block in [grouped_block1, grouped_block2]
])
)
- self.assertEqual(experiments, expected_experiments)
+ self.assertEqual(blocks, expected_blocks)
diff --git a/backend/experiment/tests/test_forms.py b/backend/experiment/tests/test_forms.py
index babe045f6..b306c4fac 100644
--- a/backend/experiment/tests/test_forms.py
+++ b/backend/experiment/tests/test_forms.py
@@ -1,11 +1,11 @@
from django.test import TestCase
-from experiment.forms import ExperimentForm, ExportForm, TemplateForm, BLOCK_RULES, SESSION_CHOICES, RESULT_CHOICES, EXPORT_OPTIONS, TEMPLATE_CHOICES
+from experiment.forms import BlockForm, ExportForm, TemplateForm, BLOCK_RULES, SESSION_CHOICES, RESULT_CHOICES, EXPORT_OPTIONS, TEMPLATE_CHOICES
-class ExperimentFormTest(TestCase):
+class BlockFormTest(TestCase):
def test_form_fields(self):
- form = ExperimentForm()
+ form = BlockForm()
self.assertIn('name', form.fields)
self.assertIn('slug', form.fields)
self.assertIn('active', form.fields)
@@ -15,7 +15,7 @@ def test_form_fields(self):
self.assertIn('playlists', form.fields)
def test_rules_field_choices(self):
- form = ExperimentForm()
+ form = BlockForm()
expected_choices = [(i, BLOCK_RULES[i].__name__) for i in BLOCK_RULES]
expected_choices.append(("", "---------"))
self.assertEqual(form.fields['rules'].choices, sorted(expected_choices))
diff --git a/backend/experiment/tests/test_model.py b/backend/experiment/tests/test_model.py
index 609105119..d4f67a9c6 100644
--- a/backend/experiment/tests/test_model.py
+++ b/backend/experiment/tests/test_model.py
@@ -2,13 +2,13 @@
from image.models import Image
from theme.models import ThemeConfig
-from experiment.models import Experiment, ExperimentCollection
+from experiment.models import Block, ExperimentCollection
from participant.models import Participant
from session.models import Session
from result.models import Result
-class ExperimentModelTest(TestCase):
+class BlockModelTest(TestCase):
@classmethod
def setUpTestData(cls):
logo_image = Image.objects.create(
@@ -25,11 +25,11 @@ def setUpTestData(cls):
logo_image=logo_image,
background_image=background_image,
)
- Experiment.objects.create(
- name='Test Experiment',
- description='Test experiment description',
- slug='test-experiment',
- url='https://example.com/experiment',
+ Block.objects.create(
+ name='Test Block',
+ description='Test block description',
+ slug='test-block',
+ url='https://example.com/block',
hashtag='test',
rounds=5,
bonus_points=10,
@@ -38,40 +38,40 @@ def setUpTestData(cls):
theme_config=ThemeConfig.objects.get(name='Default'),
)
- def test_experiment_str(self):
- experiment = Experiment.objects.get(name='Test Experiment')
- self.assertEqual(str(experiment), 'Test Experiment')
+ def test_block_str(self):
+ block = Block.objects.get(name='Test Block')
+ self.assertEqual(str(block), 'Test Block')
- def test_experiment_session_count(self):
- experiment = Experiment.objects.get(name='Test Experiment')
- self.assertEqual(experiment.session_count(), 0)
+ def test_block_session_count(self):
+ block = Block.objects.get(name='Test Block')
+ self.assertEqual(block.session_count(), 0)
- def test_experiment_playlist_count(self):
- experiment = Experiment.objects.get(name='Test Experiment')
- self.assertEqual(experiment.playlist_count(), 0)
+ def test_block_playlist_count(self):
+ block = Block.objects.get(name='Test Block')
+ self.assertEqual(block.playlist_count(), 0)
- def test_experiment_current_participants(self):
- experiment = Experiment.objects.get(name='Test Experiment')
- participants = experiment.current_participants()
+ def test_block_current_participants(self):
+ block = Block.objects.get(name='Test Block')
+ participants = block.current_participants()
self.assertEqual(len(participants), 0)
- def test_experiment_export_admin(self):
- experiment = Experiment.objects.get(name='Test Experiment')
- exported_data = experiment.export_admin()
- self.assertEqual(exported_data['experiment']['name'], 'Test Experiment')
+ def test_block_export_admin(self):
+ block = Block.objects.get(name='Test Block')
+ exported_data = block.export_admin()
+ self.assertEqual(exported_data['block']['name'], 'Test Block')
- def test_experiment_export_sessions(self):
- experiment = Experiment.objects.get(name='Test Experiment')
- sessions = experiment.export_sessions()
+ def test_block_export_sessions(self):
+ block = Block.objects.get(name='Test Block')
+ sessions = block.export_sessions()
self.assertEqual(len(sessions), 0)
- def test_experiment_export_table(self):
- experiment = Experiment.objects.get(name='Test Experiment')
+ def test_block_export_table(self):
+ block = Block.objects.get(name='Test Block')
amount_of_sessions = 3
for i in range(amount_of_sessions):
session = Session.objects.create(
- experiment=experiment,
+ block=block,
participant=Participant.objects.create()
)
Result.objects.create(
@@ -81,10 +81,10 @@ def test_experiment_export_table(self):
question_key='test_question_1',
)
- session_keys = ['experiment_id', 'experiment_name']
+ session_keys = ['block_id', 'block_name']
result_keys = ['section_name', 'result_created_at']
export_options = {'wide_format': True}
- rows, fieldnames = experiment.export_table(
+ rows, fieldnames = block.export_table(
session_keys,
result_keys,
export_options
@@ -93,19 +93,19 @@ def test_experiment_export_table(self):
self.assertEqual(len(rows), amount_of_sessions)
self.assertEqual(len(fieldnames), len(session_keys) + len(result_keys))
- def test_experiment_get_rules(self):
- experiment = Experiment.objects.get(name='Test Experiment')
- rules = experiment.get_rules()
+ def test_block_get_rules(self):
+ block = Block.objects.get(name='Test Block')
+ rules = block.get_rules()
self.assertIsNotNone(rules)
- def test_experiment_max_score(self):
- experiment = Experiment.objects.get(name='Test Experiment')
+ def test_block_max_score(self):
+ block = Block.objects.get(name='Test Block')
amount_of_results = 3
question_score = 1
session = Session.objects.create(
- experiment=experiment,
+ block=block,
participant=Participant.objects.create()
)
for j in range(amount_of_results):
@@ -120,8 +120,8 @@ def test_experiment_max_score(self):
session.save()
question_scores = amount_of_results * question_score
- bonus_points = experiment.bonus_points
- max_score = experiment.max_score()
+ bonus_points = block.bonus_points
+ max_score = block.max_score()
self.assertEqual(max_score, question_scores + bonus_points)
self.assertEqual(max_score, 13.0)
diff --git a/backend/experiment/tests/test_model_functions.py b/backend/experiment/tests/test_model_functions.py
index 961b38410..e42ae6a59 100644
--- a/backend/experiment/tests/test_model_functions.py
+++ b/backend/experiment/tests/test_model_functions.py
@@ -1,17 +1,17 @@
from django.test import TestCase
from session.models import Session
from participant.models import Participant
-from experiment.models import Experiment, ExperimentCollection, Phase, GroupedBlock
+from experiment.models import Block, ExperimentCollection, Phase, GroupedBlock
class TestModelExperiment(TestCase):
@classmethod
def setUpTestData(cls):
- cls.experiment = Experiment.objects.create(rules='THATS_MY_SONG', slug='hooked', rounds=42)
+ cls.block = Block.objects.create(rules='THATS_MY_SONG', slug='hooked', rounds=42)
def test_separate_rules_instance(self):
- rules1 = self.experiment.get_rules()
- rules2 = self.experiment.get_rules()
+ rules1 = self.block.get_rules()
+ rules2 = self.block.get_rules()
keys1 = rules1.question_series[0]['keys'] + rules1.question_series[1]['keys']
keys2 = rules2.question_series[0]['keys'] + rules2.question_series[1]['keys']
assert keys1 == keys2
@@ -31,39 +31,39 @@ def test_verbose_name_plural(self):
# Check if verbose_name_plural is correctly set
self.assertEqual(meta.verbose_name_plural, "Experiment Collections")
- def test_associated_experiments(self):
+ def test_associated_blocks(self):
collection = self.collection
phase1 = Phase.objects.create(
name='first_phase', series=collection)
phase2 = Phase.objects.create(
name='second_phase', series=collection)
- experiment = Experiment.objects.create(
+ block = Block.objects.create(
rules='THATS_MY_SONG', slug='hooked', rounds=42)
- experiment2 = Experiment.objects.create(
+ block2 = Block.objects.create(
rules='THATS_MY_SONG', slug='unhinged', rounds=42)
- experiment3 = Experiment.objects.create(
+ block3 = Block.objects.create(
rules='THATS_MY_SONG', slug='derailed', rounds=42)
GroupedBlock.objects.create(
- experiment=experiment, phase=phase1)
+ block=block, phase=phase1)
GroupedBlock.objects.create(
- experiment=experiment2, phase=phase2)
+ block=block2, phase=phase2)
GroupedBlock.objects.create(
- experiment=experiment3, phase=phase2)
- self.assertEqual(collection.associated_experiments(), [
- experiment, experiment2, experiment3])
+ block=block3, phase=phase2)
+ self.assertEqual(collection.associated_blocks(), [
+ block, block2, block3])
def test_export_sessions(self):
collection = self.collection
phase = Phase.objects.create(
name='test', series=collection)
- experiment = Experiment.objects.create(
+ block = Block.objects.create(
rules='THATS_MY_SONG', slug='hooked', rounds=42)
GroupedBlock.objects.create(
- experiment=experiment, phase=phase)
+ block=block, phase=phase)
Session.objects.bulk_create(
- [Session(experiment=experiment, participant=self.participant1),
- Session(experiment=experiment, participant=self.participant2),
- Session(experiment=experiment, participant=self.participant3)]
+ [Session(block=block, participant=self.participant1),
+ Session(block=block, participant=self.participant2),
+ Session(block=block, participant=self.participant3)]
)
sessions = collection.export_sessions()
self.assertEqual(len(sessions), 3)
@@ -72,14 +72,14 @@ def test_current_participants(self):
collection = self.collection
phase = Phase.objects.create(
name='test', series=collection)
- experiment = Experiment.objects.create(
+ block = Block.objects.create(
rules='THATS_MY_SONG', slug='hooked', rounds=42)
GroupedBlock.objects.create(
- experiment=experiment, phase=phase)
+ block=block, phase=phase)
Session.objects.bulk_create(
- [Session(experiment=experiment, participant=self.participant1),
- Session(experiment=experiment, participant=self.participant2),
- Session(experiment=experiment, participant=self.participant3)]
+ [Session(block=block, participant=self.participant1),
+ Session(block=block, participant=self.participant2),
+ Session(block=block, participant=self.participant3)]
)
participants = collection.current_participants()
self.assertEqual(len(participants), 3)
diff --git a/backend/experiment/tests/test_validators.py b/backend/experiment/tests/test_validators.py
index b532d34d7..8189bb984 100644
--- a/backend/experiment/tests/test_validators.py
+++ b/backend/experiment/tests/test_validators.py
@@ -1,7 +1,7 @@
from django.core.exceptions import ValidationError
from django.test import TestCase
-from experiment.validators import experiment_slug_validator
+from experiment.validators import block_slug_validator
class ExperimentValidatorsTest(TestCase):
@@ -9,7 +9,7 @@ def test_valid_slug(self):
# Test a valid lowercase slug
slug = 'testslug'
try:
- experiment_slug_validator(slug)
+ block_slug_validator(slug)
except ValidationError:
self.fail(f"Unexpected ValidationError raised for slug: {slug}")
@@ -17,27 +17,27 @@ def test_disallowed_slug(self):
# Test a disallowed slug
slug = 'admin'
with self.assertRaises(ValidationError) as cm:
- experiment_slug_validator(slug)
+ block_slug_validator(slug)
self.assertEqual(str(cm.exception.messages[0]), 'The slug cannot start with "admin".')
def test_uppercase_slug(self):
# Test an uppercase slug
slug = 'TestSlug'
with self.assertRaises(ValidationError) as cm:
- experiment_slug_validator(slug)
+ block_slug_validator(slug)
self.assertEqual(str(cm.exception.messages[0]), 'Slugs must be lowercase.')
def test_disallowed_prefix(self):
# Test a disallowed prefix
slug = 'admin-test'
with self.assertRaises(ValidationError) as cm:
- experiment_slug_validator(slug)
+ block_slug_validator(slug)
self.assertEqual(str(cm.exception.messages[0]), 'The slug cannot start with "admin".')
def test_valid_prefix(self):
# Test a valid prefix
slug = 'test-admin'
try:
- experiment_slug_validator(slug)
+ block_slug_validator(slug)
except ValidationError:
self.fail(f"Unexpected ValidationError raised for slug: {slug}")
diff --git a/backend/experiment/tests/test_views.py b/backend/experiment/tests/test_views.py
index 95f65279d..606a464b3 100644
--- a/backend/experiment/tests/test_views.py
+++ b/backend/experiment/tests/test_views.py
@@ -4,11 +4,11 @@
from image.models import Image
from experiment.serializers import (
- serialize_experiment,
+ serialize_block,
serialize_phase
)
from experiment.models import (
- Experiment,
+ Block,
ExperimentCollection,
Phase,
GroupedBlock,
@@ -37,10 +37,10 @@ def setUpTestData(cls):
series=collection,
index=1
)
- cls.experiment1 = Experiment.objects.create(
- name='experiment1', slug='experiment1')
+ cls.block1 = Block.objects.create(
+ name='block1', slug='block1')
GroupedBlock.objects.create(
- experiment=cls.experiment1,
+ block=cls.block1,
phase=introductory_phase
)
intermediate_phase = Phase.objects.create(
@@ -48,16 +48,16 @@ def setUpTestData(cls):
series=collection,
index=2
)
- cls.experiment2 = Experiment.objects.create(
- name='experiment2', slug='experiment2', theme_config=theme_config)
- cls.experiment3 = Experiment.objects.create(
- name='experiment3', slug='experiment3')
+ cls.block2 = Block.objects.create(
+ name='block2', slug='block2', theme_config=theme_config)
+ cls.block3 = Block.objects.create(
+ name='block3', slug='block3')
GroupedBlock.objects.create(
- experiment=cls.experiment2,
+ block=cls.block2,
phase=intermediate_phase
)
GroupedBlock.objects.create(
- experiment=cls.experiment3,
+ block=cls.block3,
phase=intermediate_phase
)
final_phase = Phase.objects.create(
@@ -65,10 +65,10 @@ def setUpTestData(cls):
series=collection,
index=3
)
- cls.experiment4 = Experiment.objects.create(
- name='experiment4', slug='experiment4')
+ cls.block4 = Block.objects.create(
+ name='block4', slug='block4')
GroupedBlock.objects.create(
- experiment=cls.experiment4,
+ block=cls.block4,
phase=final_phase
)
@@ -80,31 +80,31 @@ def test_get_experiment_collection(self):
# check that first_experiments is returned correctly
response = self.client.get('/experiment/collection/test_series/')
self.assertEqual(response.json().get(
- 'nextExperiment').get('slug'), 'experiment1')
+ 'nextBlock').get('slug'), 'block1')
# create session
Session.objects.create(
- experiment=self.experiment1,
+ block=self.block1,
participant=self.participant,
finished_at=timezone.now()
)
response = self.client.get('/experiment/collection/test_series/')
- self.assertIn(response.json().get('nextExperiment').get(
- 'slug'), ('experiment2', 'experiment3'))
+ self.assertIn(response.json().get('nextBlock').get(
+ 'slug'), ('block2', 'block3'))
self.assertEqual(response.json().get('dashboard'), [])
Session.objects.create(
- experiment=self.experiment2,
+ block=self.block2,
participant=self.participant,
finished_at=timezone.now()
)
Session.objects.create(
- experiment=self.experiment3,
+ block=self.block3,
participant=self.participant,
finished_at=timezone.now()
)
response = self.client.get('/experiment/collection/test_series/')
response_json = response.json()
self.assertEqual(response_json.get(
- 'nextExperiment').get('slug'), 'experiment4')
+ 'nextBlock').get('slug'), 'block4')
self.assertEqual(response_json.get('dashboard'), [])
self.assertEqual(response_json.get('theme').get('name'), 'test_theme')
self.assertEqual(len(response_json['theme']['header']['score']), 3)
@@ -129,12 +129,12 @@ def test_get_experiment_collection_inactive(self):
self.assertEqual(response.status_code, 404)
def test_experiment_collection_with_dashboard(self):
- # if ExperimentCollection has dashboard set True, return list of random experiments
+ # if ExperimentCollection has dashboard set True, return list of random blocks
session = self.client.session
session['participant_id'] = self.participant.id
session.save()
Session.objects.create(
- experiment=self.experiment1,
+ block=self.block1,
participant=self.participant,
finished_at=timezone.now()
)
@@ -148,12 +148,12 @@ def test_experiment_collection_with_dashboard(self):
self.assertEqual(type(response.json().get('dashboard')), list)
def test_experiment_collection_total_score(self):
- """ Test calculation of total score for grouped experiment on dashboard """
+ """ Test calculation of total score for grouped block on dashboard """
session = self.client.session
session['participant_id'] = self.participant.id
session.save()
Session.objects.create(
- experiment=self.experiment2,
+ block=self.block2,
participant=self.participant,
finished_at=timezone.now(),
final_score=8
@@ -167,7 +167,7 @@ def test_experiment_collection_total_score(self):
total_score_1 = serialized_coll_1['totalScore']
self.assertEqual(total_score_1, 8)
Session.objects.create(
- experiment=self.experiment3,
+ block=self.block3,
participant=self.participant,
finished_at=timezone.now(),
final_score=8
@@ -179,12 +179,12 @@ def test_experiment_collection_total_score(self):
class ExperimentViewsTest(TestCase):
- def test_serialize_experiment(self):
- # Create an experiment
- experiment = Experiment.objects.create(
- slug='test-experiment',
- name='Test Experiment',
- description='This is a test experiment',
+ def test_serialize_block(self):
+ # Create an block
+ block = Block.objects.create(
+ slug='test-block',
+ name='Test Block',
+ description='This is a test block',
image=Image.objects.create(
title='Test',
description='',
@@ -198,24 +198,24 @@ def test_serialize_experiment(self):
)
participant = Participant.objects.create()
Session.objects.bulk_create([
- Session(experiment=experiment, participant=participant, finished_at=timezone.now()) for index in range(3)
+ Session(block=block, participant=participant, finished_at=timezone.now()) for index in range(3)
])
- # Call the serialize_experiment function
- serialized_experiment = serialize_experiment(experiment, participant)
+ # Call the serialize_block function
+ serialized_block = serialize_block(block, participant)
# Assert the serialized data
self.assertEqual(
- serialized_experiment['slug'], 'test-experiment'
+ serialized_block['slug'], 'test-block'
)
self.assertEqual(
- serialized_experiment['name'], 'Test Experiment'
+ serialized_block['name'], 'Test Block'
)
self.assertEqual(
- serialized_experiment['description'], 'This is a test experiment'
+ serialized_block['description'], 'This is a test block'
)
self.assertEqual(
- serialized_experiment['image'], {
+ serialized_block['image'], {
'title': 'Test',
'description': '',
'file': f'{settings.BASE_URL}/upload/test-image.jpg',
@@ -227,12 +227,12 @@ def test_serialize_experiment(self):
}
)
- def test_get_experiment(self):
- # Create an experiment
- experiment = Experiment.objects.create(
- slug='test-experiment',
- name='Test Experiment',
- description='This is a test experiment',
+ def test_get_block(self):
+ # Create an block
+ block = Block.objects.create(
+ slug='test-block',
+ name='Test Block',
+ description='This is a test block',
image=Image.objects.create(
file='test-image.jpg'
),
@@ -241,16 +241,16 @@ def test_get_experiment(self):
)
participant = Participant.objects.create()
Session.objects.bulk_create([
- Session(experiment=experiment, participant=participant, finished_at=timezone.now()) for index in range(3)
+ Session(block=block, participant=participant, finished_at=timezone.now()) for index in range(3)
])
- response = self.client.get('/experiment/test-experiment/')
+ response = self.client.get('/experiment/test-block/')
self.assertEqual(
- response.json()['slug'], 'test-experiment'
+ response.json()['slug'], 'test-block'
)
self.assertEqual(
- response.json()['name'], 'Test Experiment'
+ response.json()['name'], 'Test Block'
)
self.assertEqual(
response.json()['theme']['name'], 'test_theme'
diff --git a/backend/experiment/urls.py b/backend/experiment/urls.py
index d6153b18e..0892c56fc 100644
--- a/backend/experiment/urls.py
+++ b/backend/experiment/urls.py
@@ -1,6 +1,6 @@
from django.urls import path
from django.views.generic.base import TemplateView
-from .views import get_experiment, get_experiment_collection, post_feedback, render_markdown, add_default_question_series, validate_experiment_playlist
+from .views import get_block, get_experiment_collection, post_feedback, render_markdown, add_default_question_series, validate_block_playlist
app_name = 'experiment'
@@ -8,8 +8,8 @@
path('add_default_question_series//', add_default_question_series, name='add_default_question_series'),
# Experiment
path('render_markdown/', render_markdown, name='render_markdown'),
- path('validate_playlist/', validate_experiment_playlist, name='validate_experiment_playlist'),
- path('/', get_experiment, name='experiment'),
+ path('validate_playlist/', validate_block_playlist, name='validate_block_playlist'),
+ path('/', get_block, name='experiment'),
path('/feedback/', post_feedback, name='feedback'),
path('collection//', get_experiment_collection,
name='experiment_collection'),
diff --git a/backend/experiment/validators.py b/backend/experiment/validators.py
index 95cd3295e..25bace138 100644
--- a/backend/experiment/validators.py
+++ b/backend/experiment/validators.py
@@ -8,8 +8,8 @@ def markdown_html_validator():
return FileExtensionValidator(allowed_extensions=valid_extensions)
-def experiment_slug_validator(value):
-
+def block_slug_validator(value):
+
disallowed_slugs = [
'admin',
'server',
@@ -19,6 +19,7 @@ def experiment_slug_validator(value):
'section',
'session',
'static',
+ 'block',
]
# Slug cannot start with a disallowed slug
@@ -26,6 +27,10 @@ def experiment_slug_validator(value):
if value.lower().startswith(slug):
raise ValidationError(f'The slug cannot start with "{slug}".')
- # Slugs must be lowercase
+ # Slugs must be lowercase
if value.lower() != value:
raise ValidationError('Slugs must be lowercase.')
+
+
+# This is the validator that is used in the migration file
+experiment_slug_validator = block_slug_validator
diff --git a/backend/experiment/views.py b/backend/experiment/views.py
index c00a0e557..ade3da7a1 100644
--- a/backend/experiment/views.py
+++ b/backend/experiment/views.py
@@ -18,56 +18,56 @@
logger = logging.getLogger(__name__)
-def get_experiment(request, slug):
- """Get experiment data from active experiment with given :slug
+def get_block(request, slug):
+ """Get block data from active block with given :slug
DO NOT modify session data here, it will break participant_id system
- (/participant and /experiment/ are called at the same time by the frontend)"""
- experiment = experiment_or_404(slug)
+ (/participant and /block/ are called at the same time by the frontend)"""
+ block = block_or_404(slug)
class_name = ''
if request.LANGUAGE_CODE.startswith('zh'):
class_name = 'chinese'
- if experiment.language:
- activate(experiment.language)
+ if block.language:
+ activate(block.language)
# create data
- experiment_data = {
- 'id': experiment.id,
- 'slug': experiment.slug,
- 'name': experiment.name,
- 'theme': serialize_theme(experiment.theme_config) if experiment.theme_config else None,
- 'description': experiment.description,
- 'image': serialize_image(experiment.image) if experiment.image else None,
+ block_data = {
+ 'id': block.id,
+ 'slug': block.slug,
+ 'name': block.name,
+ 'theme': serialize_theme(block.theme_config) if block.theme_config else None,
+ 'description': block.description,
+ 'image': serialize_image(block.image) if block.image else None,
'class_name': class_name, # can be used to override style
- 'rounds': experiment.rounds,
+ 'rounds': block.rounds,
'playlists': [
{'id': playlist.id, 'name': playlist.name}
- for playlist in experiment.playlists.all()
+ for playlist in block.playlists.all()
],
- 'feedback_info': experiment.get_rules().feedback_info(),
- 'next_round': serialize_actions(experiment.get_rules().first_round(experiment)),
+ 'feedback_info': block.get_rules().feedback_info(),
+ 'next_round': serialize_actions(block.get_rules().first_round(block)),
'loading_text': _('Loading')
}
- response = JsonResponse(experiment_data, json_dumps_params={'indent': 4})
- if experiment.language:
- response.set_cookie(settings.LANGUAGE_COOKIE_NAME, experiment.language)
+ response = JsonResponse(block_data, json_dumps_params={'indent': 4})
+ if block.language:
+ response.set_cookie(settings.LANGUAGE_COOKIE_NAME, block.language)
else:
- # avoid carrying over language cookie from other experiments
+ # avoid carrying over language cookie from other blocks
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, None)
return response
def post_feedback(request, slug):
text = request.POST.get('feedback')
- experiment = experiment_or_404(slug)
- feedback = Feedback(text=text, experiment=experiment)
+ block = block_or_404(slug)
+ feedback = Feedback(text=text, block=block)
feedback.save()
return JsonResponse({'status': 'ok'})
-def experiment_or_404(slug):
- # get experiment
+def block_or_404(slug):
+ # get block
try:
return Block.objects.get(slug=slug, active=True)
except Block.DoesNotExist:
@@ -88,9 +88,9 @@ def get_experiment_collection(
'''
check which `Phase` objects are related to the `ExperimentCollection` with the given slug
retrieve the phase with the lowest order (= current_phase)
- return the next experiment from the current_phase without a finished session
+ return the next block from the current_phase without a finished session
except if Phase.dashboard = True,
- then all experiments of the current_phase will be returned as an array (also those with finished session)
+ then all blocks of the current_phase will be returned as an array (also those with finished session)
'''
try:
collection = ExperimentCollection.objects.get(slug=slug, active=True)
@@ -112,14 +112,14 @@ def get_experiment_collection(
serialized_phase = serialize_phase(
current_phase, participant)
if not serialized_phase:
- # if the current phase is not a dashboard and has no unfinished experiments, it will return None
+ # if the current phase is not a dashboard and has no unfinished blocks, it will return None
# set it to finished and continue to next phase
phase_index += 1
return get_experiment_collection(request, slug, phase_index=phase_index)
except IndexError:
serialized_phase = {
'dashboard': [],
- 'next_experiment': None
+ 'next_block': None
}
return JsonResponse({
**serialize_experiment_collection(collection),
@@ -127,7 +127,7 @@ def get_experiment_collection(
})
-def get_associated_experiments(pk_list):
+def get_associated_blocks(pk_list):
''' get all the experiment objects registered in an ExperimentCollection field'''
return [Block.objects.get(pk=pk) for pk in pk_list]
@@ -152,7 +152,7 @@ def render_markdown(request):
return JsonResponse({'html': ''})
-def validate_experiment_playlist(
+def validate_block_playlist(
request: HttpRequest,
rules_id: str
) -> JsonResponse:
@@ -174,7 +174,7 @@ def validate_experiment_playlist(
playlists = Playlist.objects.filter(id__in=playlist_ids)
if not playlists:
- return JsonResponse({'status': 'error', 'message': 'The experiment must have a playlist.'})
+ return JsonResponse({'status': 'error', 'message': 'The block must have a playlist.'})
rules = BLOCK_RULES[rules_id]()
diff --git a/backend/participant/models.py b/backend/participant/models.py
index 3015e92f6..aa3750db8 100644
--- a/backend/participant/models.py
+++ b/backend/participant/models.py
@@ -78,15 +78,15 @@ def scores_per_experiment(self):
# Create best rank/score data per experiment session
for session in sessions:
- if session.experiment.slug in hits:
+ if session.block.slug in hits:
continue
- hits[session.experiment.slug] = True
+ hits[session.block.slug] = True
scores.append({
- 'experiment_slug': session.experiment.slug,
- 'experiment_name': session.experiment.name,
- 'rank': session.experiment.get_rules().rank(session),
+ 'block_slug': session.block.slug,
+ 'block_name': session.block.name,
+ 'rank': session.block.get_rules().rank(session),
'score': session.final_score,
'date': naturalday(session.finished_at),
})
diff --git a/backend/participant/tests.py b/backend/participant/tests.py
index f679e0ad1..d3f94c563 100644
--- a/backend/participant/tests.py
+++ b/backend/participant/tests.py
@@ -3,7 +3,7 @@
from django.test import Client, TestCase
from .models import Participant
-from experiment.models import Experiment
+from experiment.models import Block
from session.models import Session
from result.models import Result
@@ -13,10 +13,10 @@ class ParticipantTest(TestCase):
@classmethod
def setUpTestData(cls):
cls.participant = Participant.objects.create(unique_hash=42)
- cls.experiment = Experiment.objects.create(
+ cls.block = Block.objects.create(
rules='RHYTHM_BATTERY_INTRO', slug='test')
cls.session = Session.objects.create(
- experiment=cls.experiment,
+ block=cls.block,
participant=cls.participant,
)
cls.result1 = Result.objects.create(
@@ -67,5 +67,3 @@ def test_country_code(self):
self.client.get('/participant/')
participant = Participant.objects.last()
assert participant.country_code == 'BLA'
-
-
diff --git a/backend/question/fixtures/questionseries.json b/backend/question/fixtures/questionseries.json
index 32dc4c7c2..729b087f4 100644
--- a/backend/question/fixtures/questionseries.json
+++ b/backend/question/fixtures/questionseries.json
@@ -1,20 +1,20 @@
[
- {
- "model": "question.questionseries",
- "pk": 1,
- "fields": {
- "experiment": 14,
- "index": 1,
- "randomize": false
+ {
+ "model": "question.questionseries",
+ "pk": 1,
+ "fields": {
+ "block": 14,
+ "index": 1,
+ "randomize": false
+ }
+ },
+ {
+ "model": "question.questionseries",
+ "pk": 2,
+ "fields": {
+ "block": 20,
+ "index": 1,
+ "randomize": false
+ }
}
- },
- {
- "model": "question.questionseries",
- "pk": 2,
- "fields": {
- "experiment": 20,
- "index": 1,
- "randomize": false
- }
- }
]
diff --git a/backend/question/tests.py b/backend/question/tests.py
index 46722785c..bde6a7b45 100644
--- a/backend/question/tests.py
+++ b/backend/question/tests.py
@@ -1,6 +1,6 @@
from django.test import TestCase
-from experiment.models import Experiment
+from experiment.models import Block
from participant.models import Participant
from result.models import Result
from session.models import Session
@@ -13,10 +13,10 @@ class UtilsTestCase(TestCase):
@classmethod
def setUpTestData(cls):
cls.participant = Participant.objects.create(unique_hash=42)
- cls.experiment = Experiment.objects.create(
+ cls.block = Block.objects.create(
rules='RHYTHM_BATTERY_INTRO', slug='test')
cls.session = Session.objects.create(
- experiment=cls.experiment,
+ block=cls.block,
participant=cls.participant,
)
cls.result = Result.objects.create(
@@ -25,14 +25,14 @@ def setUpTestData(cls):
given_response='non_answer'
)
cls.questions = DEMOGRAPHICS[:3]
-
+
def test_unanswered_questions(self):
questions = unanswered_questions(self.participant, self.questions)
question = next(questions)
assert question.key == 'dgf_generation'
question = next(questions)
assert question.key == 'dgf_country_of_origin'
-
+
def test_total_unanswered_questions(self):
number = total_unanswered_questions(self.participant, self.questions)
assert number == 2
diff --git a/backend/result/tests/test_result.py b/backend/result/tests/test_result.py
index bd6784e7c..a5e0be93b 100644
--- a/backend/result/tests/test_result.py
+++ b/backend/result/tests/test_result.py
@@ -1,6 +1,6 @@
from django.test import Client, TestCase
-from experiment.models import Experiment
+from experiment.models import Block
from participant.models import Participant
from result.models import Result
from session.models import Session
@@ -11,10 +11,10 @@ class ResultTest(TestCase):
@classmethod
def setUpTestData(cls):
cls.participant = Participant.objects.create(unique_hash=42)
- cls.experiment = Experiment.objects.create(
+ cls.block = Block.objects.create(
rules='MUSICAL_PREFERENCES', slug='test')
cls.session = Session.objects.create(
- experiment=cls.experiment,
+ block=cls.block,
participant=cls.participant,
)
@@ -29,16 +29,16 @@ def setUp(self):
)
def test_json_data(self):
-
+
self.result.save_json_data({'test': 'tested'})
self.assertEqual(self.result.load_json_data(), {'test': 'tested'})
self.result.save_json_data({'test_len': 'tested_len'})
self.assertEqual(len(self.result.json_data), 2)
- def test_json_data_direct(self):
+ def test_json_data_direct(self):
self.result.json_data.update({'test_direct': 'tested_direct'})
self.result.save()
- self.assertEqual(self.result.json_data['test_direct'], 'tested_direct')
+ self.assertEqual(self.result.json_data['test_direct'], 'tested_direct')
self.result.save_json_data({'test_direct_len': 'tested_direct_len'})
self.result.save()
self.assertEqual(len(self.result.json_data), 2)
diff --git a/backend/result/tests/test_views.py b/backend/result/tests/test_views.py
index 587f44aa6..cb6b37bd8 100644
--- a/backend/result/tests/test_views.py
+++ b/backend/result/tests/test_views.py
@@ -2,7 +2,7 @@
from django.test import Client, TestCase
-from experiment.models import Experiment
+from experiment.models import Block
from participant.models import Participant
from result.models import Result
from section.models import Playlist, Section, Song
@@ -16,10 +16,10 @@ class ResultTest(TestCase):
@classmethod
def setUpTestData(cls):
cls.participant = Participant.objects.create(unique_hash=42)
- cls.experiment = Experiment.objects.create(
+ cls.block = Block.objects.create(
rules='MUSICAL_PREFERENCES', slug='test')
cls.session = Session.objects.create(
- experiment=cls.experiment,
+ block=cls.block,
participant=cls.participant,
)
@@ -95,11 +95,11 @@ def setUpTestData(cls):
filename="not/to_be_found.mp3",
tag=0
)
- cls.experiment = Experiment.objects.create(
+ cls.block = Block.objects.create(
rules='RHYTHM_BATTERY_INTRO',
slug='test')
cls.session = Session.objects.create(
- experiment=cls.experiment,
+ block=cls.block,
participant=cls.participant,
playlist=playlist
)
@@ -269,4 +269,3 @@ def test_song_sync(self):
response = self.client.post('/result/score/', client_request)
assert response.status_code == 200
assert self.session.get_previous_result(['recognize']).score == -5
-
diff --git a/backend/section/admin.py b/backend/section/admin.py
index 18a4815ce..0d3ffa5f6 100644
--- a/backend/section/admin.py
+++ b/backend/section/admin.py
@@ -49,7 +49,7 @@ class SongAdmin(admin.ModelAdmin):
class PlaylistAdmin(InlineActionsModelAdminMixin, admin.ModelAdmin):
form = PlaylistAdminForm
change_form_template = 'change_form.html'
- list_display = ('name', 'section_count', 'experiment_count')
+ list_display = ('name', 'section_count', 'block_count')
search_fields = ['name', 'section__song__artist', 'section__song__name']
inline_actions = ['add_sections',
'edit_sections', 'export_csv']
@@ -147,7 +147,7 @@ def edit_sections(self, request, obj, parent_obj=None):
# Retrieve or create Song object
song = None
if this_artist or this_name:
- song = get_or_create_song(this_artist, this_name)
+ song = get_or_create_song(this_artist, this_name)
section.song = song
section.start_time = request.POST.get(pre_fix + '_start_time')
diff --git a/backend/section/models.py b/backend/section/models.py
index 3c4de9fb1..c2b43d24e 100644
--- a/backend/section/models.py
+++ b/backend/section/models.py
@@ -72,11 +72,11 @@ def section_count(self):
section_count.short_description = "Sections"
- def experiment_count(self):
- """Number of Experiments"""
- return self.experiment_set.count()
+ def block_count(self):
+ """Number of Blocks"""
+ return self.block_set.count()
- experiment_count.short_description = "Experiments"
+ block_count.short_description = "Blocks"
def update_sections(self):
"""Update the sections from the csv file"""
@@ -148,7 +148,7 @@ def is_number(string):
# if same section already exists, update it with new info
for ex_section in existing_sections:
if ex_section.filename == section.filename:
- if song:
+ if song:
ex_section.song = song
ex_section.save()
ex_section.start_time = section.start_time
@@ -219,7 +219,7 @@ def export_sections(self):
def update_admin_csv(self):
"""Update csv data for admin"""
csvfile = CsvStringBuilder()
- writer = csv.writer(csvfile)
+ writer = csv.writer(csvfile)
for section in self.section_set.all():
if section.song:
this_artist = section.song.artist
diff --git a/backend/session/tests/test_session.py b/backend/session/tests/test_session.py
index 60d0071d2..08965c220 100644
--- a/backend/session/tests/test_session.py
+++ b/backend/session/tests/test_session.py
@@ -3,7 +3,7 @@
from django.test import TestCase
from django.utils import timezone
-from experiment.models import Experiment
+from experiment.models import Block
from participant.models import Participant
from section.models import Playlist, Section, Song
from result.models import Result
@@ -14,25 +14,25 @@ class SessionTest(TestCase):
@classmethod
def setUpTestData(cls):
-
+
cls.participant = Participant.objects.create(unique_hash=42)
- cls.experiment = Experiment.objects.create(
+ cls.block = Block.objects.create(
rules='RHYTHM_BATTERY_INTRO', slug='test')
cls.playlist = Playlist.objects.create(
name='Test playlist'
)
cls.session = Session.objects.create(
- experiment=cls.experiment,
+ block=cls.block,
participant=cls.participant,
playlist=cls.playlist
)
-
+
def test_create(self):
data = {
- 'experiment_id': self.experiment.pk,
+ 'block_id': self.block.pk,
'playlist_id': self.playlist.pk,
'participant_id': self.participant.pk
- }
+ }
response = self.client.post('/session/create', data)
assert response.status_code != 500
@@ -42,7 +42,7 @@ def test_finalize(self):
csrf_token = response_data.get('csrf_token')
participant = Participant.objects.get(pk=response_data.get('id'))
session = Session.objects.create(
- experiment=self.experiment,
+ block=self.block,
participant=participant)
data = {
'csrfmiddlewaretoken:': csrf_token
@@ -51,13 +51,13 @@ def test_finalize(self):
assert response.status_code == 200
assert Session.objects.filter(finished_at__isnull=False).count() == 1
- def test_total_questions(self):
+ def test_total_questions(self):
assert self.session.total_questions() == 0
Result.objects.create(
session=self.session
)
assert self.session.total_questions() == 1
-
+
def test_skipped_answered_questions(self):
Result.objects.create(
session=self.session,
@@ -75,23 +75,23 @@ def test_skipped_answered_questions(self):
given_response=''
)
assert self.session.skipped_questions() == 2
-
+
def test_percentile_rank(self):
# create one session with relatively low score
Session.objects.create(
- experiment=self.experiment,
+ block=self.block,
participant=self.participant,
final_score=24,
finished_at=timezone.now()
)
# create one unfinished session with relatively high score
Session.objects.create(
- experiment=self.experiment,
+ block=self.block,
participant=self.participant,
final_score=180
)
finished_session = Session.objects.create(
- experiment=self.experiment,
+ block=self.block,
participant=self.participant,
final_score=42,
finished_at=timezone.now()
@@ -140,10 +140,10 @@ def test_json_data(self):
self.session.save_json_data({'test_len': 'tested_len'})
self.assertEqual(len(self.session.json_data), 2)
- def test_json_data_direct(self):
+ def test_json_data_direct(self):
self.session.json_data.update({'test_direct': 'tested_direct'})
self.session.save()
- self.assertEqual(self.session.json_data['test_direct'], 'tested_direct')
+ self.assertEqual(self.session.json_data['test_direct'], 'tested_direct')
self.session.save_json_data({'test_direct_len': 'tested_direct_len'})
self.session.save()
self.assertEqual(len(self.session.json_data), 2)
diff --git a/backend/session/tests/test_utils.py b/backend/session/tests/test_utils.py
index 72d8340ac..64dca5407 100644
--- a/backend/session/tests/test_utils.py
+++ b/backend/session/tests/test_utils.py
@@ -1,7 +1,7 @@
from django.test import TestCase
-from experiment.models import Experiment
+from experiment.models import Block
from participant.models import Participant
from result.models import Result
from session.models import Session
@@ -14,10 +14,10 @@ class SessionUtilsTest(TestCase):
@classmethod
def setUpTestData(cls):
cls.participant = Participant.objects.create(unique_hash=42)
- cls.experiment = Experiment.objects.create(
+ cls.block = Block.objects.create(
rules='MUSICAL_PREFERENCES', slug='test')
cls.session = Session.objects.create(
- experiment=cls.experiment,
+ block=cls.block,
participant=cls.participant,
)
# create results with various question_keys, and scores from 0 to 9
@@ -28,17 +28,16 @@ def setUpTestData(cls):
question_key=keys[i],
score=i
)
-
+
def test_relevant_results_without_filter(self):
results = self.session.get_relevant_results()
assert results.count() == n_results
-
+
def test_relevant_results_with_filter(self):
results = self.session.get_relevant_results(['a', 'b'])
assert results.count() == 6
assert 'd' not in results.values_list('question_key')
-
+
def test_previous_score(self):
result = self.session.get_previous_result(['c', 'd'])
assert result.score == 9
-
diff --git a/backend/session/tests/test_views.py b/backend/session/tests/test_views.py
index 25b6f63ec..26eb53122 100644
--- a/backend/session/tests/test_views.py
+++ b/backend/session/tests/test_views.py
@@ -1,6 +1,6 @@
from django.test import TestCase
-from experiment.models import Experiment, ExperimentCollection, Phase, GroupedBlock
+from experiment.models import Block, ExperimentCollection, Phase, GroupedBlock
from experiment.actions.utils import COLLECTION_KEY
from participant.models import Participant
from section.models import Playlist
@@ -13,12 +13,12 @@ def setUpTestData(cls):
cls.participant = Participant.objects.create(unique_hash=42)
cls.playlist1 = Playlist.objects.create(name='First Playlist')
cls.playlist2 = Playlist.objects.create(name='Second Playlist')
- cls.experiment = Experiment.objects.create(
+ cls.block = Block.objects.create(
name='TestViews',
slug='testviews',
rules='RHYTHM_BATTERY_INTRO'
)
- cls.experiment.playlists.add(
+ cls.block.playlists.add(
cls.playlist1, cls.playlist2
)
@@ -29,28 +29,28 @@ def setUp(self):
def test_create_with_playlist(self):
request = {
- "experiment_id": self.experiment.id,
+ "block_id": self.block.id,
"playlist_id": self.playlist2.id
}
self.client.post('/session/create/', request)
new_session = Session.objects.get(
- experiment=self.experiment, participant=self.participant)
+ block=self.block, participant=self.participant)
assert new_session
assert new_session.playlist == self.playlist2
def test_create_without_playlist(self):
request = {
- "experiment_id": self.experiment.id
+ "block_id": self.block.id
}
self.client.post('/session/create/', request)
new_session = Session.objects.get(
- experiment=self.experiment, participant=self.participant)
+ block=self.block, participant=self.participant)
assert new_session
assert new_session.playlist == self.playlist1
def test_next_round(self):
session = Session.objects.create(
- experiment=self.experiment, participant=self.participant)
+ block=self.block, participant=self.participant)
response = self.client.get(
f'/session/{session.id}/next_round/')
assert response
@@ -62,7 +62,7 @@ def test_next_round_with_collection(self):
request_session[COLLECTION_KEY] = slug
request_session.save()
session = Session.objects.create(
- experiment=self.experiment, participant=self.participant)
+ block=self.block, participant=self.participant)
response = self.client.get(
f'/session/{session.id}/next_round/')
assert response
@@ -70,7 +70,7 @@ def test_next_round_with_collection(self):
assert changed_session.load_json_data().get(COLLECTION_KEY) is None
phase = Phase.objects.create(series=collection)
GroupedBlock.objects.create(
- phase=phase, experiment=self.experiment)
+ phase=phase, block=self.block)
response = self.client.get(
f'/session/{session.id}/next_round/')
changed_session = Session.objects.get(pk=session.pk)
diff --git a/backend/session/views.py b/backend/session/views.py
index 1864b3dda..06e0a18f2 100644
--- a/backend/session/views.py
+++ b/backend/session/views.py
@@ -17,28 +17,28 @@ def create_session(request):
# Current participant
participant = get_participant(request)
- # Get experiment
- experiment_id = request.POST.get("experiment_id")
- if not experiment_id:
- return HttpResponseBadRequest("experiment_id not defined")
+ # Get block
+ block_id = request.POST.get("block_id")
+ if not block_id:
+ return HttpResponseBadRequest("block_id not defined")
try:
- experiment = Block.objects.get(pk=experiment_id, active=True)
+ block = Block.objects.get(pk=block_id, active=True)
except Block.DoesNotExist:
raise Http404("Block does not exist")
# Create new session
- session = Session(experiment=experiment, participant=participant)
+ session = Session(block=block, participant=participant)
if request.POST.get("playlist_id"):
try:
playlist = Playlist.objects.get(
- pk=request.POST.get("playlist_id"), experiment__id=session.experiment.id)
+ pk=request.POST.get("playlist_id"), block__id=session.block.id)
session.playlist = playlist
except:
raise Http404("Playlist does not exist")
- elif experiment.playlists.count() >= 1:
+ elif block.playlists.count() >= 1:
# register first playlist
- session.playlist = experiment.playlists.first()
+ session.playlist = block.playlists.first()
# Save session
session.save()
@@ -58,7 +58,7 @@ def continue_session(request, session_id):
def next_round(request, session_id):
"""
- Fall back to continue an experiment is case next_round data is missing
+ Fall back to continue an block is case next_round data is missing
This data is normally provided in: result()
"""
# Current participant
@@ -67,14 +67,14 @@ def next_round(request, session_id):
session = get_object_or_404(Session,
pk=session_id, participant__id=participant.id)
- # check if this experiment is part of an ExperimentCollection
+ # check if this block is part of an ExperimentCollection
collection_slug = request.session.get(COLLECTION_KEY)
if collection_slug:
# check that current session does not have the collection information saved yet
if not session.load_json_data().get(COLLECTION_KEY):
# set information of the ExperimentCollection to the session
collection = ExperimentCollection.objects.get(slug=collection_slug)
- if collection and session.experiment in collection.associated_experiments():
+ if collection and session.block in collection.associated_blocks():
session.save_json_data({COLLECTION_KEY: collection_slug})
# Get next round for given session
diff --git a/backend/theme/serializers.py b/backend/theme/serializers.py
index db1bba179..9228f425f 100644
--- a/backend/theme/serializers.py
+++ b/backend/theme/serializers.py
@@ -23,7 +23,7 @@ def serialize_footer(footer: FooterConfig) -> dict:
def serialize_header(header: HeaderConfig) -> dict:
return {
- 'nextExperimentButtonText': _('Next experiment'),
+ 'nextBlockButtonText': _('Next experiment'),
'aboutButtonText': _('About us'),
'score': {
'scoreClass': 'gold',
diff --git a/backend/theme/tests/test_serializers.py b/backend/theme/tests/test_serializers.py
index c9d8bb920..d28a4bbd5 100644
--- a/backend/theme/tests/test_serializers.py
+++ b/backend/theme/tests/test_serializers.py
@@ -76,8 +76,8 @@ def test_footer_serializer(self):
self.assertEqual(serialize_footer(self.footer), expected_json)
def test_header_serializer(self):
- expected_json = {
- 'nextExperimentButtonText': 'Next experiment',
+ expected_json = {
+ 'nextBlockButtonText': 'Next experiment',
'aboutButtonText': 'About us',
'score': {
'scoreClass': 'gold',
diff --git a/e2e/tests/base_test.py b/e2e/tests/base_test.py
index 7c2ba1633..3d17e9365 100644
--- a/e2e/tests/base_test.py
+++ b/e2e/tests/base_test.py
@@ -79,16 +79,16 @@ def agree_to_consent(self, h4_text='informed consent', button_text='I agree'):
print("I agree button clicked")
- def check_for_error(self, experiment_name, experiment_slug='[no slug provided]'):
+ def check_for_error(self, block_name, block_slug='[no slug provided]'):
if "Error" in self.driver.find_element(By.TAG_NAME, "body").text:
- raise Exception(f"Could not load {experiment_name} experiment, please check the server logs and make sure the slug ({experiment_slug}) is correct.")
+ raise Exception(f"Could not load {block_name} experiment, please check the server logs and make sure the slug ({block_slug}) is correct.")
- def take_screenshot(self, experiment_name, notes=""):
+ def take_screenshot(self, block_name, notes=""):
current_time = time.strftime("%Y-%m-%d-%H-%M-%S")
- screen_shot_path = f"screenshots/{experiment_name}-{current_time}.png"
+ screen_shot_path = f"screenshots/{block_name}-{current_time}.png"
print('Capturing screenshot to', screen_shot_path, notes)
self.driver.get_screenshot_as_file(screen_shot_path)
- def handle_error(self, e, experiment_name):
- self.take_screenshot(experiment_name, str(e))
+ def handle_error(self, e, block_name):
+ self.take_screenshot(block_name, str(e))
self.fail(e)
diff --git a/e2e/tests/e2e/test_beatalignment.py b/e2e/tests/e2e/test_beatalignment.py
index e1e0e116c..1674df486 100644
--- a/e2e/tests/e2e/test_beatalignment.py
+++ b/e2e/tests/e2e/test_beatalignment.py
@@ -9,11 +9,11 @@
class TestBeatAlignment(BaseTest):
def test_beatalignment(self):
- experiment_name = "beat_alignment"
- experiment_slug = self.config['experiment_slugs'][experiment_name]
- self.driver.get(f"{self.base_url}/{experiment_slug}")
+ block_name = "beat_alignment"
+ block_slug = self.config['block_slugs'][block_name]
+ self.driver.get(f"{self.base_url}/{block_slug}")
- self.check_for_error(experiment_name, experiment_slug)
+ self.check_for_error(block_name, block_slug)
WebDriverWait(self.driver, 5).until(expected_conditions.element_to_be_clickable((By.XPATH, '//button[text()="Ok"]'))).click()
diff --git a/e2e/tests/e2e/test_categorization.py b/e2e/tests/e2e/test_categorization.py
index 580cb58c1..41c62a059 100644
--- a/e2e/tests/e2e/test_categorization.py
+++ b/e2e/tests/e2e/test_categorization.py
@@ -12,16 +12,16 @@ class TestCategorization(BaseTest):
def test_categorization(self):
- experiment_name = "categorization"
+ block_name = "categorization"
try:
self.driver.delete_all_cookies()
- experiment_slug = self.config['experiment_slugs'][experiment_name]
- self.driver.get(f"{self.base_url}/{experiment_slug}")
+ block_slug = self.config['block_slugs'][block_name]
+ self.driver.get(f"{self.base_url}/{block_slug}")
# if page body contains the word "Error", raise an exception
- self.check_for_error(experiment_name, experiment_slug)
+ self.check_for_error(block_name, block_slug)
# wait until h4 element is present and contains "INFORMED CONSENT" text (case-insensitive)
WebDriverWait(self.driver, 5) \
@@ -129,4 +129,4 @@ def test_categorization(self):
training = False
except Exception as e:
- self.handle_error(e, experiment_name)
+ self.handle_error(e, block_name)
diff --git a/e2e/tests/e2e/test_eurovision.py b/e2e/tests/e2e/test_eurovision.py
index bd9544424..d1549f392 100644
--- a/e2e/tests/e2e/test_eurovision.py
+++ b/e2e/tests/e2e/test_eurovision.py
@@ -12,15 +12,15 @@ class TestEurovision(BaseTest):
def test_eurovision(self):
- experiment_name = "eurovision"
+ block_name = "eurovision"
try:
- experiment_slug = self.config['experiment_slugs'][experiment_name]
- self.driver.get(f"{self.base_url}/{experiment_slug}")
+ block_slug = self.config['block_slugs'][block_name]
+ self.driver.get(f"{self.base_url}/{block_slug}")
# if page body contains the word "Error", raise an exception
- self.check_for_error(experiment_name, experiment_slug)
+ self.check_for_error(block_name, block_slug)
# Check & Agree to Informed Consent
self.agree_to_consent()
@@ -130,4 +130,4 @@ def test_eurovision(self):
print("Eurovision Test completed!")
except Exception as e:
- self.handle_error(e, experiment_name)
+ self.handle_error(e, block_name)
diff --git a/frontend/src/API.ts b/frontend/src/API.ts
index 4ca97f79a..7132eea52 100644
--- a/frontend/src/API.ts
+++ b/frontend/src/API.ts
@@ -99,7 +99,7 @@ export const createSession = async ({ block, participant, playlist }: CreateSess
const response = await axios.post(
API_BASE_URL + URLS.session.create,
qs.stringify({
- experiment_id: block.id,
+ block_id: block.id,
playlist_id: playlist.current,
csrfmiddlewaretoken: participant.csrf_token,
})
diff --git a/frontend/src/components/ExperimentCollection/ExperimentCollection.test.tsx b/frontend/src/components/ExperimentCollection/ExperimentCollection.test.tsx
index 78df22019..8d6a5fc82 100644
--- a/frontend/src/components/ExperimentCollection/ExperimentCollection.test.tsx
+++ b/frontend/src/components/ExperimentCollection/ExperimentCollection.test.tsx
@@ -53,7 +53,7 @@ const blockWithAllProps = getBlock({ image: 'some_image.jpg', description: 'Some
describe('ExperimentCollection', () => {
it('forwards to a single block if it receives an empty dashboard array', async () => {
- mock.onGet().replyOnce(200, { dashboard: [], nextExperiment: block1 });
+ mock.onGet().replyOnce(200, { dashboard: [], nextBlock: block1 });
render(
@@ -76,7 +76,7 @@ describe('ExperimentCollection', () => {
});
it('shows a placeholder if no image is available', () => {
- mock.onGet().replyOnce(200, { dashboard: [block1], nextExperiment: block1 });
+ mock.onGet().replyOnce(200, { dashboard: [block1], nextBlock: block1 });
render(
@@ -88,7 +88,7 @@ describe('ExperimentCollection', () => {
});
it('shows the image if it is available', () => {
- mock.onGet().replyOnce(200, { dashboard: [blockWithAllProps], nextExperiment: block1 });
+ mock.onGet().replyOnce(200, { dashboard: [blockWithAllProps], nextBlock: block1 });
render(
@@ -100,7 +100,7 @@ describe('ExperimentCollection', () => {
});
it('shows the description if it is available', () => {
- mock.onGet().replyOnce(200, { dashboard: [blockWithAllProps], nextExperiment: block1 });
+ mock.onGet().replyOnce(200, { dashboard: [blockWithAllProps], nextBlock: block1 });
render(
@@ -112,7 +112,7 @@ describe('ExperimentCollection', () => {
});
it('shows consent first if available', async () => {
- mock.onGet().replyOnce(200, { consent: 'This is our consent form!
', dashboard: [blockWithAllProps], nextExperiment: block1 });
+ mock.onGet().replyOnce(200, { consent: 'This is our consent form!
', dashboard: [blockWithAllProps], nextBlock: block1 });
render(
@@ -124,7 +124,7 @@ describe('ExperimentCollection', () => {
});
it('shows a footer if a theme with footer is available', async () => {
- mock.onGet().replyOnce(200, { dashboard: [blockWithAllProps], nextExperiment: block1, theme });
+ mock.onGet().replyOnce(200, { dashboard: [blockWithAllProps], nextBlock: block1, theme });
render(
diff --git a/frontend/src/components/ExperimentCollection/ExperimentCollection.tsx b/frontend/src/components/ExperimentCollection/ExperimentCollection.tsx
index de3340690..eac1ab1fe 100644
--- a/frontend/src/components/ExperimentCollection/ExperimentCollection.tsx
+++ b/frontend/src/components/ExperimentCollection/ExperimentCollection.tsx
@@ -32,7 +32,7 @@ const ExperimentCollection = ({ match }: ExperimentCollectionProps) => {
const participant = useBoundStore((state) => state.participant);
const setTheme = useBoundStore((state) => state.setTheme);
const participantIdUrl = participant?.participant_id_url;
- const nextExperiment = experimentCollection?.nextExperiment;
+ const nextBlock = experimentCollection?.nextBlock;
const displayDashboard = experimentCollection?.dashboard.length;
const showConsent = experimentCollection?.consent;
const totalScore = experimentCollection?.totalScore;
@@ -73,8 +73,8 @@ const ExperimentCollection = ({ match }: ExperimentCollectionProps) => {
)
}
- if (!displayDashboard && nextExperiment) {
- return
+ if (!displayDashboard && nextBlock) {
+ return
}
return (
diff --git a/frontend/src/components/ExperimentCollection/ExperimentCollectionDashboard/ExperimentCollectionDashboard.tsx b/frontend/src/components/ExperimentCollection/ExperimentCollectionDashboard/ExperimentCollectionDashboard.tsx
index 8b547803a..dfb572d93 100644
--- a/frontend/src/components/ExperimentCollection/ExperimentCollectionDashboard/ExperimentCollectionDashboard.tsx
+++ b/frontend/src/components/ExperimentCollection/ExperimentCollectionDashboard/ExperimentCollectionDashboard.tsx
@@ -16,10 +16,10 @@ interface ExperimentCollectionDashboardProps {
export const ExperimentCollectionDashboard: React.FC = ({ experimentCollection, participantIdUrl, totalScore }) => {
const { dashboard, description } = experimentCollection;
- const { nextExperimentButtonText, aboutButtonText } = experimentCollection.theme?.header || { nextExperimentButtonText: "", aboutButtonText: "" };
+ const { nextBlockButtonText, aboutButtonText } = experimentCollection.theme?.header || { nextBlockButtonText: "", aboutButtonText: "" };
const scoreDisplayConfig = experimentCollection.theme?.header?.score;
- const nextBlockSlug = experimentCollection.nextExperiment?.slug;
+ const nextBlockSlug = experimentCollection.nextBlock?.slug;
const showHeader = experimentCollection.theme?.header;
const socialMediaConfig = experimentCollection.socialMediaConfig;
@@ -35,7 +35,7 @@ export const ExperimentCollectionDashboard: React.FC
diff --git a/frontend/src/components/Final/Final.test.tsx b/frontend/src/components/Final/Final.test.tsx
index 3eff6a18c..c6b08cf35 100644
--- a/frontend/src/components/Final/Final.test.tsx
+++ b/frontend/src/components/Final/Final.test.tsx
@@ -43,7 +43,7 @@ describe('Final Component', () => {
render(
{
render(
{
const history = createMemoryHistory();
const mockActionTexts = {
- all_experiments: 'All Experiments',
+ all_blocks: 'All Blocks',
profile: 'Profile',
};
diff --git a/frontend/src/components/Profile/Profile.jsx b/frontend/src/components/Profile/Profile.jsx
index c8edaa312..8c61f437f 100644
--- a/frontend/src/components/Profile/Profile.jsx
+++ b/frontend/src/components/Profile/Profile.jsx
@@ -73,7 +73,7 @@ export const ProfileView = (data) => {
score.experiment_slug
)}
>
- {score.experiment_name}
+ {score.block_name}
{score.score} {data.points}
diff --git a/frontend/src/stories/Header.stories.tsx b/frontend/src/stories/Header.stories.tsx
index d9a7b2e7d..37b54b517 100644
--- a/frontend/src/stories/Header.stories.tsx
+++ b/frontend/src/stories/Header.stories.tsx
@@ -13,7 +13,7 @@ export default {
function getHeaderData(overrides = {}) {
return {
description: "Experiment ABC This is the experiment description
",
- nextExperimentSlug: '/th1-mozart',
+ nextBlockSlug: '/th1-mozart',
nextBlockButtonText: 'Volgende experiment',
collectionSlug: '/collection/thkids',
aboutButtonText: 'Over ons',
diff --git a/frontend/src/types/ExperimentCollection.ts b/frontend/src/types/ExperimentCollection.ts
index 177320991..8eaf69a5e 100644
--- a/frontend/src/types/ExperimentCollection.ts
+++ b/frontend/src/types/ExperimentCollection.ts
@@ -21,7 +21,7 @@ export default interface ExperimentCollection {
name: string;
description: string;
dashboard: Block[];
- nextExperiment: Block | null;
+ nextBlock: Block | null;
aboutContent: string;
consent?: Consent;
theme?: Theme;
diff --git a/frontend/src/types/Theme.ts b/frontend/src/types/Theme.ts
index b5ae06413..aaedf662f 100644
--- a/frontend/src/types/Theme.ts
+++ b/frontend/src/types/Theme.ts
@@ -7,7 +7,7 @@ export interface ScoreDisplayConfig {
}
export interface Header {
- nextExperimentButtonText: string;
+ nextBlockButtonText: string;
aboutButtonText: string;
score: ScoreDisplayConfig;
};