edu-senex/edu/api/cards.php

92 Zeilen
3,5 KiB
PHP

<?php
require_once __DIR__ . '/sm2.php';
$user_id = require_auth();
// GET /api/cards/deck/{slug}
if (get_method() === 'GET' && ($segments[1] ?? '') === 'deck' && !empty($segments[2])) {
$slug = $segments[2];
$stmt = $pdo->prepare("
SELECT c.id, c.question, c.answer, c.level, c.sort_order,
cp.next_review, cp.last_rating, cp.last_reviewed_at,
cp.ease_factor, cp.interval_days, cp.repetitions,
d.name AS deck_name, d.slug AS deck_slug
FROM cards c
JOIN decks d ON d.id = c.deck_id AND d.slug = :slug
LEFT JOIN card_progress cp ON cp.card_id = c.id AND cp.user_id = :uid
ORDER BY c.sort_order
");
$stmt->execute([':slug' => $slug, ':uid' => $user_id]);
json_ok(['cards' => $stmt->fetchAll()]);
}
// GET /api/cards/due?deck={slug}&limit=N
if (get_method() === 'GET' && ($segments[1] ?? '') === 'due') {
$slug = get_param('deck', '');
$limit = max(1, min(50, (int) get_param('limit', 20)));
$query = "
SELECT c.id, c.question, c.answer, c.level, c.sort_order, c.deck_id,
d.slug AS deck_slug, d.name AS deck_name,
cp.next_review, cp.last_rating, cp.last_reviewed_at,
cp.ease_factor, cp.interval_days, cp.repetitions
FROM cards c
JOIN decks d ON d.id = c.deck_id
LEFT JOIN card_progress cp ON cp.card_id = c.id AND cp.user_id = :uid
WHERE (cp.next_review IS NULL OR cp.next_review <= CURRENT_DATE)
";
$params = [':uid' => $user_id];
if ($slug) {
$query .= " AND d.slug = :slug";
$params[':slug'] = $slug;
}
$query .= " ORDER BY cp.next_review ASC NULLS FIRST, c.sort_order LIMIT " . $limit;
$stmt = $pdo->prepare($query);
$stmt->execute($params);
json_ok(['cards' => $stmt->fetchAll()]);
}
// POST /api/cards/{id}/review
if (get_method() === 'POST' && is_numeric($segments[1] ?? '') && ($segments[2] ?? '') === 'review') {
$card_id = (int) $segments[1];
$body = get_json_body();
$rating = $body['rating'] ?? '';
if (!in_array($rating, ['easy', 'medium', 'hard', 'wrong'])) {
json_error('Ungueltige Bewertung. Erlaubt: easy, medium, hard, wrong');
}
$stmt = $pdo->prepare("SELECT id FROM cards WHERE id = :id");
$stmt->execute([':id' => $card_id]);
if (!$stmt->fetch()) json_error('Karte nicht gefunden', 404);
$stmt = $pdo->prepare("SELECT * FROM card_progress WHERE user_id = :uid AND card_id = :cid");
$stmt->execute([':uid' => $user_id, ':cid' => $card_id]);
$progress = $stmt->fetch();
$ease = $progress['ease_factor'] ?? 2.5;
$interval = $progress['interval_days'] ?? 0;
$reps = $progress['repetitions'] ?? 0;
$result = sm2_calculate($rating, $ease, $interval, $reps);
$stmt = $pdo->prepare("
INSERT INTO card_progress (user_id, card_id, ease_factor, interval_days, repetitions, next_review, last_rating, last_reviewed_at)
VALUES (:uid, :cid, :ease, :intv, :reps, :next, :rating, NOW())
ON CONFLICT (user_id, card_id) DO UPDATE SET
ease_factor = :ease, interval_days = :intv, repetitions = :reps,
next_review = :next, last_rating = :rating, last_reviewed_at = NOW()
");
$stmt->execute([
':uid' => $user_id, ':cid' => $card_id,
':ease' => $result['ease_factor'], ':intv' => $result['interval_days'],
':reps' => $result['repetitions'], ':next' => $result['next_review'],
':rating' => $rating
]);
json_ok(['progress' => $result]);
}
json_error('Unbekannter Cards-Endpunkt', 404);