mirror of
https://github.com/claradex/nativegallery.git
synced 2025-02-21 03:02:13 +03:00
admin contest pages
This commit is contained in:
parent
22e0fe0cec
commit
13f06db887
4 changed files with 377 additions and 4 deletions
109
app/Services/TaskScheduler.php
Normal file
109
app/Services/TaskScheduler.php
Normal file
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
class TaskScheduler {
|
||||
private $taskName;
|
||||
private $command;
|
||||
private $interval;
|
||||
|
||||
public function __construct() {
|
||||
// Конструктор теперь не принимает аргументы
|
||||
}
|
||||
|
||||
private function isWindows() {
|
||||
return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
|
||||
}
|
||||
|
||||
// Метод для добавления задачи с параметрами
|
||||
public function addTask($taskName, $command, $interval = "* * * * *") {
|
||||
$this->taskName = $taskName;
|
||||
$this->command = $command;
|
||||
$this->interval = $interval;
|
||||
|
||||
return $this->isWindows() ? $this->addWindowsTask() : $this->addLinuxTask();
|
||||
}
|
||||
|
||||
public function isTaskExists($taskName = null, $command = null) {
|
||||
return $this->isWindows()
|
||||
? $this->isWindowsTaskExists($taskName)
|
||||
: $this->isLinuxTaskExists($command);
|
||||
}
|
||||
|
||||
public function removeTask($taskName = null, $command = null) {
|
||||
return $this->isWindows()
|
||||
? $this->removeWindowsTask($taskName)
|
||||
: $this->removeLinuxTask($command);
|
||||
}
|
||||
|
||||
private function addLinuxTask() {
|
||||
$cronJob = "{$this->interval} {$this->command}";
|
||||
if ($this->isLinuxTaskExists($this->command)) {
|
||||
return "✅ Cron-задача уже установлена.";
|
||||
}
|
||||
|
||||
exec("crontab -l 2>&1", $output, $return_var);
|
||||
if ($return_var !== 0) {
|
||||
$output = [];
|
||||
}
|
||||
|
||||
$output[] = $cronJob;
|
||||
file_put_contents("/tmp/my_cron", implode(PHP_EOL, $output) . PHP_EOL);
|
||||
exec("crontab /tmp/my_cron");
|
||||
unlink("/tmp/my_cron");
|
||||
|
||||
return "✅ Cron-задача добавлена!";
|
||||
}
|
||||
|
||||
private function isLinuxTaskExists($command = null) {
|
||||
exec("crontab -l 2>&1", $output);
|
||||
foreach ($output as $line) {
|
||||
if (strpos($line, $command ?? $this->command) !== false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function removeLinuxTask($command = null) {
|
||||
exec("crontab -l 2>&1", $output, $return_var);
|
||||
if ($return_var !== 0) {
|
||||
return "❌ Нет задач для удаления.";
|
||||
}
|
||||
|
||||
$filteredOutput = array_filter($output, function ($line) use ($command) {
|
||||
return strpos($line, $command ?? $this->command) === false;
|
||||
});
|
||||
|
||||
file_put_contents("/tmp/my_cron", implode(PHP_EOL, $filteredOutput) . PHP_EOL);
|
||||
exec("crontab /tmp/my_cron");
|
||||
unlink("/tmp/my_cron");
|
||||
|
||||
return "✅ Cron-задача удалена!";
|
||||
}
|
||||
|
||||
private function addWindowsTask() {
|
||||
if ($this->isWindowsTaskExists($this->taskName)) {
|
||||
return "✅ Задача уже существует в Windows.";
|
||||
}
|
||||
|
||||
$command = "schtasks /Create /SC MINUTE /MO 1 /TN \"{$this->taskName}\" /TR \"{$this->command}\" /F";
|
||||
exec($command, $output, $return_code);
|
||||
|
||||
return ($return_code === 0) ? "✅ Задача добавлена в Windows!" : "❌ Ошибка при добавлении задачи.";
|
||||
}
|
||||
|
||||
private function isWindowsTaskExists($taskName = null) {
|
||||
exec("schtasks /Query /TN \"". ($taskName ?? $this->taskName) ."\" 2>&1", $output, $return_var);
|
||||
return $return_var === 0;
|
||||
}
|
||||
|
||||
private function removeWindowsTask($taskName = null) {
|
||||
if (!$this->isWindowsTaskExists($taskName)) {
|
||||
return "❌ Задача не найдена в Windows.";
|
||||
}
|
||||
|
||||
exec("schtasks /Delete /TN \"". ($taskName ?? $this->taskName) ."\" /F", $output, $return_code);
|
||||
return ($return_code === 0) ? "✅ Задача удалена из Windows!" : "❌ Ошибка при удалении задачи.";
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -68,10 +68,10 @@ body {
|
|||
<i class="bx bx-news nav__icon"></i>
|
||||
<span class="nav__name">Новости сайта</span>
|
||||
</a>
|
||||
<!--a href="/admin?type=Contests" class="nav__link">
|
||||
<a href="/admin?type=Contests" class="nav__link">
|
||||
<i class="bx bx-party nav__icon"></i>
|
||||
<span class="nav__name">Фотоконкурсы <span class="badge text-bg-warning">BETA</span></span>
|
||||
<-->
|
||||
</a>
|
||||
<a href="/admin?type=Entities" class="nav__link">
|
||||
<i class="bx bx-package nav__icon"></i>
|
||||
<span class="nav__name">Сущности</span>
|
||||
|
|
264
views/pages/Admin/Contests.php
Normal file
264
views/pages/Admin/Contests.php
Normal file
|
@ -0,0 +1,264 @@
|
|||
<?php
|
||||
|
||||
use \App\Services\{Auth, DB, Date, TaskScheduler};
|
||||
use \App\Models\User;
|
||||
|
||||
$task = new TaskScheduler();
|
||||
|
||||
//$userprofile = new User(explode('/', $_SERVER['REQUEST_URI'])[2]);
|
||||
$contestCreate = true;
|
||||
if (!$task->isTaskExists("FinishContests", "php /path/to/finish_contests.php")) {
|
||||
$contestCreate = false;
|
||||
}
|
||||
?>
|
||||
|
||||
|
||||
<tr>
|
||||
<td class="main">
|
||||
<h1><b>Фотоконкурсы</b></h1>
|
||||
<div class="v-header__tabs">
|
||||
<div class="v-tabs">
|
||||
<div class="v-tabs__scroll">
|
||||
<div class="v-tabs__content"><a href="#" onclick="changeTab('contests')" id="contests" class="v-tab v-tab-b v-tab--active"><span class="v-tab__label">
|
||||
Конкурсы
|
||||
</span></a><a href="#" onclick="changeTab('categories')" id="categories" class="v-tab v-tab-b"><span class="v-tab__label">
|
||||
Категории
|
||||
|
||||
</span></a>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="kandle__block active__block" id="contests__block">
|
||||
<div class="p20w" style="display:block">
|
||||
<a data-bs-toggle="modal" data-bs-target="#createContest" href="#" class="btn btn-primary mt-3 <?php if ($contestCreate === false) {
|
||||
echo 'disabled';
|
||||
} ?>">Провести новый</a>
|
||||
<table class="table">
|
||||
<?php
|
||||
/*echo $task->addTask(
|
||||
"FinishContests",
|
||||
"php ".$_SERVER['DOCUMENT_ROOT']."/app/Controllers/Exec/Tasks/FinishContests.php >> ".$_SERVER['DOCUMENT_ROOT'].NGALLERY['root']['logslocation']." 2>&1",
|
||||
"* * * * *" // Каждую минуту (можно менять)
|
||||
);*/
|
||||
if ($contestCreate === false) {
|
||||
echo "<div class='alert alert-warning' role='alert'>У вас не добавлена задача на проведение конкурсов. Без неё, сервер не сможет завершать конкурс и проводить новый автоматически.</div>";
|
||||
}
|
||||
echo $task->removeTask("FinishContests", "php /path/to/finish_contests.php");
|
||||
|
||||
?>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th width="100">ID</th>
|
||||
<th width="25%">Тема</th>
|
||||
<th>Дата начала отбора</th>
|
||||
<th>Дата конца отбора</th>
|
||||
<th>Дата начала</th>
|
||||
<th>Дата конца</th>
|
||||
<th>Статус</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<?php
|
||||
$themes = DB::query('SELECT * FROM contests ORDER BY id DESC');
|
||||
foreach ($themes as $t) {
|
||||
$themetitle = DB::query('SELECT title FROM contests_themes WHERE id=:id', array(':id' => $t['themeid']))[0]['title'];
|
||||
if ($t['status'] === 0) {
|
||||
$status = 'Ещё не проведён';
|
||||
} else if ($t['status'] === 1) {
|
||||
$status = 'Отбор кандидатов';
|
||||
} else if ($t['status'] === 2) {
|
||||
$status = 'Отбор победителей';
|
||||
} else if ($t['status'] === 3) {
|
||||
$status = 'Завершён';
|
||||
} else {
|
||||
$status = 'Сбой';
|
||||
}
|
||||
echo '<tr class="' . $color . '">
|
||||
<td>' . $t['id'] . '</td>
|
||||
<td>' . $themetitle . '</td>
|
||||
<td>' . Date::zmdate($t['openpretendsdate']) . '</td>
|
||||
<td>' . Date::zmdate($t['closepretendsdate']) . '</td>
|
||||
<td>' . Date::zmdate($t['opendate']) . '</td>
|
||||
<td>' . Date::zmdate($t['closedate']) . '</td>
|
||||
<td>' . $status . '</td>
|
||||
</tr>';
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="kandle__block" style="display: none;" id="categories__block">
|
||||
<div class="p20w" style="display:block">
|
||||
<a data-bs-toggle="modal" data-bs-target="#createContestTheme" href="#" class="btn btn-primary mt-3">Создать</a>
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th width="100">ID</th>
|
||||
<th width="50%">Название</th>
|
||||
<th>В автоматическом отборе</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<?php
|
||||
$themes = DB::query('SELECT * FROM contests_themes');
|
||||
foreach ($themes as $t) {
|
||||
if ($t['status'] === 1) {
|
||||
$auto = 'Да';
|
||||
} else {
|
||||
$auto = 'Нет';
|
||||
}
|
||||
echo '<tr class="' . $color . '">
|
||||
<td>' . $t['id'] . '</td>
|
||||
<td>' . $t['title'] . '</td>
|
||||
<td>' . $auto . '</td>
|
||||
</tr>';
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<div class="modal fade" id="createContest" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h1 class="modal-title fs-5" id="exampleModalLabel"><b>Создание конкурса</b></h1>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="contest">
|
||||
<div class="mb-3">
|
||||
<label for="exampleFormControlTextarea1" class="form-label">Тематика</label>
|
||||
<select name="themeid" class="form-select" aria-label="Default select example">
|
||||
<option selected>Open this select menu</option>
|
||||
<option value="1">One</option>
|
||||
<option value="2">Two</option>
|
||||
<option value="3">Three</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="exampleFormControlTextarea1" class="form-label">Дата начала отбора претенднетов</label>
|
||||
<input name="openpretendsdate" type="datetime-local" class="form-select">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="exampleFormControlTextarea1" class="form-label">Дата конца отбора претенднетов</label>
|
||||
<input name="closepretendsdate" type="datetime-local" class="form-select">
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<div class="form-check">
|
||||
<input name="startContestNow" class="form-check-input" type="checkbox" value="1" id="startContestNow">
|
||||
<label class="form-check-label" for="startContestNow">
|
||||
Провести конкурс сразу после конца отбора претендентов
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="contestStart" class="form-label">Дата начала проведения конкурса</label>
|
||||
<input id="contestStartInput" name="opendate" type="datetime-local" class="form-select">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="exampleFormControlTextarea1" class="form-label">Дата конца проведения конкурса</label>
|
||||
<input name="closedate" type="datetime-local" class="form-select">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a type="button" class="btn btn-secondary" data-bs-dismiss="modal">Отмена</a>
|
||||
<a href="#" onclick="createContest(); return false;" data-bs-dismiss="modal" class="btn btn-primary">Добавить</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="createContestTheme" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h1 class="modal-title fs-5" id="exampleModalLabel"><b>Добавление категории конкурса</b></h1>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="contestTheme">
|
||||
<div class="mb-3">
|
||||
<label for="exampleFormControlTextarea1" class="form-label">Название</label>
|
||||
<input class="form-control" id="exampleFormControlTextarea1" name="body">
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="1" name="active" id="flexCheckChecked" checked>
|
||||
<label class="form-check-label" for="flexCheckChecked">
|
||||
Активна для автоматического подбора
|
||||
</label>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a type="button" class="btn btn-secondary" data-bs-dismiss="modal">Отмена</a>
|
||||
<a href="#" onclick="createContestTheme(); return false;" data-bs-dismiss="modal" class="btn btn-primary">Добавить</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#startContestNow').on('change', function() {
|
||||
$('#contestStartInput').prop('disabled', $(this).is(':checked'));
|
||||
});
|
||||
});
|
||||
function createContestTheme() {
|
||||
var formData = new FormData(document.getElementById("contestTheme"));
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: '/api/admin/contests/createtheme',
|
||||
data: formData,
|
||||
success: function(response) {
|
||||
var jsonData = JSON.parse(response);
|
||||
|
||||
Notify.noty('success', 'OK!');
|
||||
|
||||
|
||||
},
|
||||
cache: false,
|
||||
contentType: false,
|
||||
processData: false
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function createContest() {
|
||||
var formData = new FormData(document.getElementById("contest"));
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: '/api/admin/contests/create',
|
||||
data: formData,
|
||||
success: function(response) {
|
||||
var jsonData = JSON.parse(response);
|
||||
|
||||
Notify.noty('success', 'OK!');
|
||||
|
||||
|
||||
},
|
||||
cache: false,
|
||||
contentType: false,
|
||||
processData: false
|
||||
});
|
||||
|
||||
}
|
||||
</script>
|
|
@ -39,10 +39,10 @@ use \App\Models\User;
|
|||
<div class="v-header__tabs">
|
||||
<div class="v-tabs">
|
||||
<div class="v-tabs__scroll">
|
||||
<div class="v-tabs__content"><a href="#" onclick="changeTab('full')" id="full" class="v-tab v-tab--active"><span class="v-tab__label">
|
||||
<div class="v-tabs__content"><a href="#" onclick="changeTab('full')" id="full" class="v-tab v-tab-b v-tab--active"><span class="v-tab__label">
|
||||
Полный список
|
||||
|
||||
</span></a><a href="#" onclick="changeTab('moderate')" id="moderate" class="v-tab"><span class="v-tab__label">
|
||||
</span></a><a href="#" onclick="changeTab('moderate')" id="moderate" class="v-tab v-tab-b"><span class="v-tab__label">
|
||||
Ожидают модерации
|
||||
|
||||
</span></a>
|
||||
|
|
Loading…
Reference in a new issue