Ugrás a tartalomra
Fejlesztői integrációk

Kösd össze a Puzzelt a saját platformoddal

A Puzzel egy játékos eredményét — a pontszámát, hogy meddig jutott, mit válaszolt — közvetlenül átadhatja egy másik rendszernek, anélkül hogy annak teljes LMS-nek kellene lennie. Ez az oldal az összes csatornát bemutatja: mi megy ki, mikor megy ki, és mi a legkisebb dolog, amit fel kell építened a fogadásához.

Így mennek ki az eredmények
Webhookon, vagy üzenetben a tevékenységet körülvevő oldalnak
Az oldalad képes
Bejelentkeztetni a játékost, és visszaállítani a tevékenységet
Bekapcsolva
Tevékenységenként, a szerkesztő Fejlesztői menüjében
Ehhez jár
Egy fizetős csomaghoz — ingyenes fiókon ezek a beállítások ki vannak kapcsolva

Melyik csatornára van szükséged?

Három dolog hagyhatja el a tevékenységet, és egy jöhet be. Hogy melyik illik hozzád, egyetlen kérdésen múlik: a játékos a te oldaladon belül ül, vagy egészen máshol?

Kifelé a Puzzelből
Befelé a Puzzelbe

Eredmény-webhook

Kapcsold be a szerkesztőben az „Eredmények küldése webhookra” beállítást, és add meg hozzá egy URL-t. Ettől kezdve minden alkalommal, amikor a játékos haladása mentésre kerül, a böngészője POST kéréssel elküldi a teljes eredményt JSON-ként arra az URL-re.

Beállítás lépésről lépésre
  1. 1 Nyisd meg a tevékenységet a szerkesztőben, és lépj a Fejlesztői menübe.
  2. 2 Kapcsold be az „Eredmények küldése webhookra” beállítást, és illeszd be a végpontodat az alatta lévő mezőbe. Teljes URL-nek kell lennie — egy puszta domain nem elfogadott —, és https-nek kell lennie, mert a böngésző letiltja a sima http hívást egy https-en keresztül kiszolgált oldalról.
  3. 3 Játszd végig egyszer magad a tevékenységet. Az első POST kérés azonnal megérkezik, amint válaszolsz valamire.
Egy fogadó, elejétől a végéig
import express from 'express';

const app = express();

// The POST is made by the player's browser, so the browser asks permission
// first. Answer the preflight and the real request can land.
app.use((req, res, next) => {
  res.set('Access-Control-Allow-Origin', 'https://puzzel.org');
  res.set('Access-Control-Allow-Headers', 'Content-Type');
  if (req.method === 'OPTIONS') return res.sendStatus(204);
  next();
});

app.post('/puzzel/results', express.json(), async (req, res) => {
  const result = req.body;

  // One run posts several times as it goes. Key on the pair, not on an
  // insert: each call carries the whole state, so the newest simply wins.
  await db.results.upsert(
    { playerUid: result.playerUid, activityKey: result.activityKey },
    result
  );

  // Only act on the finish once.
  if (result.progress >= 100 || result.hasAlternateCompletion) {
    await markCourseStepComplete(result);
  }

  res.sendStatus(200);
});
Játék közben érkezik, nem csak a végén

Egy eredmény minden bejegyzés-mentéskor kimegy: egy gépelési szünet után, amikor egy kártyát lehelyeznek, amikor az óra megáll, és még egyszer, amikor a tevékenység befejeződik. Egy hosszú keresztrejtvény pár tucat hívást jelent, nem egyet — ezért a fogadódat upsertként írd meg, aminek a kulcsa a playerUid és az activityKey, ne beszúrásként. Minden hívás a teljes állapotot hordozza, így a legújabb mindig felülírja az előzőt, és egy elveszett hívást a következő pótol.

Hogyan különböztesd meg a befejezést egy mentéstől

A progress egy százalék: 100 azt jelenti, hogy a tevékenység befejeződött. Néhány típus úgy is befejeződhet, hogy nem éri el ezt — egy végigválaszolt Quiz, egy megoldott megoldásmező —, ezek helyette a hasAlternateCompletion mezőt hordozzák. Mindkettőt kezeld befejezettként.

A játékos böngészője küldi

A POST kérés abból a lapból érkezik, amelyben a tevékenység éppen fut, nem egy Puzzel-szerverről. A legtöbb, webhookok fogadására épített végpont ezt már elfogadja. Ha a tiéd sosem lát kérést, ez az oka: a böngésző előbb engedélyt kér, ezért válaszolj az OPTIONS preflight kérésre egy Access-Control-Allow-Origin fejléccel, és a valódi POST kérés utána megérkezik.

