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);