612 lines
22 KiB
PHP
612 lines
22 KiB
PHP
<?php
|
||
include 'k-api.php';
|
||
|
||
function db()
|
||
{
|
||
$pdo = new PDO('sqlite:./data.db');
|
||
$pdo->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 * FROM classes WHERE classid = ?", [$classId]);
|
||
$db = null;
|
||
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]);
|
||
$db = null;
|
||
|
||
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]);
|
||
$db = null;
|
||
|
||
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]);
|
||
$db = null;
|
||
|
||
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]);
|
||
$db = null;
|
||
|
||
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 * 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) {
|
||
$db = null;
|
||
// with rings
|
||
return ['data' => $content, 'type' => 2];
|
||
} else {
|
||
// without rings
|
||
$results = FastDBReq($db, "SELECT * FROM RINGS WHERE classId = ?", [$classId]);
|
||
$rings = json_decode(findClosestDateSort($results, $day)['content'], true);
|
||
$out = joinArraysByKey($content, $rings, true);
|
||
$db = null;
|
||
return ['data' => $out, 'type' => 1];
|
||
}
|
||
} else {
|
||
// return shedules + calls
|
||
$dayOfWeek = getDayOfWeek($day);
|
||
$results = FastDBReq($db, "SELECT * 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 * FROM RINGS WHERE classId = ?", [$classId]);
|
||
$rings = json_decode(findClosestDateSort($results, $day)['content'], true);
|
||
$out = joinArraysByKey($schedule, $rings);
|
||
$db = null;
|
||
return ['data' => $out, 'type' => 0];
|
||
} else {
|
||
$db = null;
|
||
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 * FROM admins WHERE adminId=?", [$adminId]);
|
||
if (count($results) == 0) {
|
||
$db = null;
|
||
$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 * 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 * 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 * FROM RINGS WHERE classId = ?", [$classId]);
|
||
if (count($results) > 0) {
|
||
$rings = json_decode(findClosestDateSort($results, $day)['content'], true);
|
||
}
|
||
}
|
||
$db = null;
|
||
|
||
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 * FROM admins WHERE adminId=?", [$adminId]);
|
||
if (count($results) == 0) {
|
||
$db = null;
|
||
$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);
|
||
|
||
// im too lazy to close db
|
||
|
||
switch ($tab) {
|
||
case 0: // changes
|
||
// first get rasp and compare
|
||
// if no chnages skip, else publish
|
||
|
||
$dayOfWeek = getDayOfWeek($day);
|
||
$results = FastDBReq($db, "SELECT * 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 * 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 * FROM admins WHERE adminId=?", [$adminId]);
|
||
if (count($results) == 0) {
|
||
$db = null;
|
||
$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:
|
||
$db = null;
|
||
return "you saved your live because you didn't know what tabs are here";
|
||
}
|
||
$db = null;
|
||
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 * FROM admins WHERE adminId=?", [$adminId]);
|
||
if (count($results) == 0) {
|
||
$db = null;
|
||
$req->res->code(400);
|
||
return "админ не найден";
|
||
}
|
||
if (!$withSelf && !in_array($results[0]['adminPrems'], [-1, 2])) {
|
||
$db = null;
|
||
$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) {
|
||
$db = null;
|
||
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) {
|
||
$db = null;
|
||
return "egor";
|
||
}
|
||
break;
|
||
default:
|
||
$db = null;
|
||
return "?";
|
||
}
|
||
}
|
||
$db = null;
|
||
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 * FROM admins WHERE adminId=?", [$adminId]);
|
||
if (count($results) == 0) {
|
||
$db = null;
|
||
$req->res->code(400);
|
||
return "админ не найден";
|
||
}
|
||
if (!in_array($results[0]['adminPrems'], [-1, 2])) {
|
||
$db = null;
|
||
$req->res->code(400);
|
||
return "недостаточно прав";
|
||
}
|
||
|
||
$classId = $results[0]['adminClass'];
|
||
|
||
$results = FastDBReq($db, "SELECT * FROM classes WHERE classId=?", [$classId]);
|
||
if (count($results) == 0) {
|
||
$db = null;
|
||
$req->res->code(400);
|
||
return "класса не существует";
|
||
}
|
||
$classData = $results[0];
|
||
$adminsData = FastDBReq($db, "SELECT * FROM admins WHERE adminClass=?", [$classId]);
|
||
$db = null;
|
||
|
||
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 * FROM admins WHERE adminId=?", [$adminId]);
|
||
if (count($results) == 0) {
|
||
$db = null;
|
||
$req->res->code(400);
|
||
return "админ не найден";
|
||
}
|
||
if (!in_array($results[0]['adminPrems'], [-1, 2])) {
|
||
$db = null;
|
||
$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:
|
||
$db = null;
|
||
return "?";
|
||
}
|
||
});
|
||
});
|