setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); return $pdo; }; function findClosestDateSort(array $array, string $targetDate) { if (empty($array) || !preg_match('/^\d{1,2}-\d{1,2}-\d{2}$/', $targetDate)) { return null; } $targetDateTime = DateTime::createFromFormat('d-m-y', $targetDate); if ($targetDateTime === false) return null; $targetTimestamp = $targetDateTime->getTimestamp(); $result = null; $maxTimestamp = null; foreach ($array as $item) { $itemDateTime = DateTime::createFromFormat('d-m-y', $item['fromDate']); if ($itemDateTime === false) continue; $itemTimestamp = $itemDateTime->getTimestamp(); if ($itemTimestamp <= $targetTimestamp && ($maxTimestamp === null || $itemTimestamp > $maxTimestamp)) { $maxTimestamp = $itemTimestamp; $result = $item; } } return $result ?: ['content' => '[]']; } function getDayOfWeek(string $date) { $p = explode('-', $date); if (count($p) !== 3) throw new InvalidArgumentException('DD-MM-YY|YYYY'); [$d, $m, $y] = $p; if (strlen($y) === 2) $y = '20' . $y; $dt = DateTime::createFromFormat('Y-m-d', "$y-$m-$d"); if (!$dt) throw new InvalidArgumentException('Invalid date'); return (int)$dt->format('N') - 1; // 0=Mon ... 6=Sun } function joinArraysByKey(array $primaryArray, array $secondaryArray, bool $doNotOverwrite = false, string $key = 'num'): array { // Index secondary array once for O(1) lookups $indexedArray = array_column($secondaryArray, null, $key); $result = []; foreach ($primaryArray as $item) { if (!isset($item[$key])) { $result[] = $item; continue; } $currentKey = $item[$key]; if (isset($indexedArray[$currentKey])) { // Merge based on $doNotOverwrite flag $result[] = $doNotOverwrite ? array_merge($indexedArray[$currentKey], $item) // Primary values take precedence : array_merge($item, $indexedArray[$currentKey]); // Secondary values take precedence } else { $result[] = $item; } } return $result; } function FastDBReq(PDO $db, string $sql, array $params = []): array { try { $stmt = $db->prepare($sql); $stmt->execute($params); return $stmt->fetchAll(PDO::FETCH_ASSOC); } catch (PDOException $e) { throw $e; } } CreateApi(function ($api) { if (file_exists('./api.lock')) { http_response_code(500); $f = fopen('./api.lock', 'r') or die("server eгor"); $fs = filesize('./api.lock'); if ($fs == 0) { $cnt = ""; } else { $cnt = fread($f, $fs); } fclose($f); die($cnt); } $api->useUpdates(db()); $api->on('/', 'GET', function () { return 'dengi'; }); $api->on('/login', 'POST', function ($req) { if (!isset($req->data['classId'])) { $req->res->code(400); return "class is empty"; } $classId = substr(strtoupper($req->data['classId']), 0, 10); // according docs (UPPERCASE, MIN 3 MAX 10) $db = db(); $results = FastDBReq($db, "SELECT classid, userclassname FROM classes WHERE classid = ?", [$classId]); if (count($results) != 0) { return $results[0]; } else { $req->res->code(400); return "класс $classId не найден"; } }); $api->on('/get_class_user_f', 'POST', function ($req) { if (!isset($req->data['classId'])) { $req->res->code(400); return ""; } $classId = substr(strtoupper($req->data['classId']), 0, 10); // according docs (UPPERCASE, MIN 3 MAX 10) $db = db(); $results = FastDBReq($db, "SELECT userclassname FROM classes WHERE classid = ?", [$classId]); if (count($results) != 0) { return $results[0]; } else { $req->res->code(400); return; } }); $api->on('/get_admin_user_f', 'POST', function ($req) { if (!isset($req->data['adminId'])) { $req->res->code(400); return ""; } $adminId = $req->data['adminId']; $db = db(); $results = FastDBReq($db, "SELECT adminName FROM admins where adminid = ?", [$adminId]); if (count($results) != 0) { return $results[0]; } else { $req->res->code(400); return; } }); $api->on('/get_admin_level', 'POST', function ($req) { if (!isset($req->data['adminId'])) { $req->res->code(400); return ""; } $adminId = $req->data['adminId']; $db = db(); $results = FastDBReq($db, "SELECT adminPrems FROM admins where adminid = ?", [$adminId]); if (count($results) != 0) { return $results[0]; } else { $req->res->code(400); return; } }); $api->on('/admin_login', 'POST', function ($req) { if (!isset($req->data['adminId'])) { $req->res->code(400); return "admin is empty"; } $adminId = $req->data['adminId']; $db = db(); $results = FastDBReq($db, "SELECT * FROM admins WHERE adminid = ?", [$adminId]); if (count($results) != 0) { return $results[0]; } else { $req->res->code(400); return "админ не найден"; } }); $api->on('/req_client_schedule', 'POST', function ($req) { // NOTE: THIS IS SCHEDULE FOR USER (SHOULD BE WITH CHANGES AND CALLS) // types = [0 - default schedule, 1 - with schedule changes, 2 - with schedule and rings] if (!$req->hasData(['classId', 'day'])) { $req->res->code(400); return "net dannih"; } $classId = substr(strtoupper($req->data['classId']), 0, 10); $day = $req->data['day']; if (!preg_match('/\d{1,2}-\d{1,2}-(\d{2}|\d{4})$/', $day)) return "wrong date format"; $db = db(); $results = FastDBReq($db, "SELECT content FROM changes WHERE classId = ? AND forDay = ?", [$classId, $day]); if (count($results) > 0) { // return only changes $content = json_decode($results[0]['content'], true); $has_full_rings = true; foreach ($content as $_idx => $item) { if (!isset($item['t-begin']) || !isset($item['t-end'])) { $has_full_rings = false; // optionally record $idx break; } } if ($has_full_rings) { // with rings return ['data' => $content, 'type' => 2]; } else { // without rings $results = FastDBReq($db, "SELECT content, fromDate FROM RINGS WHERE classId = ?", [$classId]); $rings = json_decode(findClosestDateSort($results, $day)['content'], true); $out = $content; if ($rings !== null) { $out = joinArraysByKey($content, $rings, true); } return ['data' => $out, 'type' => 1]; } } else { // return shedules + calls $dayOfWeek = getDayOfWeek($day); $results = FastDBReq($db, "SELECT content, fromDate FROM schedules WHERE classId = ? AND dayOfWeek = ?", [$classId, $dayOfWeek]); if (count($results) > 0) { $out = []; $schedule = json_decode(findClosestDateSort($results, $day)['content'], true); $results = FastDBReq($db, "SELECT content, fromDate FROM RINGS WHERE classId = ?", [$classId]); $rings = json_decode(findClosestDateSort($results, $day)['content'], true); $out = $schedule; if ($rings !== null) { $out = joinArraysByKey($schedule, $rings); } return ['data' => $out, 'type' => 0]; } else { return ['data' => []]; } } }); $api->on('/editor_data', "POST", function ($req) { if (!$req->hasData(['tab', 'day', 'adminId'])) { $req->res->code(400); return "bad data"; } $adminId = $req->data['adminId']; $db = db(); $results = FastDBReq($db, "SELECT adminClass FROM admins WHERE adminId=?", [$adminId]); if (count($results) == 0) { $req->res->code(400); return "админ не найден"; # end } $classId = $results[0]['adminClass']; $day = $req->data['day']; $tab = intval($req->data['tab']); $changes = null; $schedule = []; $rings = []; if ($tab != 2) { if ($tab == 0) { $results = FastDBReq($db, "SELECT content FROM changes WHERE classId = ? AND forDay = ?", [$classId, $day]); if (count($results) > 0) { $changes = json_decode($results[0]['content'], true); } } $dayOfWeek = getDayOfWeek($day); $results = FastDBReq($db, "SELECT content, fromDate FROM schedules WHERE classId = ? AND dayOfWeek = ?", [$classId, $dayOfWeek]); if (count($results) > 0) { $schedule = json_decode(findClosestDateSort($results, $day)['content'], true); } } else { $results = FastDBReq($db, "SELECT content, fromDate FROM RINGS WHERE classId = ?", [$classId]); if (count($results) > 0) { $rings = json_decode(findClosestDateSort($results, $day)['content'], true); } } switch ($tab) { case 0: if ($changes === null) { // type check!!! return $schedule; } else { return $changes; } case 1: return $schedule; case 2: return $rings; default: return "tab not found dengi dengi"; } }); $api->on( "/editor_publish", "POST", function ($req) { if (!$req->hasData(['adminId', 'tab', 'day', 'newData'])) { $req->res->code(400); return "bad data"; } $adminId = $req->data['adminId']; $db = db(); $results = FastDBReq($db, "SELECT adminClass FROM admins WHERE adminId=?", [$adminId]); if (count($results) == 0) { $req->res->code(400); return "админ не найден"; # end } $classId = $results[0]['adminClass']; $day = $req->data['day']; $tab = intval($req->data['tab']); $newDataRaw = $req->data['newData']; $newData = json_decode($newDataRaw, true); switch ($tab) { case 0: // changes // first get rasp and compare // if no chnages skip, else publish $dayOfWeek = getDayOfWeek($day); $results = FastDBReq($db, "SELECT fromDate, content FROM schedules WHERE classId = ? AND dayOfWeek = ?", [$classId, $dayOfWeek]); $publish = true; if (count($results) > 0) { $schedule = json_decode(findClosestDateSort($results, $day)['content'], true); if ($newData === $schedule) { // position sentensive $publish = false; } } if ($publish) { // removing changes for today if they are exists $results = FastDBReq($db, "SELECT content FROM changes WHERE classId = ? AND forDay = ?", [$classId, $day]); if (count($results) > 0) { $changes = json_decode($results[0]['content'], true); if ($newData === $changes) { // already present return true; } FastDBReq($db, "DELETE FROM changes WHERE forDay = ? AND classId = ?", [$day, $classId]); // SCARY 💀💀💀 } // creating new FastDBReq($db, 'INSERT INTO changes VALUES (?, ?, ?)', [$classId, $day, $newDataRaw]); return true; } return false; case 1: // rasp $dayOfWeek = getDayOfWeek($day); // FIXME: im to lazy to find if closest rasp are the same FastDBReq($db, 'DELETE FROM schedules WHERE classId=? AND fromDate=?', [$classId, $day]); FastDBReq($db, 'INSERT INTO schedules VALUES (?,?,?,?)', [$classId, $day, $dayOfWeek, $newDataRaw]); return true; case 2: // rigns //same FastDBReq($db, 'DELETE FROM rings WHERE classId=? AND fromDate=?', [$classId, $day]); FastDBReq($db, 'INSERT INTO rings VALUES (?,?,?)', [$classId, $day, $newDataRaw]); return true; default: return "tab not found dengi dengi"; } } ); $api->on('/editor_fullitems_del', "POST", function ($req) { // SCARY!!!!!! // LEVEL 10000000 // 💀💀💀💀💀 if (!$req->hasData(['tab', 'day', 'adminId'])) { $req->res->code(400); return "bad data"; } $adminId = $req->data['adminId']; $db = db(); $results = FastDBReq($db, "SELECT adminClass FROM admins WHERE adminId=?", [$adminId]); if (count($results) == 0) { $req->res->code(400); return "админ не найден"; # end } $classId = $results[0]['adminClass']; $day = $req->data['day']; $tab = intval($req->data['tab']); switch ($tab) { case 0: FastDBReq($db, "DELETE FROM changes WHERE forDay = ? AND classId = ?", [$day, $classId]); break; case 1: FastDBReq($db, 'DELETE FROM schedules WHERE classId=? AND fromDate=?', [$classId, $day]); break; case 2: FastDBReq($db, 'DELETE FROM rings WHERE classId=? AND fromDate=?', [$classId, $day]); break; default: return "you saved your live because you didn't know what tabs are here"; } return true; }); $api->on('/update_admin', "POST", function ($req) { if (!$req->hasData(['adminId', 'action'])) { $req->res->code(400); return "bad data"; } $adminId = $req->data['adminId']; $withSelf = true; $action = $req->data['action']; if (isset($req->data['person'])) { $withSelf = false; } $adminId = $req->data['adminId']; $db = db(); $results = FastDBReq($db, "SELECT adminPrems FROM admins WHERE adminId=?", [$adminId]); if (count($results) == 0) { $req->res->code(400); return "админ не найден"; } if (!$withSelf && !in_array($results[0]['adminPrems'], [-1, 2])) { $req->res->code(400); return 'нету прав'; } if ($withSelf) { switch ($action) { case "change_name": if (!isset($req->data['value'])) { $req->res->code(400); return "bad data"; } $value = trim($req->data['value']); if (strlen($value) == 0) { $req->res->code(400); return "bad data"; } try { FastDBReq($db, 'UPDATE admins SET adminName = ? WHERE adminId = ?', [$value, $adminId]); } catch (PDOException) { return "egor"; } break; } } else { $person = $req->data['person']; switch ($action) { case "change_name": if (!isset($req->data['value'])) { $req->res->code(400); return "bad data"; } $value = trim($req->data['value']); if (strlen($value) == 0) { $req->res->code(400); return "bad data"; } try { FastDBReq($db, 'UPDATE admins SET adminName = ? WHERE adminId = ?', [$value, $person]); } catch (PDOException) { return "egor"; } break; default: return "?"; } } return true; }); $api->on('/classprofile_view', "POST", function ($req) { if (!$req->hasData(['adminId'])) { $req->res->code(400); return "bad data"; } $adminId = $req->data['adminId']; $db = db(); $results = FastDBReq($db, "SELECT adminPrems, adminClass FROM admins WHERE adminId=?", [$adminId]); if (count($results) == 0) { $req->res->code(400); return "админ не найден"; } if (!in_array($results[0]['adminPrems'], [-1, 2])) { $req->res->code(400); return "недостаточно прав"; } $classId = $results[0]['adminClass']; $results = FastDBReq($db, "SELECT classid FROM classes WHERE classid=?", [$classId]); if (count($results) == 0) { $req->res->code(400); return "класса не существует"; } $classData = $results[0]; $adminsData = FastDBReq($db, "SELECT * FROM admins WHERE adminClass=?", [$classId]); return ["status" => 1, "class" => $classData, "admins" => $adminsData]; }); $api->on('/classprofile_edit', "POST", function ($req) { if (!$req->hasData(['adminId', 'action'])) { $req->res->code(400); return "bad data"; } $adminId = $req->data['adminId']; $db = db(); $results = FastDBReq($db, "SELECT adminPrems, adminClass FROM admins WHERE adminId=?", [$adminId]); if (count($results) == 0) { $req->res->code(400); return "админ не найден"; } if (!in_array($results[0]['adminPrems'], [-1, 2])) { $req->res->code(400); return "недостаточно прав"; } $classId = $results[0]['adminClass']; $action = $req->data['action']; switch ($action) { case 'update_name': try { if (!isset($req->data['value'])) { $req->res->code(400); return "bad data"; } $value = trim($req->data['value']); if (strlen($value) == 0) { $req->res->code(400); return "bad data"; } FastDBReq($db, "UPDATE classes SET userclassname = ? WHERE classid=?", [$value, $classId]); return true; } catch (PDOException $e) { error_log($e); return "егор"; } break; case 'create_admin': if (!isset($req->data['value'])) { $req->res->code(400); return "bad data"; } $value = trim($req->data['value']); if (strlen($value) == 0 || !str_contains($value, ';')) { $req->res->code(400); return "bad data"; } $value = explode(';', $value); if (sizeof($value) != 2) { $req->res->code(400); return 'bad data'; } $n_adminId = $value[0]; $n_adminName = base64_decode($value[1]); try { FastDBReq($db, "INSERT INTO admins (adminId,adminName,adminClass,adminPrems) VALUES (?,?,?,?)", [$n_adminId, $n_adminName, $classId, 1]); return true; } catch (PDOException) { $req->res->code(500); return "ошибка"; } case "delete_admin": if (!isset($req->data['value'])) { $req->res->code(400); return "bad data"; } $person = trim($req->data['value']); if (strlen($person) == 0) { $req->res->code(400); return "bad data"; } FastDBReq($db, "DELETE FROM admins WHERE adminId=?", [$person]); return true; default: return "?"; } }); });