Ajoute un suivi xAPI optionnel (bolt-on) au paquet SCORM exporté
Build and deploy / test-python (push) Successful in 9m41s
Build and deploy / test-js (push) Successful in 51s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped

Greffe l'envoi de statements xAPI vers un LRS configurable par le
créateur du jeu, en parallèle du reporting SCORM existant : réglages
stockés en base (_meta), formulaire dans la modale d'export, injection
dans le paquet exporté. Relié aussi bien à l'action de flow "Modifier
un score/statut" qu'au parcours quête/quiz (qui alimentait déjà le
SCORM classique via un chemin séparé).

L'export ne se lance plus automatiquement à l'ouverture de la modale,
pour laisser le temps d'enregistrer les réglages xAPI avant de générer
le paquet.
This commit is contained in:
william
2026-09-05 10:00:57 +02:00
parent 7ebc9b143f
commit f7a50e5afe
13 changed files with 422 additions and 3 deletions
+2
View File
@@ -34,6 +34,8 @@ from .games.create_game import create_game
from .games.update_game_name import update_game_name
from .games.delete_game import delete_game
from .games.move_game import move_game
from .games.get_xapi_settings import get_xapi_settings
from .games.set_xapi_settings import set_xapi_settings
from .games.game_type_catalog import (
ONBOARDING_TYPES, DEFAULT_ONBOARDING_TYPE,
get_onboarding_type, get_onboarding_type_raw, set_onboarding_type,
+23
View File
@@ -0,0 +1,23 @@
from ..connection import connect
def get_xapi_settings(slug):
"""Réglages xAPI de CE jeu (voir set_xapi_settings.py — stockés dans
_meta, même convention que 'name'/'onboarding_type', voir
db/games/game_type_catalog.py) : URL du LRS (Learning Record Store)
+ identifiants, saisis une seule fois par le créateur du jeu (voir
routes/publish/xapi_settings.py) plutôt que négociés à chaque
lancement (jamais le protocole cmi5 complet, voir publish/
build_scorm_package.py::build_scorm_zip). Chaînes vides si non
configuré — `endpoint` vide signifie "xAPI désactivé pour ce jeu"."""
conn = connect(slug)
rows = conn.execute(
"SELECT key, value FROM _meta WHERE key IN ('xapi_lrs_endpoint', 'xapi_lrs_login', 'xapi_lrs_password')"
).fetchall()
conn.close()
values = {row["key"]: row["value"] for row in rows}
return {
"endpoint": values.get("xapi_lrs_endpoint") or "",
"login": values.get("xapi_lrs_login") or "",
"password": values.get("xapi_lrs_password") or "",
}
+24
View File
@@ -0,0 +1,24 @@
from ..connection import connect
def set_xapi_settings(slug, endpoint, login, password=None):
"""Enregistre les réglages xAPI de CE jeu (voir get_xapi_settings.py).
`password=None` (champ laissé vide côté formulaire, voir
routes/publish/xapi_settings.py) laisse le mot de passe déjà
enregistré INCHANGÉ — jamais écrasé par une chaîne vide, pour ne pas
obliger à le retaper à chaque modification de l'URL/du login, et pour
que la route GET puisse ne jamais renvoyer sa valeur au navigateur
(juste un booléen "déjà configuré")."""
conn = connect(slug)
conn.execute(
"INSERT OR REPLACE INTO _meta (key, value) VALUES ('xapi_lrs_endpoint', ?)", (endpoint or "",)
)
conn.execute(
"INSERT OR REPLACE INTO _meta (key, value) VALUES ('xapi_lrs_login', ?)", (login or "",)
)
if password is not None:
conn.execute(
"INSERT OR REPLACE INTO _meta (key, value) VALUES ('xapi_lrs_password', ?)", (password,)
)
conn.commit()
conn.close()