- outputs/platform, outputs/prospect : scripts de construction des decks commerciaux + captures sources et .pptx generes. - outputs/mnaha : seed complet de l'instance de demo luxembourgeoise (scripts par etape, contenus, images generees), le deck en version marque blanche et en version brandee, le PDF de presentation. - outputs/Wireframes : maquettes app mobile, app web et manager. - interview clients : notes de l'entretien Fourneau St Michel. state.json et les __pycache__ sont ignores : le premier porte les cles d'API de l'instance seedee, les scripts le regenerent.
145 lines
5.6 KiB
Python
145 lines
5.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Étape 2 — articles, sommaire et quiz.
|
|
|
|
Une section se crée vide (POST /api/Section, qui ne connaît que le type), puis se
|
|
remplit par un PUT typé. C'est le chemin que suit manager-app.
|
|
"""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
from api import Api, LANGS, tr
|
|
from content import ARTICLES, MENUS, QUIZZES
|
|
|
|
STATE = Path(__file__).resolve().parent / "state.json"
|
|
|
|
ARTICLE, MENU, QUIZ = 6, 4, 5
|
|
|
|
|
|
def empty_translations():
|
|
return [{"language": lang, "value": ""} for lang in LANGS]
|
|
|
|
|
|
def create_section(api, state, config_key, section_type, label):
|
|
"""Crée la section si son label n'existe pas déjà dans cette configuration."""
|
|
config_id = state["configs"][config_key]
|
|
existing = api.get(f"/api/Section/configuration/{config_id}") or []
|
|
found = next((s for s in existing if s["label"] == label), None)
|
|
if found:
|
|
return found, False
|
|
created = api.post("/api/Section", {
|
|
"configurationId": config_id,
|
|
"instanceId": state["instanceId"],
|
|
"label": label,
|
|
"type": section_type,
|
|
"isSubSection": False,
|
|
})
|
|
return created, True
|
|
|
|
|
|
def seed_articles(api, state):
|
|
for config_key, articles in ARTICLES.items():
|
|
for order, art in enumerate(articles):
|
|
section, created = create_section(api, state, config_key, ARTICLE,
|
|
art["label"])
|
|
lat, lon = art["coords"]
|
|
api.put("/api/Section", {
|
|
**section,
|
|
"type": ARTICLE,
|
|
"order": order,
|
|
"title": tr(**art["title"]),
|
|
"description": tr(**art["description"]),
|
|
"content": tr(**art["content"]),
|
|
"isContentTop": False,
|
|
"isReadAudioAuto": False,
|
|
"audioIds": empty_translations(),
|
|
"contents": [],
|
|
"isBeacon": True,
|
|
"beaconId": art["beacon"],
|
|
"latitude": lat,
|
|
"longitude": lon,
|
|
"meterZoneGPS": 12,
|
|
})
|
|
print(f" {'+' if created else '=':1} article {config_key} / {art['label']}")
|
|
|
|
|
|
def seed_menus(api, state):
|
|
for config_key, menu in MENUS.items():
|
|
section, created = create_section(api, state, config_key, MENU, menu["label"])
|
|
api.put("/api/Section", {
|
|
**section,
|
|
"type": MENU,
|
|
"order": 10,
|
|
"title": tr(**menu["title"]),
|
|
"description": tr(**menu["description"]),
|
|
"sections": [],
|
|
})
|
|
print(f" {'+' if created else '='} sommaire {config_key} / {menu['label']}")
|
|
|
|
|
|
def seed_quizzes(api, state):
|
|
for config_key, quiz in QUIZZES.items():
|
|
section, created = create_section(api, state, config_key, QUIZ, quiz["label"])
|
|
api.put("/api/Section", {
|
|
**section,
|
|
"type": QUIZ,
|
|
"order": 11,
|
|
"title": tr(**quiz["title"]),
|
|
"description": tr(FR="Trois questions, une minute.",
|
|
DE="Drei Fragen, eine Minute.",
|
|
EN="Three questions, one minute.",
|
|
NL="Drie vragen, één minuut."),
|
|
"questions": [],
|
|
"bad_level": tr(FR="Il reste des salles à explorer.",
|
|
DE="Es gibt noch Säle zu entdecken.",
|
|
EN="There are still rooms to explore.",
|
|
NL="Er zijn nog zalen te ontdekken."),
|
|
"medium_level": tr(FR="Bon début — continuez la visite.",
|
|
DE="Guter Anfang — setzen Sie den Rundgang fort.",
|
|
EN="Good start — carry on with the visit.",
|
|
NL="Goed begin — zet het bezoek voort."),
|
|
"good_level": tr(FR="Belle attention aux détails.",
|
|
DE="Schöne Aufmerksamkeit für Details.",
|
|
EN="Fine attention to detail.",
|
|
NL="Mooie aandacht voor details."),
|
|
"great_level": tr(FR="Sans faute. Vous avez tout lu !",
|
|
DE="Fehlerfrei. Sie haben alles gelesen!",
|
|
EN="Flawless. You read everything!",
|
|
NL="Foutloos. U hebt alles gelezen!"),
|
|
})
|
|
|
|
already = api.get(f"/api/SectionQuiz/{section['id']}/questions") or []
|
|
if already:
|
|
print(f" = quiz {config_key} ({len(already)} questions déjà là)")
|
|
continue
|
|
|
|
for order, question in enumerate(quiz["questions"]):
|
|
api.post(f"/api/SectionQuiz/{section['id']}/questions", {
|
|
"sectionQuizId": section["id"],
|
|
"order": order,
|
|
"label": [{"language": lang, "value": question["q"].get(lang,
|
|
question["q"]["FR"])}
|
|
for lang in LANGS],
|
|
"responses": [
|
|
{"order": i,
|
|
"isGood": good,
|
|
"label": [{"language": lang, "value": text.get(lang, text["FR"])}
|
|
for lang in LANGS]}
|
|
for i, (text, good) in enumerate(question["answers"])
|
|
],
|
|
})
|
|
print(f" + quiz {config_key} ({len(quiz['questions'])} questions)")
|
|
|
|
|
|
def main():
|
|
api = Api()
|
|
state = json.loads(STATE.read_text(encoding="utf-8"))
|
|
seed_articles(api, state)
|
|
seed_menus(api, state)
|
|
seed_quizzes(api, state)
|
|
print("\nétape 2 terminée")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|