Kezeld állításként, ne bizonyítékként

A kérésen nincs aláírás, és egy olyan böngészőből érkezik, amit nem te irányítasz, szóval bárki, aki megnézi az oldalt, tud neked is küldeni egyet. Ez rendben van egy folyamatjelző sáv vagy egy irányítópult kitöltéséhez. Amit nem hagynál egy diáknak magának beállítani — egy számító osztályzatot, egy tanúsítványt, egy fizetést —, azt ellenőrizd a saját Puzzel irányítópultodon lévő eredmények alapján, vagy bízd a pontszám vitelét az LMS osztályzat-összekötőkre.

Eredmények a beágyazó oldalnak

Ha beágyazod a tevékenységet, ugyanezt a JSON-t elküldheted a saját oldaladnak egy szerver helyett. Kapcsold be az „Eredmények küldése a szülőoldalnak” beállítást, és figyeld az üzenetet. Semmi nem hagyja el a böngészőt, így nincs végpont, amit fel kellene építened, és nincs CORS, amivel foglalkoznod kellene.

index.html
<iframe
  src="https://puzzel.org/en/quiz/embed?p=-Nq8sample_activity_key"
  width="100%"
  height="700"
  frameborder="0"
  allowfullscreen
></iframe>

<script>
  window.addEventListener('message', (event) => {
    if (event.origin !== 'https://puzzel.org') return;

    const result = event.data;
    if (!result || !result.activityKey) return;

    // Same shape the webhook posts, same advice: it arrives repeatedly.
    saveProgress(result);
  });
</script>
Ellenőrizd, honnan jött az üzenet

A figyelőd minden, az oldalnak küldött üzenetet meghall, beleértve más kereteket és böngészőbővítményeket is. Hasonlítsd össze az event.origin értékét a https://puzzel.org címmel, mielőtt megbíznál a tartalmában.

Ugyanaz a tartalom, ugyanaz az időzítés

Ez a webhook ikertestvére: ugyanazok a mezők, ugyanazokban a pillanatokban elküldve. Minden, ami a „Mit tartalmaz egy eredmény” alatt szerepel, itt is érvényes.

Befejezésjelzés

A legkisebb csatorna, arra az esetre, ha maga az eredmény nem tartozik rád: kapcsold be a „Befejezésjelzés küldése” beállítást, és az oldalad egyetlen üzenetet kap abban a pillanatban, amikor a játékos befejezi.

index.html
window.addEventListener('message', (event) => {
  if (event.origin !== 'https://puzzel.org') return;
  if (event.data?.completed !== true) return;

  // { completed: true, activityKey: '-Nq8sample_activity_key' }
  unlockNextLesson(event.data.activityKey);
});
Mi érkezik
{
  "completed": true,
  "activityKey": "-Nq8sample_activity_key"
}
Az eredmény már mentve van, mire megérkezik

A jelzést szándékosan azután küldjük, hogy a befejező mentés megtörtént, így egy olyan oldal, amely az eredményt visszaolvasva reagál, már ott találja azt.

Csak iframe-en belül

Mindkét üzenetcsatorna a tevékenységet keretbe foglaló oldalnak küld üzenetet. Önálló lapon megnyitva nincs kinek szólni, így semmi nem megy ki.

Mit tartalmaz egy eredmény

Egyetlen forma, akármelyik csatorna hordozza is. A játékos válaszainak kulcsa a tevékenység saját elem-azonosítója, ezért ugyanezek a kulcsok jelennek meg a correctUids mezőben is.

