Lingara Lingara Dokumentation Ratgeber API Bibliotheken Apps Erstellen Web-App
Sprache: Deutsch

Kontext und Einwilligung

Diese Seite ist aus dem Englischen übersetzt. Wenn die beiden voneinander abweichen, ist die englische Seite maßgeblich. Englische Seite lesen

Ihre App erfährt etwas über einen Lernenden nur über Kontext-Slices. Jeder Slice ist ein kleiner Datensatz mit festen Feldern. Ihr Manifest listet die Slices auf, die es anfordert, der Lernende stimmt jedem einzelnen zu, wenn er Ihre App installiert, und Lingara sendet einen Slice nur, solange beides weiterhin gilt.

Die Slices

SliceFeldWas es enthält
languagessource_langDie Sprache, von der aus der Lernende lernt, als Sprach-Tag wie en.
target_langDie Sprache, die er lernt.
levelSein Niveau darin, von 1 bis 9, sofern er eines festgelegt hat.
plan_summaryplan_idDie ID seines neuesten Lektionsplans, die einen Plan von einem anderen unterscheidet. Ihre App kann den Plan damit nicht abrufen, denn das Token Ihrer App liest Ihr eigenes Konto, nicht das des Lernenden.
titleDer generierte Titel des Plans, höchstens 120 Zeichen, sofern er einen hat.
target_langDie Sprache, die der Plan unterrichtet.
set_countWie viele Sets der Plan hat, höchstens 200.
sets_completedWie viele dieser Sets der Lernende abgeschlossen hat.
review_duedueWie viele Karteikarten jetzt fällig sind, höchstens 100000.
learnedWie viele Wörter er gelernt hat, höchstens 100000.
tutor_topictopicWorum es in seinem letzten Tutor-Chat geht, 1 bis 120 Zeichen. Es stammt aus dem Titel eines Plans oder dem Bildschirm, auf dem er sich befindet, nie aus seinen eigenen Worten.

Was kein Slice enthält

Kein Slice enthält eine E-Mail-Adresse, einen Namen, eine Benutzer-ID oder irgendetwas, das der Lernende eingegeben hat. Wer der Lernende ist, erfährt Ihre App aus dem subject der Anfrage, einem stabilen Wert, der für jede App ein anderer ist. Das Token Ihrer App liest Ihr eigenes Konto, nie das des Lernenden, daher sind die Slices alles, was Ihre App über ihn weiß.

Einwilligung

  • Der Lernende stimmt jedem Slice zu, wenn er Ihre App installiert. Um zu ändern, wozu er zugestimmt hat, deinstalliert er Ihre App und installiert sie erneut.
  • Wenn Sie Ihr Manifest so ändern, dass es weniger Slices anfordert, enden die entfernten sofort.
  • Wenn Sie es so ändern, dass es mehr anfordert, erreichen die neuen Slices keinen Lernenden, bis er neu installiert.
  • Lingara prüft die Einwilligung bei jeder Anfrage erneut und verwirft jeden Slice, dem der Lernende nicht zugestimmt hat oder den Ihr Manifest nicht mehr anfordert. Ein Slice, der nicht zu seinem Datensatz passt, wird ebenfalls verworfen, nie die ganze Anfrage.

Das Beispiel unten baut seine Zeile aus den Slices, die es erhalten hat, und ruft keine API auf.

Sprache des Codebeispiels

TypeScript

// The app's own client reads its owner's account, never the learner's. The
// slices are all a render knows about the learner.
function planLine(request: AppRenderRequest): string {
  let line = "";
  for (const slice of request.context) {
    // A slice is present only when the learner agreed to share it.
    if (slice.kind === "languages") line += `${slice.source_lang} → ${slice.target_lang}. `;
    if (slice.kind === "plan_summary") line += `${slice.sets_completed}/${slice.set_count} sets.`;
  }
  return line;
}

Rust

