Files
Streamer-app/api/streamers.php
Vlastislav Svatek 153c83f7fa first commit
2026-04-26 02:23:11 +02:00

270 lines
10 KiB
PHP

<?php
// ============================================================
// api/streamers.php
//
// GET /api/streamers — public list (evaluated only)
// GET /api/streamers?all=1 — full list (admin or mod)
// POST /api/streamers — suggest a streamer (public)
// POST /api/streamers?admin=1 — add streamer (admin only)
// PUT /api/streamers?id=N — update streamer + rating (admin or mod)
// DELETE /api/streamers?id=N — delete streamer (admin only)
// ============================================================
require_once __DIR__ . '/db.php';
cors();
$method = $_SERVER['REQUEST_METHOD'];
// ------------------------------------------------------------------
// GET — fetch streamers
// ------------------------------------------------------------------
if ($method === 'GET') {
start_session();
$is_admin = !empty($_SESSION['is_admin']);
$is_mod = is_moderator();
// Detect if logged-in OAuth user is a member of any rater team
$is_team_member = false;
if (!$is_admin && !$is_mod && !empty($_SESSION['oauth_user']['id'])) {
$stmt = db()->prepare("SELECT 1 FROM rater_group_members WHERE user_id = :uid LIMIT 1");
$stmt->execute([':uid' => $_SESSION['oauth_user']['id']]);
$is_team_member = (bool)$stmt->fetchColumn();
}
// 'all=1' is admin/mod request for unfiltered list (with notes etc.)
$all = isset($_GET['all']) && ($is_admin || $is_mod);
// Team members must see all streamers (even unevaluated) so they can rate them
$see_unevaluated = $all || $is_team_member;
if ($all) {
$sql = "
SELECT s.*,
r.statistiky, r.grafika, r.alerty, r.vychytavky,
r.nahled, r.nastaveni, r.odlisnost, r.reward, r.notes,
g.id AS team_id, g.name AS team_name
FROM streamers s
LEFT JOIN ratings r ON r.streamer_id = s.id
LEFT JOIN rater_groups g ON g.streamer_id = s.id
ORDER BY s.evaluated DESC, s.name ASC
";
} elseif ($see_unevaluated) {
// Team member: all streamers, but no admin-only fields like notes
$sql = "
SELECT s.id, s.name, s.platform, s.kick_name, s.status,
s.game, s.title, s.evaluated, s.community_locked,
r.statistiky, r.grafika, r.alerty, r.vychytavky,
r.nahled, r.nastaveni, r.odlisnost, r.reward,
g.id AS team_id, g.name AS team_name
FROM streamers s
LEFT JOIN ratings r ON r.streamer_id = s.id
LEFT JOIN rater_groups g ON g.streamer_id = s.id
ORDER BY s.evaluated DESC, s.name ASC
";
} else {
$sql = "
SELECT s.id, s.name, s.platform, s.kick_name, s.status,
s.game, s.title, s.evaluated, s.community_locked,
r.statistiky, r.grafika, r.alerty, r.vychytavky,
r.nahled, r.nastaveni, r.odlisnost, r.reward,
g.id AS team_id, g.name AS team_name
FROM streamers s
INNER JOIN ratings r ON r.streamer_id = s.id
LEFT JOIN rater_groups g ON g.streamer_id = s.id
WHERE s.evaluated = true
ORDER BY (r.statistiky + r.grafika + r.alerty + r.vychytavky +
r.nahled + r.nastaveni + r.odlisnost) DESC
";
}
$rows = db()->query($sql)->fetchAll();
// Reshape: nest ratings under 'r' key to match frontend format
$out = array_map(function($row) {
$s = [
'id' => $row['id'],
'name' => $row['name'],
'platform' => $row['platform'],
'kick' => $row['kick_name'] ?? '',
'status' => $row['status'],
'game' => $row['game'] ?? '',
'title' => $row['title'] ?? '',
'evaluated' => (bool)$row['evaluated'],
'community_locked' => (bool)($row['community_locked'] ?? false),
'added_by' => $row['added_by'] ?? 'admin',
'r' => [
's' => (int)($row['statistiky'] ?? 0),
'g' => (int)($row['grafika'] ?? 0),
'a' => (int)($row['alerty'] ?? 0),
'v' => (int)($row['vychytavky'] ?? 0),
'n' => (int)($row['nahled'] ?? 0),
'ns' => (int)($row['nastaveni'] ?? 0),
'o' => (int)($row['odlisnost'] ?? 0),
],
'reward' => (int)($row['reward'] ?? 0),
'team_id' => isset($row['team_id']) ? (int)$row['team_id'] : null,
'team_name' => $row['team_name'] ?? null,
];
if (isset($row['notes'])) {
$s['notes'] = $row['notes'];
}
return $s;
}, $rows);
json_out($out);
}
// ------------------------------------------------------------------
// POST — add streamer (suggestion from public, or admin add)
// ------------------------------------------------------------------
if ($method === 'POST') {
$body = body();
$is_admin_add = isset($_GET['admin']);
if ($is_admin_add) {
session_start();
if (empty($_SESSION['is_admin'])) json_error('Unauthorized', 401);
}
$name = sanitize_name($body['name'] ?? '');
if (strlen($name) < 2) json_error('Invalid streamer name');
$platform = in_array($body['platform'] ?? '', ['twitch','kick']) ? $body['platform'] : 'twitch';
$kick_name = sanitize_name($body['kick_name'] ?? '');
$submitter = substr(trim($body['submitter'] ?? ''), 0, 60);
$added_by = $is_admin_add ? 'admin' : 'viewer';
try {
$stmt = db()->prepare("
INSERT INTO streamers (name, platform, kick_name, added_by, submitter)
VALUES (:name, :platform, :kick_name, :added_by, :submitter)
RETURNING id
");
$stmt->execute([
':name' => $name,
':platform' => $platform,
':kick_name' => $kick_name,
':added_by' => $added_by,
':submitter' => $submitter,
]);
$row = $stmt->fetch();
json_out(['ok' => true, 'id' => $row['id']], 201);
} catch (PDOException $e) {
if (str_contains($e->getMessage(), 'unique')) {
json_error('Streamer already exists', 409);
}
json_error('DB error', 500);
}
}
// ------------------------------------------------------------------
// PUT — update streamer + rating (admin or mod)
// ------------------------------------------------------------------
if ($method === 'PUT') {
require_mod();
$id = (int)($_GET['id'] ?? 0);
if (!$id) json_error('Missing id');
$is_admin = !empty($_SESSION['is_admin']);
$body = body();
// Lock/unlock community ratings — admin only
if (isset($_GET['lock'])) {
if (!$is_admin) json_error('Admin only', 403);
$locked = !empty($body['community_locked']) ? 'true' : 'false';
db()->prepare("UPDATE streamers SET community_locked=:l WHERE id=:id")
->execute([':l' => $locked, ':id' => $id]);
json_out(['ok' => true]);
}
// Clamp rating values 0-10
$clamp = fn($v) => max(0, min(10, (int)$v));
$r = $body['r'] ?? [];
$stats = $clamp($r['s'] ?? 0);
$graf = $clamp($r['g'] ?? 0);
$alert = $clamp($r['a'] ?? 0);
$vych = $clamp($r['v'] ?? 0);
$nahl = $clamp($r['n'] ?? 0);
$nast = $clamp($r['ns'] ?? 0);
$odl = $clamp($r['o'] ?? 0);
$notes = substr(trim($body['notes'] ?? ''), 0, 2000);
$evaluated = ($stats + $graf + $alert + $vych + $nahl + $nast + $odl) > 0;
// Reward — admin can override manually, mods get auto-calculated
$reward = $is_admin
? max(0, min(130, (int)($body['reward'] ?? 0)))
: ($evaluated ? (int)round(30 + (($stats+$graf+$alert+$vych+$nahl+$nast+$odl) / 70) * 100) : 0);
$db = db();
// Moderators can only update ratings, not streamer metadata (status/game/title)
if ($is_admin) {
$kick = sanitize_name($body['kick'] ?? '');
$status = in_array($body['status'] ?? '', ['live','offline']) ? $body['status'] : 'offline';
$game = substr(trim($body['game'] ?? ''), 0, 100);
$title = substr(trim($body['title'] ?? ''), 0, 200);
$db->prepare("
UPDATE streamers
SET kick_name=:kick, status=:status, game=:game, title=:title, evaluated=:evaluated
WHERE id=:id
")->execute([
':kick'=>$kick, ':status'=>$status, ':game'=>$game,
':title'=>$title, ':evaluated'=>$evaluated?'true':'false', ':id'=>$id,
]);
} else {
// Mod: only update evaluated flag
$db->prepare("UPDATE streamers SET evaluated=:evaluated WHERE id=:id")
->execute([':evaluated'=>$evaluated?'true':'false', ':id'=>$id]);
}
// Upsert rating row
$db->prepare("
INSERT INTO ratings
(streamer_id, statistiky, grafika, alerty, vychytavky,
nahled, nastaveni, odlisnost, reward, notes)
VALUES
(:sid, :s, :g, :a, :v, :n, :ns, :o, :reward, :notes)
ON CONFLICT (streamer_id) DO UPDATE SET
statistiky = EXCLUDED.statistiky,
grafika = EXCLUDED.grafika,
alerty = EXCLUDED.alerty,
vychytavky = EXCLUDED.vychytavky,
nahled = EXCLUDED.nahled,
nastaveni = EXCLUDED.nastaveni,
odlisnost = EXCLUDED.odlisnost,
reward = EXCLUDED.reward,
notes = EXCLUDED.notes,
updated_at = NOW()
")->execute([
':sid' => $id,
':s' => $stats,
':g' => $graf,
':a' => $alert,
':v' => $vych,
':n' => $nahl,
':ns' => $nast,
':o' => $odl,
':reward' => $reward,
':notes' => $notes,
]);
json_out(['ok' => true]);
}
// ------------------------------------------------------------------
// DELETE — remove streamer (admin only)
// ------------------------------------------------------------------
if ($method === 'DELETE') {
require_admin();
$id = (int)($_GET['id'] ?? 0);
if (!$id) json_error('Missing id');
db()->prepare("DELETE FROM streamers WHERE id = :id")->execute([':id' => $id]);
json_out(['ok' => true]);
}
json_error('Method not allowed', 405);