MezőTípusMit csinál
activityKey
mindig
string
stringA tevékenység, amelyhez az eredmény tartozik. Ugyanaz a kulcs, amit a tevékenység saját URL-jében látsz, a ?p= után.
playerUid
mindig
string
stringKi játszott, egy névtelen azonosítóként. Ez az adott eszközön állandó erre a játékosra nézve, ezért ez lesz az eredmények kulcsa — nem e-mail-cím, és nem Puzzel-fiók.
player
néha
object
objectA regisztrációs mezők, amiket a tevékenység bekér, ahogy beállítottad őket: név, e-mail, osztály, student_id és így tovább. Hiányzik, amíg a játékos nem regisztrált, és teljesen hiányzik egy olyan tevékenységnél, amely semmit nem kér.
progress
mindig
number
numberMennyire jutott előre, százalékban. 100 azt jelenti, hogy befejezte.
timePassed
mindig
number
numberA tevékenységen töltött idő, ezredmásodpercben.
lastPlayedAt
mindig
number
numberMikor mentődött ez az eredmény, Unix-időbélyegként, ezredmásodpercben.
createdAt
néha
number
numberMikor kezdődött a próbálkozás, Unix-időbélyegként, ezredmásodpercben.
playerInput
néha
object
objectAmit a játékos ténylegesen beírt — kulcsa annak az elemnek az azonosítója, amelyikhez tartozik. A belső forma a tevékenység típusától függ — egy szó, elhelyezett kártyák listája, egy kiválasztott opció.
correctUids
néha
object
objectMelyik elemek helyesek ezek közül, ugyanazzal a kulccsal. Hiányzik, amíg semmire nem válaszoltak még.
score
néha
number
numberElért pontszám, azokon a típusokon, amelyek pontozzák a menetet. Máshol hiányzik — beleértve egy olyan menetet is, amely valóban nulla pontot ért el, ezért mindig ellenőrizd, hogy a kulcs létezik-e, mielőtt kiolvasod.
performance
néha
number
numberEgy típus saját mércéje arról, hogy mennyire ment jól, ahol ilyet vezet — például a percenkénti szó a gépelésgyakorlásnál.
attempts
néha
number
numberHányadik menetről van szó: 1 az első alkalommal, eggyel több minden újrakezdésnél. Csak azokon a típusokon jelenik meg, amelyek korán befejezhetnek egy menetet, és számolják az újrapróbálkozásokat.
knockedOut
néha
boolean
booleanA menet egy rossz válasznál véget ért, és lezárult anélkül, hogy befejeződött volna.
hasAlternateCompletion
néha
boolean
booleanA tevékenység olyan módon fejeződött be, amely nem éri el a 100%-ot — egy végigválaszolt Quiz, egy megoldott megoldásmező. Kezeld befejezésként.
missedKeys
néha
array
arrayKarakterek, amiket a játékos folyamatosan elrontott, a leggyakrabban tévesztettel elöl. Csak a gépelésgyakorlásnál.
contentVersion
néha
number
numberA tevékenység tartalmának melyik verziójával szemben játszottak. Akkor változik, amikor a tulajdonos szerkeszti a kérdéseket, így egy régi eredmény megkülönböztethető egy aktuálistól.
Egy befejezett Quiz, ahogy megérkezik
{
  "activityKey": "-Nq8sample_activity_key",
  "playerUid": "kK3r9TzSampleAnonymousUid",
  "player": {
    "name": "Ava Ortega",
    "email": "ava@school.example",
    "class": "5B"
  },
  "progress": 100,
  "timePassed": 243120,
  "lastPlayedAt": 1758297843120,
  "createdAt": 1758297600000,
  "playerInput": {
    "-Nq8item_one": "Lisbon",
    "-Nq8item_two": "1969"
  },
  "correctUids": {
    "-Nq8item_one": true,
    "-Nq8item_two": false
  },
  "score": 800,
  "contentVersion": 1757923200000
}
Hiányzik, nem üres

Egy nem alkalmazható mező kimarad a JSON-ból, ahelyett hogy null vagy nulla értékkel szerepelne. Így különböztethető meg az a típus, amely nem pontoz egy menetet, attól a menettől, amely nulla pontot ért el — ezért mindig alapértékkel olvasd, és sose feltételezd, hogy egy kulcs biztosan jelen van.

A tevékenység visszaállítása az oldaladról

Egy utasítás a másik irányba is utazik. Ha bekapcsolod a „Vezérlés fogadása a szülőoldalról” beállítást, a beágyazó oldal törölheti a játékos válaszait, és visszaállíthatja a tevékenységet a kezdetére — egy saját „próbáld újra” gombhoz, a kereten kívül.

reset
const frame = document.querySelector('iframe').contentWindow;

// Sent to the frame, from the page that embeds it — no other sender is
// accepted, and the activity has to have the trigger setting switched on.
frame.postMessage({ trigger: { type: 'reset' } }, 'https://puzzel.org');
A visszaállítás az egyetlen utasítás

Nincs üzenet egy eredmény beküldésére, a záróüzenet megnyitására vagy egy kérdésre ugrásra. A visszaállítástól eltérő bármit kérő üzenetet figyelmen kívül hagyja.

Csak a beágyazó oldalt hallja meg

