Skip to content

Commit

Permalink
Merge main into develop (#1351)
Browse files Browse the repository at this point in the history
* fix: correct video links

* fix: Refactor Docker commands in scripts (#1282)

Update the Docker commands in the scripts to use the "docker compose" syntax instead of "docker-compose".

* fix: Fix some search & replace too many, where I mistook `docker-compose-deploy.yml` for a `docker-compose` command (#1283)

* fix(style): Prevent percentage circle from overlapping background circle (#1281)

* Added: Disable pinch zoom on iOS (#1284)

* feat: Add useDisableIOSPinchZoomOnTouchDevices hook

This commit adds a new hook called useDisableIOSPinchZoomOnTouchDevices to the frontend codebase. The hook is responsible for preventing pinch zoom gestures on iOS devices. It is used in the App component to disable pinch zoom on touch devices.

* feat: Add touch-action property to disable pinch zoom on iOS

* fix(style): Move percentage circle down 100% to align with background circle

* fix: use vimeo for videos

* fix: redefine ButtonArray button gaps

* fix: docker compose without hyphen

* fix: update podman-compose file names (#1290)

* adjust debrief template

* Fixed: Fix Circle percentage overlap issue (attempt 3) (#1291)

* style: Move rotate transform and transform origin to the circle's svg level

* story(AutoPlay): Add `AutoPlay` story

* chore(deps): Update `package.json` version to `2.2.5` (#1293)

* fix: remove non-breaking spaces when showing composer / ensemble / piece

* fix: adjust scaling of image in th_preverbal

* chore: update version

* chore: remove unused import

* Refactor: Remove `logoClickConfirm` and make user go to the experiment dashboard directly (#1303)

* refactor: Remove `logoClickConfirm` and make user go to the experiment dashboard directly

* chore(deps): Update package version to 2.2.7

---------

Co-authored-by: BeritJanssen <berit.janssen@gmail.com>
  • Loading branch information
drikusroor and BeritJanssen authored Nov 5, 2024
1 parent 99a8db4 commit 8831ccb
Show file tree
Hide file tree
Showing 26 changed files with 235 additions and 215 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,22 @@ Install [Docker Desktop](https://docs.docker.com/desktop/).
Make a copy of [the file](https://github.com/Amsterdam-Music-Lab/MUSCLE/blob/develop/.env.dist) `.env.dist` (in the same directory as this README) and rename it to `.env.` This file contains variables used by Docker to start up a container network serving MUSCLE.

Start Docker (the app icon is a whale carrying containers). Then, open a terminal and run
`docker-compose up` (add `sudo` on Linux).
This command starts up the containers defined in `docker-compose.yaml`:
`docker compose up` (add `sudo` on Linux).
This command starts up the containers defined in `docker compose.yaml`:
- a PostgreSQL container, for storing experiment/user/playlist data, saved on the host machine in the Docker user data, represented in the volume `db_data`. Data added to the database will persist if the container is shut down.
- a ip2country container, which provides country codes for ip addresses, used for demographic information of users.
- a container of the server, defined in DockerfileDevelop in `backend`. The Dockerfile defines the Python version and installs development dependencies. The startup command runs migrations and then starts up a Django development server.
- a container of the client, defined in DockerfileDevelop in `frontend`. The Dockerfile defines the node version and installs node modules. The startup command kicks off a React development server.

Once you see all containers have started up, open your browser and navigate to [localhost:3000](http://localhost:3000). You should now be able to see the first screen of the Goldsmiths Musical Sophistication Index questionnaire.

Since the `docker-compose.yaml` defines bind mounts for `backend` and `frontend`, any changes to the files on the host are immediately reflected in the containers, which means code watching works and hot reload works in the same way as with a native node or Django server.
Since the `docker compose.yaml` defines bind mounts for `backend` and `frontend`, any changes to the files on the host are immediately reflected in the containers, which means code watching works and hot reload works in the same way as with a native node or Django server.

To stop the containers, press `ctrl-c` or (in another terminal) run
`docker-compose down`.
`docker compose down`.

## Production build
A production build should define its own `docker-compose.yaml`, making use of the `Dockerfile` of the `backend` and `frontend` environments. It should also define a custom .env file, with safe passwords for the SQL database and the Python backend. Instead of mounting the entire backend and frontend directory and using the development servers, the backend should serve with gunicorn, and the frontend should use a build script to compile static html, css and JavaScript.
A production build should define its own `docker compose.yaml`, making use of the `Dockerfile` of the `backend` and `frontend` environments. It should also define a custom .env file, with safe passwords for the SQL database and the Python backend. Instead of mounting the entire backend and frontend directory and using the development servers, the backend should serve with gunicorn, and the frontend should use a build script to compile static html, css and JavaScript.

## Troubleshooting

Expand Down
40 changes: 8 additions & 32 deletions backend/experiment/rules/toontjehoger_1_mozart.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,9 @@ def get_answer_explainer(self, session, round):

heading = "Goed gedaan!" if correct_answer_given else "Helaas!"

feedback_correct = "Het juiste antwoord was inderdaad {}.".format(
last_result.expected_response
)
feedback_incorrect = (
"Antwoord {} is niet goed! Het juiste antwoord was {}.".format(
last_result.given_response, last_result.expected_response
)
feedback_correct = "Het juiste antwoord was inderdaad {}.".format(last_result.expected_response)
feedback_incorrect = "Antwoord {} is niet goed! Het juiste antwoord was {}.".format(
last_result.given_response, last_result.expected_response
)
feedback = feedback_correct if correct_answer_given else feedback_incorrect

Expand All @@ -120,22 +116,14 @@ def get_score(self, session):
# Feedback message
last_result = session.last_result()
section = last_result.section
feedback = (
"Je hoorde {} van {}.".format(
section.song.name, non_breaking_spaces(section.artist_name())
)
if section
else ""
)
feedback = "Je hoorde {} van {}.".format(section.song.name, section.artist_name()) if section else ""

# Return score view
config = {"show_total_score": True}
score = Score(session, config=config, feedback=feedback)
return [score]

def get_image_trial(
self, session, section_group, image_url, question, expected_response
):
def get_image_trial(self, session, section_group, image_url, question, expected_response):
# Config
# -----------------
section = session.playlist.get_section(filter_by={"group": section_group})
Expand Down Expand Up @@ -176,20 +164,14 @@ def get_image_trial(
"E": "E",
},
view="BUTTON_ARRAY",
result_id=prepare_result(
key, session, section=section, expected_response=expected_response
),
result_id=prepare_result(key, session, section=section, expected_response=expected_response),
submits=True,
style=STYLE_TOONTJEHOGER,
)
form = Form([question])

image_trial = Trial(
html=HTML(
body='<img src="{}" style="height:calc(100% - 260px);max-height:326px;max-width: 100%;"/>'.format(
image_url
)
),
html=HTML(body='<img src="{}" style="max-height:326px;max-width: 100%;"/>'.format(image_url)),
feedback_form=form,
title=self.TITLE,
)
Expand All @@ -211,15 +193,10 @@ def get_explainer_round2():
return [explainer]

def calculate_score(self, result, data):
score = (
self.SCORE_CORRECT
if result.expected_response == result.given_response
else self.SCORE_WRONG
)
score = self.SCORE_CORRECT if result.expected_response == result.given_response else self.SCORE_WRONG
return score

def get_final_round(self, session):

# Finish session.
session.finish()
session.save()
Expand Down Expand Up @@ -255,7 +232,6 @@ def get_final_round(self, session):
return [*answer_explainer, *score, final, info]

def validate_playlist(self, playlist: Playlist):

errors = []

errors += super().validate_playlist(playlist)
Expand Down
6 changes: 4 additions & 2 deletions backend/experiment/rules/toontjehoger_2_preverbal.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,10 @@ def get_round1(self, session):

image_trial = Trial(
html=HTML(
body='<img src="{}" style="height:calc(100% - 260px);max-height:326px;max-width: 100%;"/>'.format(
"/images/experiments/toontjehoger/preverbal_1.webp")),
body='<img src="{}" style="max-height:326px;max-width: 100%;"/>'.format(
"/images/experiments/toontjehoger/preverbal_1.webp"
)
),
feedback_form=form,
title=self.TITLE,
)
Expand Down
16 changes: 7 additions & 9 deletions backend/experiment/rules/toontjehogerkids_1_mozart.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@


class ToontjeHogerKids1Mozart(ToontjeHoger1Mozart):
ID = 'TOONTJE_HOGER_KIDS_1_MOZART'
ID = "TOONTJE_HOGER_KIDS_1_MOZART"

QUESTION_URL1 = "/images/experiments/toontjehogerkids/mozart-effect1.webp"
QUESTION_URL2 = "/images/experiments/toontjehogerkids/mozart-effect2.webp"
Expand All @@ -25,14 +25,13 @@ def intro_explaliner(self):
Step("Kun jij het juiste antwoord vinden?"),
],
step_numbers=True,
button_label="Start"
button_label="Start",
)

def get_task_explainer(self):
return "Je vouwt een papier en knipt er twee hoekjes af, precies zoals op het plaatje. Welke vorm krijgt het papier dan?"

def get_final_round(self, session):

# Finish session.
session.finish()
session.save()
Expand All @@ -44,13 +43,12 @@ def get_final_round(self, session):
score = self.get_score(session)

# Final
final_text = "Goed gedaan!" if session.final_score >= 2 * \
self.SCORE_CORRECT else "Best lastig!"
final_text = "Goed gedaan!" if session.final_score >= 2 * self.SCORE_CORRECT else "Best lastig!"
final = Final(
session=session,
final_text=final_text,
rank=toontjehoger_ranks(session),
button={'text': 'Wat hebben we getest?'}
button={"text": "Wat hebben we getest?"},
)

# Info page
Expand All @@ -60,17 +58,17 @@ def get_final_round(self, session):
join("info", "toontjehogerkids", "debrief.html"),
{
"debrief": debrief_message,
"vid1": "https://video.leidenuniv.nl/embed/secure/iframe/entryId/1_moxxt7x6/uiConfId/44110401/st/0",
"vid1": "https://player.vimeo.com/video/1012736186?h=82640b5e3a",
"vid1_title": "Wat is het Mozart effect?",
"vid2": "https://video.leidenuniv.nl/embed/secure/iframe/entryId/1_trd2yc58/uiConfId/44110401/st/0",
"vid2": "https://player.vimeo.com/video/1012736336?h=e90fff89cd",
"vid2_title": "Hoe werkt het Mozart effect?",
},
)
info = Info(
body=body,
heading="Het Mozart effect",
button_label="Terug naar ToontjeHogerKids",
button_link=get_current_experiment_url(session)
button_link=get_current_experiment_url(session),
)

return [*answer_explainer, *score, final, info]
35 changes: 14 additions & 21 deletions backend/experiment/rules/toontjehogerkids_2_preverbal.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,25 @@


class ToontjeHogerKids2Preverbal(ToontjeHoger2Preverbal):
ID = 'TOONTJE_HOGER_KIDS_2_PREVERBAL'
ID = "TOONTJE_HOGER_KIDS_2_PREVERBAL"

def get_intro_explainer(self):
return Explainer(
instruction="Het eerste luisteren",
steps=[
Step(
"Je krijgt straks een soort grafieken van geluid te zien, met een uitlegfilmpje."),
Step(
"Welk plaatje denk jij dat hoort bij de stem van een mens?"),
Step(
"En hoor jij het verschil tussen twee babyhuiltjes?"),
Step("Je krijgt straks een soort grafieken van geluid te zien, met een uitlegfilmpje."),
Step("Welk plaatje denk jij dat hoort bij de stem van een mens?"),
Step("En hoor jij het verschil tussen twee babyhuiltjes?"),
],
step_numbers=True,
button_label="Start"
button_label="Start",
)

def get_spectrogram_info(self):
image_url = "/images/experiments/toontjehoger/spectrogram_info_nl.webp"
description = (
"Dit is een spectrogram. Wil je weten hoe dat werkt? Kijk dan het filmpje!"
)
video = "https://video.leidenuniv.nl/embed/secure/iframe/entryId/1_ghoti6z2/uiConfId/44110401/st/0"
body = f'<div class="center"><img src="{image_url}"></div><p>{description}</p><div style="max-width:608px"><div style="position:relative;padding-bottom:66.118421052632%"><iframe width="608" height="402" src="{video}" class="kmsembed" frameborder="0" title="Hoe werkt een spectrogram?" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0"></iframe></div></div>'
description = "Dit is een spectrogram. Wil je weten hoe dat werkt? Kijk dan het filmpje!"
video = "https://player.vimeo.com/video/1012736887?h=bac11b4075"
body = f'<div class="center"><img src="{image_url}"></div><p>{description}</p><div style="padding:56.25% 0 0 0;position:relative;margin-bottom:2vh;"><iframe src="{video}" frameborder="0" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="Hoe werkt een spectrogram?"></iframe></div><script src=https://player.vimeo.com/api/player.js></script>'

# Return answer info view
info = Info(
Expand Down Expand Up @@ -65,7 +60,7 @@ def get_score(self, session, rounds_passed):
feedback = "Helaas! Geluid A is de Franse baby."

# Return score view
config = {'show_total_score': True}
config = {"show_total_score": True}
score = Score(session, config=config, feedback=feedback)
return [score]

Expand All @@ -76,7 +71,6 @@ def get_round2_question(self):
return "Hierboven zie je twee spectrogrammen van babyhuiltjes. Eentje is een Duitse baby en eentje is een Franse baby. De talen Frans en Duits klinken heel anders. Kun jij bedenken welke van deze baby’s de Franse baby is?"

def get_final_round(self, session):

# Finish session.
session.finish()
session.save()
Expand All @@ -85,13 +79,12 @@ def get_final_round(self, session):
score = self.get_score(session, session.get_rounds_passed())

# Final
final_text = "Goed gedaan!" if session.final_score >= 2 * \
self.SCORE_CORRECT else "Best lastig!"
final_text = "Goed gedaan!" if session.final_score >= 2 * self.SCORE_CORRECT else "Best lastig!"
final = Final(
session=session,
final_text=final_text,
rank=toontjehoger_ranks(session),
button={'text': 'Wat hebben we getest?'}
button={"text": "Wat hebben we getest?"},
)

# Info page
Expand All @@ -100,17 +93,17 @@ def get_final_round(self, session):
join("info", "toontjehogerkids", "debrief.html"),
{
"debrief": debrief_message,
"vid1": "https://video.leidenuniv.nl/embed/secure/iframe/entryId/1_q8r74zji/uiConfId/44110401/st/0",
"vid1": "https://player.vimeo.com/video/1012712004?h=1ec875caec",
"vid1_title": "Franse en Duitse baby",
"vid2": "https://video.leidenuniv.nl/embed/secure/iframe/entryId/1_rteiyere/uiConfId/44110401/st/0",
"vid2": "https://player.vimeo.com/video/1012712095?h=020b0bfc37",
"vid2_title": "Geluiden in Duitsland en Frankrijk",
},
)
info = Info(
body=body,
heading="Het eerste luisteren",
button_label="Terug naar ToontjeHogerKids",
button_link=get_current_experiment_url(session)
button_link="/collection/thkids",
)

return [*score, final, info]
Loading

0 comments on commit 8831ccb

Please sign in to comment.