// The app's own client reads its owner's account, never the learner's. The
// slices are all a render knows about the learner.
/// The learner's target language and, when they shared their plan, its
/// `(sets_completed, set_count)`.
fn shared_plan(request: &AppRenderRequest) -> (String, Option<(u32, u32)>) {
    let (mut target_lang, mut progress) = (String::from("zh"), None);
    for slice in &request.context {
        match slice {
            ContextSlice::Languages(languages) => target_lang = languages.target_lang.clone(),
            ContextSlice::PlanSummary(summary) => progress = Some((summary.sets_completed, summary.set_count)),
            _ => {}
        }
    }
    (target_lang, progress)
}

Go

// The app's own client reads its owner's account, never the learner's.
// The slices are all a render knows about the learner.
//
// Each slice is present only when the learner agreed to share it.
card := lingaraapps.NewCard().Heading("Your plan", 1)
for _, slice := range req.Context {
	switch s := slice.(type) {
	case lingaraapps.ContextSliceLanguages:
		card.Text(fmt.Sprintf("Learning %s from %s", s.TargetLang, s.SourceLang))
	case lingaraapps.ContextSlicePlanSummary:
		card.Text(fmt.Sprintf("%d of %d sets done", s.SetsCompleted, s.SetCount))
	}
}

Java

import com.getlingara.apps.Card;
import com.getlingara.apps.Reply;
import com.getlingara.apps.model.AppRenderRequest;
import com.getlingara.apps.model.ContextSlice;
import com.getlingara.apps.model.ContextSliceLanguages;
import com.getlingara.apps.model.ContextSlicePlanSummary;

// The app's own client reads its owner's account, never the learner's. The slices are all a
// render knows about the learner.
static Reply render(AppRenderRequest request) {
  Card.Builder card = Card.card();
  // A slice is present only when the learner agreed to share it; the context is read-only.
  for (ContextSlice slice : request.getContext()) {
    if (slice instanceof ContextSliceLanguages languages) {
      card.heading("Learning " + languages.targetLang(), 1);
    } else if (slice instanceof ContextSlicePlanSummary summary) {
      card.text(summary.setsCompleted() + " of " + summary.setCount() + " sets done");
    }
  }
  return card.heading("Today", 2).build();
}

Kotlin

import com.getlingara.apps.kotlin.Reply
import com.getlingara.apps.kotlin.card
import com.getlingara.apps.kotlin.model.AppRenderRequest
import com.getlingara.apps.kotlin.model.ContextSliceLanguages
import com.getlingara.apps.kotlin.model.ContextSlicePlanSummary

// The app's own client reads its owner's account, never the learner's. The slices are all a
// render knows about the learner.
fun renderWithContext(request: AppRenderRequest): Reply {
    // A slice is present only when the learner agreed to share it; the context is read-only.
    val languages = request.context.filterIsInstance<ContextSliceLanguages>().firstOrNull()
    val summary = request.context.filterIsInstance<ContextSlicePlanSummary>().firstOrNull()
    return card {
        heading("Learning ${languages?.targetLang ?: "today"}", 1)
        if (summary != null) {
            text("${summary.setsCompleted} of ${summary.setCount} sets done")
        }
    }
}

Ruby

# The app's own client reads its owner's account, never the learner's. The
# slices are all a render knows about the learner.
#
# A slice is present only when the learner agreed to share it.
request.context.filter_map do |slice|
  case slice
  in Lingara::Apps::ContextSliceLanguages(source_lang:, target_lang:)
    "#{source_lang} → #{target_lang}."
  in Lingara::Apps::ContextSlicePlanSummary(sets_completed:, set_count:)
    "#{sets_completed}/#{set_count} sets."
  else nil
  end
end.join(" ")

PHP

use Lingara\Apps\Generated\ContextSliceLanguages;
use Lingara\Apps\Generated\ContextSlicePlanSummary;

function planLine(AppRenderRequest $request): string
{
    // The app's own client reads its owner's account, never the learner's. The
    // slices are all a render knows about the learner.
    $line = '';
    // A slice is present only when the learner agreed to share it.
    foreach ($request->getContext() as $slice) {
        if ($slice instanceof ContextSliceLanguages) {
            $line .= "{$slice->sourceLang} → {$slice->targetLang}. ";
        } elseif ($slice instanceof ContextSlicePlanSummary) {
            $line .= "{$slice->setsCompleted}/{$slice->setCount} sets.";
        }
    }
    return $line;
}

Siehe auch