Az utasítást csak attól az oldaltól fogadja el, amely keretbe foglalja a tevékenységet, és sehonnan máshonnan — nem egy testvérkerettől, nem egy oldalon futó szkripttől. A beállítás alapból ki van kapcsolva, ezért kapcsold be azoknál a tevékenységeknél, amelyeket te vezérelsz.

Hozd magaddal a játékos azonosítását

Ha a platformod már tudja, ki játszik, a tevékenységnek nem kell újra megkérdeznie. Két kézfogás létezik erre, mindkettő egy, az oldaladba ágyazott tevékenységhez, és mindkettőt mi kapcsoljuk be, nem a szerkesztőben — mivel megváltoztatják, kihez tartozik egy eredmény, ezeket veled egyeztetve állítjuk be, nem egy jelölőnégyzettel.

Küldd el nekünk a játékost

A tevékenység bejelenti magát egy „app-loaded” üzenettel, és vár. Az oldalad visszaküldi a játékos adatait, és az eredmény az ő nevük alatt kerül rögzítésre anélkül, hogy a játékosnak bármit be kellene írnia, vagy regisztrációs képernyőt kellene látnia.

Küldj nekünk egy tokent

Ugyanaz a kézfogás, de az oldalad a mezők helyett az azonosítószolgáltatód által kiállított JWT-t küldi el. Ezt a fiókodhoz beállított kibocsátók alapján ellenőrizzük, mielőtt beengednénk a játékost, így az azonosítás bizonyított, nem csak állított — ezt kérd, ha az eredménynek megbízhatónak kell lennie.

index.html
window.addEventListener('message', (event) => {
  if (event.origin !== 'https://puzzel.org') return;

  // The activity says it is ready for a player.
  if (event.data === 'app-loaded') {
    frame.postMessage(
      {
        player: { name: 'Ava Ortega', email: 'ava@school.example', class: '5B' },
        // true starts a fresh attempt instead of resuming this player's last one
        should_reset: false
      },
      'https://puzzel.org'
    );
  }

  // Signed in; the board is coming.
  if (event.data?.success === true) hideYourOwnSpinner();
});
Kérd, hogy kapcsoljuk be

Mondd el, melyik kettőt szeretnéd, és hova ágyazod be a tevékenységeket, és mi beállítjuk a fiókodat, és végigvezetünk rajta.

Írj nekünk az azonosításról

Tevékenységek létrehozása a saját rendszeredből

Minden fent leírt dolog egy kimenő eredményről szól. A másik irány — maguknak a tevékenységeknek a létrehozása egy már meglévő tartalomból — a Puzzle API dolga: egy POST kérés tevékenységtípusonként, cserébe egy kulcsot és egy beágyazható URL-t kapsz.

Az API-dokumentáció megtekintése

Amikor egy kész összekötő a jobb válasz

Ha a másik oldalon egy valódi LMS áll, valószínűleg semmi erre nincs szükséged. Az osztályzatok maguktól visszakerülhetnek az osztálynaplójába, anélkül hogy neked bármit is üzemeltetned kellene.

Egyik sem ezek közül?

Kurzusplatformok, tagsági oldalak, intranetek és bármi, amit magad építettél, pontosan azok, amikre ez az oldal csatornái valók. Egy beágyazás plusz a befejezésjelzés a legtöbb esetet lefedi.

Amit nem találsz itt

Hogy ne is keresd hiába:

  • Nincs végpont az eredmények visszaolvasására. Az API tevékenységeket hoz létre; az eredmények az ezen az oldalon szereplő csatornákon keresztül, vagy az irányítópultod exportjain keresztül hagyják el a rendszert.
  • Nincs aláírás a webhookon. Nincs mihez viszonyítva ellenőrizni a kérést, ezért egy eredmény nem lehet az egyetlen alapja valaminek, ami valóban számít.
  • Nincs fiókszintű webhook. Az URL egy tevékenység beállítása, ezért egy lemásolt tevékenység magával viszi, egy új pedig nélküle indul.
  • Semmi nincs egy csapatjátékban vagy egy élő szobában. Mindkét üzenetcsatorna és a webhook is egyjátékos játékra való, és a beállítások automatikusan kikapcsolnak, amikor a csapatjáték be van kapcsolva.
  • Nincs kézbesítési sor. Semmi nem tárolódik és küldődik újra — a következő mentés maga az újrapróbálkozás, és a menet utolsó hívása számít.

Valami nem úgy működik, ahogy kéne?

Küldd el a kérést, amit kipróbáltál, és a hibát, amit visszakaptál, és valódi választ kapsz attól, aki a végpontot írta.

E-mail a támogatásnak