Compare commits

...

41 commits

Author SHA1 Message Date
themohooks
f4cb133e46 fixes 2025-02-21 23:55:20 +03:00
themohooks
540e643e9a Update Index.php 2025-02-21 23:30:47 +03:00
themohooks
e82faca521 патч номер один 2025-02-21 00:31:27 +03:00
themohooks
dea3e88c38 Create sql_0003.sql 2025-02-18 16:41:25 +03:00
themohooks
8681ba9060 Update ngallery-example.yaml 2025-02-18 16:28:01 +03:00
themohooks
cfab1d2e96 update admin pages 2025-02-18 00:28:37 +03:00
themohooks
118968739c update contests 2025-02-18 00:08:13 +03:00
themohooks
04373e197c update contest pages 2025-02-17 23:10:16 +03:00
themohooks
847ebb32be Update VotingWaiting.php 2025-02-17 22:33:04 +03:00
themohooks
0275ff30c6 update send pretend 2025-02-17 22:19:26 +03:00
themohooks
b41ec07317 contests 2025-02-17 22:10:46 +03:00
themohooks
e9655f6463 trash 2025-02-16 06:19:08 +03:00
themohooks
8b8cedf6c1 prretend send 2025-02-16 06:19:04 +03:00
themohooks
303d70d1a3 Update ExecContests.php 2025-02-16 06:18:56 +03:00
themohooks
c31617fd10 update pages 2025-02-16 06:18:52 +03:00
themohooks
4ee7f4b79b update rate contest photos 2025-02-16 06:18:43 +03:00
themohooks
0581edcc3d update js 2025-02-16 06:18:24 +03:00
themohooks
83b0e8ccc9 Update Register.php 2025-02-16 06:18:13 +03:00
themohooks
1dab03afe8 update pages 2025-02-16 04:37:24 +03:00
themohooks
be2963117a task manager & contests via server 2025-02-16 04:37:18 +03:00
themohooks
b5ff9d1998 update contests api 2025-02-16 04:37:06 +03:00
themohooks
3360b9d208 update admin 2025-02-16 04:36:52 +03:00
themohooks
52dbf10d3d update core files 2025-02-16 04:36:38 +03:00
themohooks
be85a9531a contests to photos 2025-02-15 04:54:34 +03:00
themohooks
13f06db887 admin contest pages 2025-02-15 04:54:22 +03:00
themohooks
22e0fe0cec add contest pages 2025-02-15 04:54:12 +03:00
themohooks
b0c8b51fe6 Update Register.php 2025-02-15 04:54:02 +03:00
themohooks
020ec19124 contests api 2025-02-15 04:53:57 +03:00
themohooks
2e5c8ffbb0 materials update 2025-02-15 04:53:38 +03:00
themohooks
8087b7c720 Update .gitignore 2025-02-15 04:53:15 +03:00
themohooks
2918dd347b fix register 2025-02-14 21:29:20 +03:00
themohooks
a665b92e11 Update README.md 2025-02-14 19:56:11 +03:00
themohooks
07a6a41468 another changes 2025-02-14 19:55:09 +03:00
themohooks
61c0e0cc9e some changes to vehicles 2025-02-14 19:54:55 +03:00
themohooks
dce7aa906a comments.php 2025-02-12 16:58:20 +03:00
themohooks
3078238206 fix place on photo 2025-02-12 16:35:08 +03:00
themohooks
69706f7df6 Update Comment.php 2025-02-12 13:00:02 +03:00
themohooks
ab9b61c3ea fix show delete & edit buttons in comments 2025-02-12 12:58:17 +03:00
themohooks
3d03ccce6f fix entity show info 2025-02-11 21:53:43 +03:00
themohooks
9774d329fd Update Main.php 2025-02-11 21:31:13 +03:00
themohooks
3b3efb4c84 fix show page 2025-02-11 21:17:35 +03:00
68 changed files with 3520 additions and 385 deletions

4
.gitignore vendored
View file

@ -6,10 +6,12 @@
/ngallery.yaml
ngallery.yaml
/cdn/
*.yaml
ngallery.yaml
/views/pages/t.php
views/pages/t.php
rules.txt
rules.txt
/uploads/*
t.php
logs
.txt

View file

@ -55,7 +55,6 @@ NativeGallery - это реверсивный open-source движок попу
- [x] Полноценный EXIF
- [x] Модерация
- [ ] Редактирование
- [ ] Примечания (для сущностей)
- [ ] Обновления:
- [x] Новые фотографии
- [x] Новые фотографии из подписок

View file

@ -0,0 +1,31 @@
<?php
namespace App\Controllers\Api\Admin\Contests;
use App\Services\{Auth, Router, GenerateRandomStr, DB, Json, EXIF};
use App\Models\{User, Vote, Photo};
class Create
{
public function __construct()
{
$openprdate = strtotime($_POST['openpretendsdate']);
$closeprdate = strtotime($_POST['closepretendsdate']);
$opendate = strtotime($_POST['opendate']);
$closedate = strtotime($_POST['closedate']);
if ($_POST['startContestNow'] === "1") {
$opendate = $closeprdate;
}
DB::query('INSERT INTO contests VALUES (\'0\', :themeid, :openprdate, :closeprdate, :opendate, :closedate, 0)', array(':themeid' => $_POST['themeid'], ':openprdate' => $openprdate, ':closeprdate'=>$closeprdate, ':opendate' => $opendate, ':closedate'=>$closedate));
echo json_encode(
array(
'errorcode' => 0,
'error' => 0
)
);
}
}

View file

@ -0,0 +1,28 @@
<?php
namespace App\Controllers\Api\Admin\Contests;
use App\Services\{Auth, Router, GenerateRandomStr, DB, Json, EXIF};
use App\Models\{User, Vote, Photo};
class CreateTheme
{
public function __construct()
{
if ($_POST['active'] === "1") {
$status = 1;
} else {
$status = 0;
}
DB::query('INSERT INTO contests_themes VALUES (\'0\', :title, :status)', array(':title' => $_POST['body'], ':status' => $status));
echo json_encode(
array(
'errorcode' => 0,
'error' => 0
)
);
}
}

View file

@ -0,0 +1,37 @@
<?php
namespace App\Controllers\Api\Admin\Settings;
use App\Services\{Auth, Router, GenerateRandomStr, DB, Json, EXIF, TaskScheduler};
use App\Models\{User, Vote, Photo};
class TaskManager
{
public function __construct()
{
$task = new TaskScheduler();
foreach (NGALLERY_TASKS as $t) {
$id = $_GET['id'];
if (isset($t['id']) && $t['id'] == $id) {
if ($_GET['type'] === 0) {
$task->removeTask($t['id'], "php ".$_SERVER['DOCUMENT_ROOT'].$t['handler']);
} else {
$task->addTask(
$t['id'],
"php ".$_SERVER['DOCUMENT_ROOT'].$t['handler']." >> ".$_SERVER['DOCUMENT_ROOT'].NGALLERY['root']['logslocation']." 2>&1",
"* * * * *"
);
}
echo json_encode(
array(
'errorcode' => 0,
'error' => 0
)
);
}
}
}
}

View file

@ -0,0 +1,59 @@
<?php
namespace App\Controllers\Api\Contests;
use App\Services\{DB, Json};
class GetInfo
{
private array $contest;
private string $pretendsStatus;
private string $publicStatus;
public function __construct()
{
$this->fetchContest();
$this->setStatuses();
$this->outputJson();
}
private function fetchContest(): void
{
$statuses = [0, 1, 2];
foreach ($statuses as $status) {
$contest = DB::query('SELECT * FROM contests WHERE status = :status', [':status' => $status]);
if (!empty($contest)) {
$this->contest = $contest[0];
break;
}
}
}
private function setStatuses(): void
{
$time = time();
$status = $this->contest['status'] ?? null;
if ($status === 0) {
$this->pretendsStatus = ($this->contest['openpretendsdate'] > $time) ? 'waiting' : 'waitingforserver';
$this->publicStatus = 'closed';
} elseif ($status === 1) {
$this->pretendsStatus = ($this->contest['closepretendsdate'] > $time) ? 'opened' : 'waitingforserver';
$this->publicStatus = 'closed';
} elseif ($status === 2) {
$this->pretendsStatus = 'closed';
$this->publicStatus = ($this->contest['closedate'] <= $time) ? 'waitingforserver' : 'opened';
}
}
private function outputJson(): void
{
echo json_encode(array(
'contest' => $this->contest,
'statuses' => [
'pretends' => $this->pretendsStatus,
'public' => $this->publicStatus,
]
));
}
}

View file

@ -0,0 +1,46 @@
<?php
namespace App\Controllers\Api\Images\Contests;
use App\Services\{Auth, Router, GenerateRandomStr, DB, Json, EXIF};
use App\Models\{User, Vote, Photo};
class Rate
{
public function __construct()
{
$count = 3;
$uservotes = DB::query('SELECT COUNT(*) FROM contests_rates WHERE user_id=:uid AND contest_id=:cid', array(':uid' => Auth::userid(), ':cid' => $_GET['kid']))[0]['COUNT(*)'];
$countvotes = $count - $uservotes;
$contest = DB::query('SELECT * FROM contests WHERE id=:id', array(":id" => $_GET['kid']))[0];
$photo = new Photo($_GET['pid']);
if ($contest['status'] != 2) {
exit;
}
if ($photo->i('on_contest') != 1 && $photo->i('contest_id') != $_GET['kid']) {
exit;
}
if ((int)DB::query('SELECT photo_id FROM contests_rates WHERE photo_id=:pid AND user_id=:uid AND contest_id=:cid', array(':uid' => Auth::userid(), ':pid' => $_GET['pid'], ':cid' => $_GET['kid']))[0]['photo_id'] === (int)$_GET['pid']) {
DB::query('DELETE FROM contests_rates WHERE user_id=:uid AND photo_id=:pid AND contest_id=:cid', array(':pid' => $_GET['pid'], ':uid' => Auth::userid(), ':cid' => $_GET['kid']));
$status = 0;
$newval = $countvotes + 1;
} else {
$newval = $countvotes - 1;
if ($newval >= 0) {
DB::query('INSERT INTO contests_rates VALUES (\'0\', :pid, :uid, :cid)', array(':pid' => $_GET['pid'], ':uid' => Auth::userid(), ':cid' => $_GET['kid']));
$status = 1;
}
}
if ($newval < 0) {
$text = 'Вы можете выбрать максимум 3 фотографии.';
} else if ($newval === 0) {
$text = 'Вы выбрали 3 фотографии. Спасибо за голосование!';
} else {
$text = "Вы можете выбрать ещё {$newval} фото.";
}
echo '[{"' . $_GET['pid'] . '":'.$status.'},"' . $text . '"]';
}
}

View file

@ -0,0 +1,34 @@
<?php
namespace App\Controllers\Api\Images\Contests;
use App\Services\{Auth, Router, GenerateRandomStr, DB, Json, EXIF};
use App\Models\{User, Vote};
class SendPretend
{
public function __construct()
{
if (isset($_POST['cid'])) {
if (DB::query('SELECT contest_id FROM photos WHERE user_id=:uid', array(':uid' => Auth::userid()))[0]['contest_id'] != $_POST['cid']) {
DB::query('UPDATE photos SET on_contest=1, contest_id=:id WHERE id=:idd', array(':id' => $_POST['cid'], ':idd' => $_POST['photo_id']));
echo json_encode(
array(
'errorcode' => 0,
'error' => 0
)
);
}
} else {
echo json_encode(
array(
'errorcode' => 1,
'error' => 0
)
);
}
}
}

View file

@ -2,69 +2,103 @@
namespace App\Controllers\Api\Images;
use App\Services\{Auth, Router, GenerateRandomStr, DB, Json, EXIF};
use App\Models\{User, Vote};
use App\Models\{User, Vote, VoteContest};
class Rate
{
public function __construct()
{
if (isset($_GET['vote']) && isset($_GET['pid'])) {
if (Vote::photo(Auth::userid(), $_GET['pid']) === -1) {
DB::query('INSERT INTO photos_rates VALUES (\'0\', :id, :pid, :type, 0)', array(':id'=>Auth::userid(), ':pid' => $_GET['pid'], ':type'=>$_GET['vote']));
if (Vote::photo(Auth::userid(), $_GET['pid']) != $_GET['vote']) {
DB::query('DELETE FROM photos_rates WHERE user_id=:id AND photo_id=:pid AND type=:type', array(':id'=>Auth::userid(), ':pid' => $_GET['pid'], ':type'=>Vote::photo(Auth::userid(), $_GET['pid'])));
}
} else if (Vote::photo(Auth::userid(), $_GET['pid']) === (int)$_GET['vote']) {
DB::query('DELETE FROM photos_rates WHERE user_id=:id AND photo_id=:pid', array(':id'=>Auth::userid(), ':pid' => $_GET['pid']));
} else {
DB::query('UPDATE photos_rates SET type=:type WHERE user_id=:id AND photo_id=:pid', array(':id'=>Auth::userid(), ':pid' => $_GET['pid'], ':type'=>$_GET['vote']));
}
$votes = DB::query('SELECT * FROM photos_rates WHERE photo_id=:id ORDER BY id DESC', array(':id' => $_GET['pid']));
$userId = Auth::userid();
$photoId = $_GET['pid'];
$voteType = (int) $_GET['vote'];
$contest = (isset($_GET['action']) && $_GET['action'] === 'vote-konk') ? 1 : 0;
$contestId = $_GET['cid'];
if ($contest === 1) {
if (VoteContest::photo($userId, $photoId, $contestId) === -1) {
DB::query(
'INSERT INTO photos_rates_contest (id, user_id, photo_id, type, contest_id) VALUES (NULL, :id, :pid, :type, :cid)',
[':id' => $userId, ':pid' => $photoId, ':type' => $voteType, ':cid'=>$contestId]
);
if (VoteContest::photo($userId, $photoId, $contestId) != $voteType) {
DB::query(
'DELETE FROM photos_rates_contest WHERE user_id=:id AND photo_id=:pid AND type=:type AND contest_id=:cid',
[':id' => $userId, ':pid' => $photoId, ':type' => VoteContest::photo($userId, $photoId, $contestId), ':cid'=>$contestId]
);
}
} elseif (VoteContest::photo($userId, $photoId, $contestId) === $voteType) {
DB::query(
'DELETE FROM photos_rates_contest WHERE user_id=:id AND photo_id=:pid AND contest_id=:cid',
[':id' => $userId, ':pid' => $photoId, ':cid'=>$contestId]
);
} else {
DB::query(
'UPDATE photos_rates_contest SET type=:type WHERE user_id=:id AND photo_id=:pid AND contest_id=:cid',
[':id' => $userId, ':pid' => $photoId, ':type' => $voteType, ':cid'=>$contestId]
);
}
} else {
if (Vote::photo($userId, $photoId) === -1) {
DB::query(
'INSERT INTO photos_rates (id, user_id, photo_id, type, contest) VALUES (NULL, :id, :pid, :type, 0)',
[':id' => $userId, ':pid' => $photoId, ':type' => $voteType]
);
if (Vote::photo($userId, $photoId) != $voteType) {
DB::query(
'DELETE FROM photos_rates WHERE user_id=:id AND photo_id=:pid AND type=:type AND contest=0',
[':id' => $userId, ':pid' => $photoId, ':type' => Vote::photo($userId, $photoId)]
);
}
} elseif (Vote::photo($userId, $photoId) === $voteType) {
DB::query(
'DELETE FROM photos_rates WHERE user_id=:id AND photo_id=:pid AND contest=0',
[':id' => $userId, ':pid' => $photoId]
);
} else {
DB::query(
'UPDATE photos_rates SET type=:type WHERE user_id=:id AND photo_id=:pid AND contest=0',
[':id' => $userId, ':pid' => $photoId, ':type' => $voteType]
);
}
}
$votes = DB::query('SELECT * FROM photos_rates WHERE photo_id=:id ORDER BY id DESC', [':id' => $photoId]);
$formattedVotesPos = [];
$formattedVotesNeg = [];
foreach ($votes as $vote) {
$user = new User($vote['user_id']);
if ($vote['type'] === 0) {
$type = 0;
$formattedVotesNeg[] = [$vote['user_id'], $user->i('username'), $type];
} else if ($vote['type'] === 1) {
$type = 1;
$formattedVotesPos[] = [$vote['user_id'], $user->i('username'), $type];
$formattedVotesNeg[] = [$vote['user_id'], $user->i('username'), 0];
} elseif ($vote['type'] === 1) {
$formattedVotesPos[] = [$vote['user_id'], $user->i('username'), 1];
}
}
if (Vote::photo(Auth::userid(), $_GET['pid']) === 0) {
$negbtn = true;
$posbtn = false;
} else if (Vote::photo(Auth::userid(), $_GET['pid']) === 1) {
$negbtn = false;
$posbtn = true;
$currentVote = Vote::photo($userId, $photoId);
$contCurrentVote = VoteContest::photo($userId, $photoId, $contestId);
if ($contest === 0) {
$count = Vote::count($photoId);
} else {
$negbtn = false;
$posbtn = false;
$count = VoteContest::count($photoId, $contestId);
}
$result = [
'buttons' => [$negbtn, $posbtn],
'buttons' => [
'negbtn' => $currentVote === 0,
'posbtn' => $currentVote === 1,
'negbtn_contest' => $contCurrentVote === 0,
'posbtn_contest' => $contCurrentVote === 1,
],
'errors' => '',
'rating' => Vote::count($_GET['pid'])
'rating' => $count,
'votes' => [
1 => $formattedVotesPos,
0 => $formattedVotesNeg
]
];
$votes = [];
$votes[1] = $formattedVotesPos;
$votes[0] = $formattedVotesNeg;
if (!empty($votes)) {
$result['votes'] = $votes;
}
header('Content-Type: application/json');
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);

View file

@ -37,7 +37,7 @@ class Upload
} else {
$moderated = 1;
}
DB::query('INSERT INTO photos VALUES (\'0\', :userid, :postbody, :photourl, :time, :timeup, :exif, 0, :moderated, :place, 0, :gallery, :entityid, 0, :content)', array(':postbody' => $postbody, ':userid' => Auth::userid(), ':time' => mktime(0, 0, 0, $_POST['month'], $_POST['day'], $_POST['year']), ':content' => $content, ':photourl' => self::$photourl, ':exif' => $exif, ':place' => $_POST['place'], ':timeup' => time(), ':moderated' => $moderated, ':gallery'=>$_POST['gallery'], ':entityid'=>self::$entitydata_id));
DB::query('INSERT INTO photos VALUES (\'0\', :userid, :postbody, :photourl, :time, :timeup, :exif, 0, :moderated, :place, 0, :gallery, :entityid, 0, 0, 0, :content)', array(':postbody' => $postbody, ':userid' => Auth::userid(), ':time' => mktime(0, 0, 0, $_POST['month'], $_POST['day'], $_POST['year']), ':content' => $content, ':photourl' => self::$photourl, ':exif' => $exif, ':place' => $_POST['place'], ':timeup' => time(), ':moderated' => $moderated, ':gallery'=>$_POST['gallery'], ':entityid'=>self::$entitydata_id));
if (($moderated === 1) && (self::$subsnotify != 'disabled')) {
$followers = DB::query('SELECT * FROM followers WHERE user_id=:uid', array(':uid' => Auth::userid()));
foreach ($followers as $f) {

View file

@ -321,7 +321,9 @@ class Register
if (NGALLERY['root']['registration']['emailverify'] === true) {
$status === 3;
}
$token = GenerateRandomStr::gen_uuid();
DB::query('INSERT INTO users VALUES (\'0\', :username, :email, :password, :photourl, 5, :online, 0, :status, :content)', array(':username' => ltrim($username), ':password' => password_hash(ltrim($password), PASSWORD_BCRYPT), ':photourl' => '/static/img/avatar.png', ':email' => $email, ':content' => $content, ':online' => time(), ':status'=>$status));
$user_id = DB::query('SELECT id FROM users WHERE username=:username', array(':username' => $username))[0]['id'];
if (NGALLERY['root']['registration']['emailverify'] === true) {
$disposableEmailFilter = new DisposableEmailFilter();
if ($disposableEmailFilter->isDisposableEmailAddress($_POST['email'])) {
@ -334,8 +336,6 @@ class Register
);
die();
}
$token = GenerateRandomStr::gen_uuid();
$user_id = DB::query('SELECT id FROM users WHERE username=:username', array(':username' => $username))[0]['id'];
$key = GenerateRandomStr::gen_uuid();
$content = Json::return(
array(

View file

@ -19,6 +19,9 @@ use \App\Controllers\Api\Images\Comments\Delete as PhotoCommentDelete;
use \App\Controllers\Api\Images\Comments\Pin as PhotoCommentPin;
use \App\Controllers\Api\Images\Comments\Load as PhotoCommentLoad;
use \App\Controllers\Api\Images\Comments\Rate as PhotoCommentVote;
use \App\Controllers\Api\Images\Contests\SendPretend as PhotoContestsSendPretend;
use \App\Controllers\Api\Images\Contests\Rate as PhotoContestsRate;
use \App\Controllers\Api\Contests\GetInfo as ContestsGetInfo;
use \App\Controllers\Api\GeoDB\Search as GeoDBSearch;
use \App\Controllers\Api\Vehicles\Load as VehiclesLoad;
use \App\Controllers\Api\Profile\Update as ProfileUpdate;
@ -31,6 +34,9 @@ use \App\Controllers\Api\Admin\GetVehicleInputs as AdminGetVehicleInputs;
use \App\Controllers\Api\Admin\GeoDB\Create as AdminGeoDBCreate;
use \App\Controllers\Api\Admin\GeoDB\Load as AdminGeoDBLoad;
use \App\Controllers\Api\Admin\GeoDB\Delete as AdminGeoDBDelete;
use \App\Controllers\Api\Admin\Contests\CreateTheme as AdminContestsCreateTheme;
use \App\Controllers\Api\Admin\Contests\Create as AdminContestsCreate;
use \App\Controllers\Api\Admin\Settings\TaskManager as AdminTaskManager;
class ApiController
{
@ -51,6 +57,9 @@ class ApiController
public static function photovote() {
return new PhotoVote();
}
public static function photovotecontest() {
return new PhotoContestsRate();
}
public static function photofavorite() {
return new PhotoFavorite();
}
@ -93,6 +102,9 @@ class ApiController
public static function recentphotos() {
return new PhotoLoadRecent();
}
public static function sendpretendphoto() {
return new PhotoContestsSendPretend();
}
public static function loaduser() {
return new UserLoad();
}
@ -108,6 +120,12 @@ class ApiController
public static function admingetvehicleinputs() {
return new AdminGetVehicleInputs();
}
public static function admincontestscreatetheme() {
return new AdminContestsCreateTheme();
}
public static function admincontestscreate() {
return new AdminContestsCreate();
}
public static function admingeodbcreate() {
return new AdminGeoDBCreate();
}
@ -117,9 +135,15 @@ class ApiController
public static function admingeodbdelete() {
return new AdminGeoDBDelete();
}
public static function admintaskmanager() {
return new AdminTaskManager();
}
public static function vehiclesload() {
return new VehiclesLoad();
}
public static function contestsgetinfo() {
return new ContestsGetInfo();
}
}

View file

@ -17,5 +17,15 @@ class ContestsController
Page::set('Contests/VotingIndex');
}
public static function waiting()
{
Page::set('Contests/VotingWaiting');
}
public static function sendpretend()
{
Page::set('Contests/VotingSendPretend');
}
}

View file

@ -0,0 +1,186 @@
<?php
namespace App\Controllers\Exec\Tasks;
require_once __DIR__ . '/../../../../vendor/autoload.php';
use Symfony\Component\Yaml\Yaml;
define("NGALLERY", Yaml::parse(file_get_contents(__DIR__ . '/../../../../ngallery.yaml'))['ngallery']);
use App\Services\{Router, Auth, DB, Json, Date};
use App\Controllers\ExceptionRegister;
use App\Core\Page;
class ExecContests
{
public static function run()
{
if (NGALLERY['root']['contests']['enabled'] != true) {
echo "Contests on this server disabled. Skip...";
exit;
}
$contests = DB::query('SELECT * FROM contests WHERE status < 3');
foreach ($contests as $contest) {
self::processContest($contest);
}
}
private static function processContest(array $contest)
{
echo "Checking contest ID {$contest['id']}\n";
switch ($contest['status']) {
case 0:
self::handleOpenPretends($contest);
break;
case 1:
self::handleClosePretends($contest);
break;
case 2:
self::handleClosingContest($contest);
break;
case 02:
self::handleClosePretendsByTime($contest);
break;
}
}
private static function handleOpenPretends(array $contest)
{
if (self::isAnotherContestInStatus(1)) {
echo "[{$contest['id']}] Waiting for another contest to complete dialing. Skip...\n";
return;
}
if ($contest['openpretendsdate'] <= time()) {
DB::query('UPDATE contests SET status = 1 WHERE id = :id', [':id' => $contest['id']]);
echo "[{$contest['id']}] Opened for pretends.\n";
} else {
echo "[{$contest['id']}] Not ready for open pretends. Skip...\n";
}
}
private static function handleClosePretends(array $contest)
{
if (self::isAnotherContestInStatus(2) || self::isAnotherContestInStatus(02)) {
echo "[{$contest['id']}] Waiting for another contest to end. Skip...\n";
return;
}
if ($contest['closepretendsdate'] <= time()) {
DB::query('UPDATE photos SET on_contest=2 WHERE on_contest=1 AND contest_id=:id', array(':id'=>$contest['id']));
if ($contest['opendate'] <= time()) {
DB::query('UPDATE contests SET status = 2 WHERE id = :id', [':id' => $contest['id']]);
echo "[{$contest['id']}] Opened.\n";
} else {
DB::query('UPDATE contests SET status = 02 WHERE id = :id', [':id' => $contest['id']]);
}
echo "[{$contest['id']}] Closed for pretends.\n";
} else {
echo "[{$contest['id']}] Not closed for pretends. Skip...\n";
}
}
private static function handleClosePretendsByTime(array $contest)
{
echo "[{$contest['id']}] Cheking for Open by time...\n";
if ($contest['opendate'] <= time()) {
DB::query('UPDATE contests SET status = 2 WHERE id = :id', [':id' => $contest['id']]);
echo "[{$contest['id']}] .\n";
} else {
echo "[{$contest['id']}] not opened by time. Skip...\n";
}
echo "[{$contest['id']}] Opened.\n";
}
private static function handleClosingContest(array $contest)
{
if ($contest['closedate'] > time()) {
echo "[{$contest['id']}] Waiting for end time. Skip...\n";
return;
}
echo "[{$contest['id']}] Ready for closing!\n";
self::processVotes($contest);
DB::query('UPDATE contests SET status = 3 WHERE id = :id', [':id' => $contest['id']]);
DB::query('UPDATE photos SET contest_id = 0, on_contest = 0 WHERE contest_id = :id', [':id' => $contest['id']]);
echo "[{$contest['id']}] Closed.\n";
if (NGALLERY['root']['contests']['autonew']['enabled'] === true) {
echo "Creating new contest...";
$theme = DB::query('SELECT * FROM contests_themes WHERE status=1 ORDER BY RAND() LIMIT 1')[0];
if (count($theme) <= 0) {
echo "Not found themes for autocreating Contest. Skip...\n";
return;
}
$time = time();
if (NGALLERY['root']['contests']['autonew']['times']['pretendsopen'] === 'now') {
$pretendsopen = $time;
$status = 1;
} else {
$status = 0;
$pretendsopen = Date::addTime(NGALLERY['root']['contests']['autonew']['times']['pretendsopen']);
}
$pretendsclose = Date::addTime(NGALLERY['root']['contests']['autonew']['times']['pretendsclose']);
if (NGALLERY['root']['contests']['autonew']['times']['open'] === 'now') {
$contestopen = $pretendsclose;
} else {
$contestopen = Date::addTime(NGALLERY['root']['contests']['autonew']['times']['open']);
}
$contestclose = Date::addTime(NGALLERY['root']['contests']['autonew']['times']['close']);
DB::query('INSERT INTO contests VALUES (\'0\', :themeid, :openprdate, :closeprdate, :opendate, :closedate, :status)', array(':themeid'=>$theme['id'], ':openprdate'=>$pretendsopen, ':closeprdate'=>$pretendsclose, ':opendate'=>$contestopen, ':closedate'=>$contestclose, ':status'=>$status));
echo "Contest created! Continue...";
}
}
private static function processVotes(array $contest)
{
$votes = DB::query(
'SELECT user_id, photo_id, COUNT(*) AS vote_count
FROM contests_rates WHERE contest_id = :id
GROUP BY user_id ORDER BY vote_count DESC LIMIT 10',
[':id' => $contest['id']]
);
$place = 1;
foreach ($votes as $vote) {
self::updatePhotoContent($vote, $contest, $place);
$place++;
}
}
private static function updatePhotoContent(array $vote, array $contest, int $place)
{
$photo = DB::query('SELECT * FROM photos WHERE id = :id', [':id' => $vote['photo_id']])[0];
$photoData = json_decode($photo['content'], true);
if (!isset($photoData['contests']) || !is_array($photoData['contests'])) {
$photoData['contests'] = [];
}
$theme = DB::query('SELECT title FROM contests_themes WHERE id = :id', [':id' => $contest['themeid']])[0]['title'];
$photoData['contests'][] = [
'id' => $contest['id'],
'contesttheme' => $theme,
'votenum' => $vote['vote_count'],
'place' => $place
];
DB::query('INSERT INTO contests_winners VALUES (\'0\', :photo_id, :place, :contest_id, :date)', array(':photo_id'=>$vote['photo_id'], ':place'=>$place, ':contest_id'=>$contest['id'], ':date'=>time()));
DB::query('UPDATE photos SET content = :content, on_contest=0, contest_id=0 WHERE id = :id', [
':id' => $vote['photo_id'],
':content' => json_encode($photoData, JSON_UNESCAPED_UNICODE)
]);
}
private static function isAnotherContestInStatus(int $status): bool
{
return !empty(DB::query('SELECT status FROM contests WHERE status = :status', [':status' => $status]));
}
}
if (php_sapi_name() === 'cli') {
ExecContests::run();
}

View file

@ -0,0 +1,4 @@
tasks:
- id: "ExecContests"
type: "cron"
handler: "/app/Controllers/Exec/Tasks/ExecContests.php"

View file

@ -16,6 +16,11 @@ class MainController
{
Page::set('Main');
}
public static function page()
{
Page::set('Page');
}
public static function about()
{
@ -47,11 +52,6 @@ class MainController
{
Page::set('Top30');
}
public static function vehicle()
{
Page::set('Vehicle');
}
public static function feed()
{
@ -77,6 +77,11 @@ class MainController
{
Page::set('Errors/EmailVerify');
}
public static function comments()
{
Page::set('Comments/Index');
}
public static function tour()
{

View file

@ -9,7 +9,7 @@ class SearchController
{
public static function i()
{
Page::set('Search');
Page::set('Search/Index');
}

View file

@ -0,0 +1,23 @@
<?php
namespace App\Controllers;
use \App\Services\{Router, Auth, DB, Json};
use \App\Controllers\ExceptionRegister;
use \App\Core\Page;
class VehicleController
{
public static function i()
{
Page::set('Vehicle/Index');
}
public static function iedit()
{
Page::set('Vehicle/IndexEdit');
}
public static function dbedit()
{
Page::set('Vehicle/DBEdit');
}
}

View file

@ -17,12 +17,12 @@ class Routes
Router::get('/register', 'RegisterController@i');
Router::get('/photo/$id', 'PhotoController@i');
Router::get('/author/$id', 'ProfileController@i');
Router::get('/page/$id', 'MainController@page');
Router::post('/api/login', 'ApiController@login');
Router::post('/api/register', 'ApiController@register');
Router::get('/api/photo/stats', 'ApiController@photostats');
Router::get('/about', 'MainController@about');
Router::get('/rules', 'MainController@rules');
Router::get('/vehicle/$id', 'MainController@vehicle');
Router::get('/rules/pub', 'MainController@publicationRules');
Router::get('/rules/photo', 'MainController@photoRules');
Router::get('/rules/video', 'MainController@videoRules');
@ -38,9 +38,11 @@ class Routes
Router::get('/article/$id', 'MainController@gallery');
Router::get('/voting', 'ContestsController@index');
Router::get('/voting/results', 'ContestsController@results');
Router::get('/voting/waiting', 'ContestsController@waiting');
Router::get('/comments', 'MainController@comments');
if (Auth::userid() > 0) {
$user = new \App\Models\User(Auth::userid());
Router::get('/lk', 'ProfileController@lk');
Router::get('/lk/upload', 'ProfileController@upload');
Router::get('/lk/history', 'ProfileController@lkhistory');
@ -51,7 +53,10 @@ class Routes
Router::get('/search', 'SearchController@i');
Router::get('/fav', 'MainController@fav');
Router::get('/voting/sendpretend', 'ContestsController@sendpretend');
Router::get('/vehicle/edit', 'VehicleController@iedit');
Router::get('/vehicle/dbedit', 'VehicleController@dbedit');
Router::post('/api/upload', 'ApiController@upload');
Router::post('/api/profile/update', 'ApiController@updateprofile');
Router::post('/api/photo/comment', 'ApiController@photocomment');
@ -64,6 +69,9 @@ class Routes
Router::post('/api/photo/comment/$id/edit', 'ApiController@photocommentedit');
Router::post('/api/photo/comment/$id/delete', 'ApiController@photocommentdelete');
Router::post('/api/photo/comment/$id/pin', 'ApiController@photocommentpin');
Router::post('/api/photo/contests/sendpretend', 'ApiController@sendpretendphoto');
Router::get('/api/photo/contests/rate', 'ApiController@photovotecontest');
Router::get('/api/contests/getinfo', 'ApiController@contestsgetinfo');
Router::get('/api/vehicles/load', 'ApiController@vehiclesload');
Router::get('/api/geodb/search', 'ApiController@geodbsearch');
if ($user->i('admin') > 0) {
@ -74,11 +82,15 @@ class Routes
Router::any('/api/admin/getvehicleinputs/$id', 'ApiController@admingetvehicleinputs');
Router::any('/api/admin/geodb/create', 'ApiController@admingeodbcreate');
Router::any('/api/admin/geodb/load', 'ApiController@admingeodbload');
Router::any('/api/admin/contests/createtheme', 'ApiController@admincontestscreatetheme');
Router::any('/api/admin/contests/create', 'ApiController@admincontestscreate');
Router::any('/api/admin/settings/taskmanager', 'ApiController@admintaskmanager');
}
Router::get('/logout', 'MainController@logout');
Router::get('/404', 'ExceptionRegister@notfound');
} else {
Router::redirect('/login?return='.$_SERVER['HTTP_REFERER']);
}
Router::get('/vehicle/$id', 'VehicleController@i');
}
}

View file

@ -108,12 +108,19 @@ class Comment
if ($this->c['user_id'] === Auth::userid() || $photo->i('user_id') === Auth::userid()) {
echo '
<div class="dropdown">
<a style="color: #000" class="compl" href="/lk/ticket.php?action=add&amp;wid=3252565">...</a>
<div class="dropdown-content">'; ?>
<a style="margin-bottom: 10px;" href="#" onclick="createModal(<?= $this->c['id'] ?>, 'EDIT_COMMENT', '<?= htmlspecialchars($this->c['body']) ?>', 'modaledit<?= $this->c['id'] ?>'); return false;">Редактировать</a><br>
<a style="color: #000" class="compl" href="#">...</a>
<div class="dropdown-content">';
?>
<a href="#" onclick="pinComment(<?= $this->c['id'] ?>); return false;"><?=$pinc?></a><br>
<?php
if ($this->c['user_id'] === Auth::userid()) { ?>
<a style="margin-bottom: 10px;" href="#" onclick="createModal(<?= $this->c['id'] ?>, 'EDIT_COMMENT', '<?= htmlspecialchars($this->c['body']) ?>', 'modaledit<?= $this->c['id'] ?>'); return false;">Редактировать</a><br>
<a href="#" onclick="createModal(<?= $this->c['id'] ?>, 'DELETE_COMMENT', '', 'modaldel<?= $this->c['id'] ?>'); return false;">Удалить</a>
<?php
<?php }
echo '
</div>
</div>

View file

@ -7,7 +7,23 @@ class Vote
{
public static function photo($user_id, $pid)
{
$result = DB::query('SELECT type FROM photos_rates WHERE user_id=:uid AND photo_id=:pid', array(':uid' => $user_id, ':pid' => $pid));
$result = DB::query('SELECT type FROM photos_rates WHERE user_id=:uid AND photo_id=:pid AND contest=0', array(':uid' => $user_id, ':pid' => $pid));
if (!empty($result)) {
$type = $result[0]['type'];
if ($type < 0) {
$type = -1;
}
return $type;
} else {
return -1;
}
}
public static function photoContest($user_id, $pid)
{
$result = DB::query('SELECT type FROM photos_rates WHERE user_id=:uid AND photo_id=:pid AND contest=1', array(':uid' => $user_id, ':pid' => $pid));
if (!empty($result)) {
$type = $result[0]['type'];
if ($type < 0) {

View file

@ -0,0 +1,37 @@
<?php
namespace App\Models;
use App\Services\{DB, GenerateRandomStr};
class VoteContest
{
public static function photo($user_id, $pid, $cid)
{
$result = DB::query('SELECT type FROM photos_rates_contest WHERE user_id=:uid AND photo_id=:pid AND contest_id=:id', array(':uid' => $user_id, ':pid' => $pid, ':id'=>$cid));
if (!empty($result)) {
$type = $result[0]['type'];
if ($type < 0) {
$type = -1;
}
return $type;
} else {
return -1;
}
}
public static function count($pid, $cid) {
$result = DB::query('SELECT * FROM photos_rates_contest WHERE photo_id=:pid AND contest_id=:id', array(':pid' => $pid, ':id'=>$cid));
$votes = 0;
foreach ($result as $r) {
if ($r['type'] === 1) {
$votes++;
} else {
$votes--;
}
}
return $votes;
}
}
?>

View file

@ -1,5 +1,6 @@
<?php
namespace App\Services;
use InvalidArgumentException;
class Date
{
@ -65,5 +66,38 @@ class Date
);
return $formattedDate;
}
public static function addTime($timeString, int $baseTime = null)
{
if ($baseTime === null) {
$baseTime = time();
}
preg_match('/^(\d+)([smhdwMy])$/', $timeString, $matches);
if (!$matches) {
throw new InvalidArgumentException("Неверный формат времени: $timeString");
}
[$fullMatch, $amount, $unit] = $matches;
$amount = (int) $amount;
$multipliers = [
's' => 1, // секунды
'm' => 60, // минуты
'h' => 3600, // часы
'd' => 86400, // дни
'w' => 604800, // недели
'M' => 2629743, // месяцы (среднее значение)
'y' => 31556926 // годы (среднее значение)
];
if (!isset($multipliers[$unit])) {
throw new InvalidArgumentException("Неизвестная единица измерения: $unit");
}
return $baseTime + ($amount * $multipliers[$unit]);
}
}
?>

View file

@ -0,0 +1,152 @@
<?php
namespace App\Services;
class TaskScheduler {
public function __construct() {}
private function isWindows() {
return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
}
public function addTask($taskName, $command, $interval = "* * * * *") {
return $this->isWindows() ? $this->addWindowsTask($taskName, $command) : $this->addLinuxTask($command, $interval);
}
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);
}
public function getTaskStatus($taskName, $command = null) {
if (!$this->isTaskExists($taskName, $command)) {
return "Не работает (задача отсутствует)";
}
return $this->isWindows() ? $this->getWindowsTaskStatus($taskName) : $this->getLinuxTaskStatus($command);
}
public function findHandlerById($array, $id) {
foreach ($array as $item) {
if (isset($item['id']) && $item['id'] === $id) {
return $item['handler'] ?? null;
}
}
return null;
}
private function addLinuxTask($command, $interval) {
$cronJob = "{$interval} {$command}";
if ($this->isLinuxTaskExists($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) !== 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) === 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 getLinuxTaskStatus($command) {
exec("ps aux | grep '" . escapeshellarg($command) . "' | grep -v grep", $output, $return_code);
if (empty($output)) {
return "Не работает (ошибка: процесс не найден)";
}
return "✅ Работает корректно";
}
private function addWindowsTask($taskName, $command) {
if ($this->isWindowsTaskExists($taskName)) {
return "✅ Задача уже существует в Windows.";
}
$cmd = "schtasks /Create /SC MINUTE /MO 1 /TN \"{$taskName}\" /TR \"{$command}\" /F";
exec($cmd, $output, $return_code);
return ($return_code === 0) ? "✅ Задача добавлена в Windows!" : "❌ Ошибка при добавлении задачи.";
}
private function isWindowsTaskExists($taskName = null) {
exec("schtasks /Query /TN \"". ($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) ."\" /F", $output, $return_code);
return ($return_code === 0) ? "✅ Задача удалена из Windows!" : "❌ Ошибка при удалении задачи.";
}
private function getWindowsTaskStatus($taskName) {
exec("schtasks /Query /TN \"{$taskName}\" /FO LIST /V", $output, $return_var);
if ($return_var !== 0) {
return "Не работает (задача отсутствует)";
}
$status = "Не работает (ошибка: неизвестно)";
$output = array_map(function($line) {
return iconv('Windows-1251', 'UTF-8', $line);
}, $output);
// Ищем статус задачи
foreach ($output as $line) {
if (strpos($line, "Статус:") !== false) {
if (stripos($line, "Выполняется") !== false) {
$status = "✅ Работает корректно";
} elseif (stripos($line, "Готово") !== false) {
$status = "Не работает (но активна)";
} elseif (stripos($line, "Не удалось запустить") !== false) {
$status = "Не работает (ошибка: не удалось запустить)";
}
break;
}
}
return $status;
}
}
?>

View file

@ -23,5 +23,8 @@
"paquettg/php-html-parser": "^2.2",
"phpmailer/phpmailer": "^6.9",
"beeyev/disposable-email-filter-php": "^1.3"
},
"require-dev": {
"phpstan/phpstan": "*"
}
}

63
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "ec83690d34b55f6ada188bcfc6a299db",
"content-hash": "844a94a4ce9ce290e30dd5845c27ed3f",
"packages": [
{
"name": "aws/aws-crt-php",
@ -2248,7 +2248,66 @@
"time": "2024-04-29T11:44:00+00:00"
}
],
"packages-dev": [],
"packages-dev": [
{
"name": "phpstan/phpstan",
"version": "2.1.5",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "451b17f9665481ee502adc39be987cb71067ece2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/451b17f9665481ee502adc39be987cb71067ece2",
"reference": "451b17f9665481ee502adc39be987cb71067ece2",
"shasum": ""
},
"require": {
"php": "^7.4|^8.0"
},
"conflict": {
"phpstan/phpstan-shim": "*"
},
"bin": [
"phpstan",
"phpstan.phar"
],
"type": "library",
"autoload": {
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "PHPStan - PHP Static Analysis Tool",
"keywords": [
"dev",
"static analysis"
],
"support": {
"docs": "https://phpstan.org/user-guide/getting-started",
"forum": "https://github.com/phpstan/phpstan/discussions",
"issues": "https://github.com/phpstan/phpstan/issues",
"security": "https://github.com/phpstan/phpstan/security/policy",
"source": "https://github.com/phpstan/phpstan-src"
},
"funding": [
{
"url": "https://github.com/ondrejmirtes",
"type": "github"
},
{
"url": "https://github.com/phpstan",
"type": "github"
}
],
"time": "2025-02-13T12:49:56+00:00"
}
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {},

View file

@ -15,6 +15,7 @@ class App
if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/ngallery.yaml')) {
define("NGALLERY", Yaml::parse(file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/ngallery.yaml'))['ngallery']);
define("NGALLERY_TASKS", Yaml::parse(file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/app/Controllers/Exec/Tasks/ngallery-tasks.yaml'))['tasks']);
if (NGALLERY['root']['debug'] === true) {
Debugger::enable();
}

View file

@ -68,3 +68,12 @@ ngallery:
allowgif: true
comments:
premoderation: false
contests:
enabled: true
autonew:
enabled: true
times:
pretendsopen: 'now'
pretendsclose: '2d'
open: 'now'
close: '2d'

View file

@ -1,8 +1,5 @@
-- Migration script to update database schema
-- Drop tables that are no longer needed
-- (No tables to drop as all tables in 111.sql exist in 222.sql)
-- Add new tables from 222.sql that don't exist in 111.sql
CREATE TABLE IF NOT EXISTS `contests` (
`id` int(10) NOT NULL AUTO_INCREMENT,
@ -29,8 +26,8 @@ CREATE TABLE IF NOT EXISTS `servicekeys` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Modify existing tables to add new columns
ALTER TABLE `photos`
ADD COLUMN IF NOT EXISTS `pinnedcomment_id` int(10) NOT NULL DEFAULT 0 AFTER `entitydata_id`;
-- Using proper ALTER TABLE syntax for MySQL
ALTER TABLE `photos` ADD COLUMN `pinnedcomment_id` int(10) NOT NULL DEFAULT 0 AFTER `entitydata_id`;
-- Set AUTO_INCREMENT values for the new tables
ALTER TABLE `contests` AUTO_INCREMENT = 1;

162
sqlcore/sql_0003.sql Normal file
View file

@ -0,0 +1,162 @@
-- Add new tables for contest functionality
CREATE TABLE IF NOT EXISTS `contests_pretends` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`photo_id` int(10) NOT NULL,
`contest_id` int(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `contests_rates` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`photo_id` int(10) NOT NULL,
`user_id` int(10) NOT NULL,
`contest_id` int(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `contests_themes` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`title` text NOT NULL,
`status` int(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `contests_winners` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`photo_id` int(10) NOT NULL,
`place` int(10) NOT NULL,
`contest_id` int(10) NOT NULL,
`date` int(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `photos_rates_contest` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`photo_id` int(10) NOT NULL,
`user_id` int(10) NOT NULL,
`contest_id` int(10) NOT NULL,
`type` int(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Add new pages table
CREATE TABLE IF NOT EXISTS `pages` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`title` text NOT NULL,
`body` text NOT NULL,
`created_by` int(10) NOT NULL,
`created_at` int(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Modify existing tables
-- Update contests table
SET @s = (SELECT IF(
EXISTS(
SELECT * FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'contests'
AND COLUMN_NAME = 'openpretendsdate'
),
'SELECT 1',
'ALTER TABLE `contests` ADD COLUMN `openpretendsdate` int(10) NOT NULL AFTER `themeid`'
));
PREPARE stmt FROM @s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @s = (SELECT IF(
EXISTS(
SELECT * FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'contests'
AND COLUMN_NAME = 'closepretendsdate'
),
'SELECT 1',
'ALTER TABLE `contests` ADD COLUMN `closepretendsdate` int(10) NOT NULL AFTER `openpretendsdate`'
));
PREPARE stmt FROM @s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- Update entities table
ALTER TABLE `entities` MODIFY `createdate` bigint(20) NOT NULL;
-- Update news table
ALTER TABLE `news` MODIFY `body` mediumtext NOT NULL;
-- Update photos table
SET @s = (SELECT IF(
EXISTS(
SELECT * FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'photos'
AND COLUMN_NAME = 'on_contest'
),
'SELECT 1',
'ALTER TABLE `photos` ADD COLUMN `on_contest` int(10) NOT NULL DEFAULT 0 AFTER `pinnedcomment_id`'
));
PREPARE stmt FROM @s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @s = (SELECT IF(
EXISTS(
SELECT * FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'photos'
AND COLUMN_NAME = 'contest_id'
),
'SELECT 1',
'ALTER TABLE `photos` ADD COLUMN `contest_id` int(10) NOT NULL DEFAULT 0 AFTER `on_contest`'
));
PREPARE stmt FROM @s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- Update charset and collation for tables
ALTER TABLE `entities`
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `entities_data`
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `followers`
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `followers_notifications`
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `galleries`
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `news`
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `photos_favorite`
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `photos_views`
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `uploadindex_history`
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `login_tokens`
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `photos`
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `photos_comments`
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `photos_comments_rates`
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `photos_rates`
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `users`
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

View file

@ -371,10 +371,10 @@ table.nospaces > tbody > tr > td.lcol { padding:2px 6px 0; }
.flag-left { padding-left:26px !important; }
.input-flag { margin:-2px -26px 0 5px; position:relative; z-index:11; }
.contestBtn { display:block; cursor:pointer; width:56px; height:28px; margin:10px; background:url('/img/vote_contest.gif') no-repeat; opacity:0.7; }
.contestBtn { display:block; cursor:pointer; width:56px; height:28px; margin:10px; background:url('/static/img/vote_contest.gif') no-repeat; opacity:0.7; }
.contestBtn:hover { opacity:1; }
.contestBtn.voted { opacity:1; background:url('/img/vote_contest_pressed.gif') no-repeat; }
.contestBtn.loading { opacity:1; background:url('/img/vote_contest_loading.gif') no-repeat; }
.contestBtn.voted { opacity:1; background:url('/static/img/vote_contest_pressed.gif') no-repeat; }
.contestBtn.loading { opacity:1; background:url('/static/img/vote_contest_loading.gif') no-repeat; }
.died { border:solid 1px black; padding:0 2px; }

89
static/css/tabs.css Normal file
View file

@ -0,0 +1,89 @@
.v-header {
/**
* Redefine media queries, because header mobile styles are enabled
* when page width is less than two-columns layout width (~960px)
*/
--border-radius: 8px;
--offset-x: var(--island-offset-x, 20px);
--offset-y: 24px;
border-radius: var(--border-radius);
padding: var(--offset-y) var(--offset-x);
font-size: 16px;
line-height: 1.5em;
}
@media (max-width: 999px) {
.v-header {
--offset-x: var(--island-offset-x, 16px);
--offset-y: 16px;
}
}
.v-header__tabs {
margin-bottom: calc(var(--offset-y)* -1);
margin-left: calc(var(--offset-x)* -1);
margin-right: calc(var(--offset-x)* -1);
}
.v-tabs {
--height: 63px;
--nav-size: 36px;
--tab-offset: 12px;
font-size: var(--font-size);
height: var(--height);
position: relative;
min-width: 0;
}
.v-tabs__scroll {
white-space: nowrap;
overflow-x: hidden;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
}
.v-header__tabs .v-tabs__content {
padding-left: var(--offset-x);
padding-right: var(--offset-x);
}
.v-tabs__content {
display: -ms-inline-flexbox;
display: inline-flex;
vertical-align: top;
}
.v-tab:first-child {
padding-left: 0;
}
.v-tab--active {
pointer-events: none;
color: #ffffff;
}
.v-tab {
padding: 0 var(--tab-offset);
-ms-flex-negative: 0;
flex-shrink: 0;
cursor: pointer;
color: #000000;
font-weight: 400;
}
.v-tab--active .v-tab__label {
position: relative;
}
.v-tab__label {
display: -ms-flexbox;
display: flex;
-ms-flex-align: baseline;
align-items: baseline;
height: var(--height);
line-height: calc(var(--height) + 1px);
}
.v-tab--active .v-tab__label::after {
content: '';
width: 100%;
height: 3px;
background-color: #306bff;
position: absolute;
bottom: 0;
left: 0;
border-radius: 500px;
}
.active__block, .active__blockm {
display: block !important;
transition: 0.3s all;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 300 KiB

After

Width:  |  Height:  |  Size: 215 KiB

BIN
static/img/star_people.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 B

BIN
static/img/vote_contest.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
static/img/vs1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 542 B

BIN
static/img/vs2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 B

BIN
static/img/vs3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

39
static/js/changeTab.js Normal file
View file

@ -0,0 +1,39 @@
function changeTab(id) {
const $activeTabs = $('.v-tab-b.v-tab--active');
const $activeBlocks = $('.active__block');
const $newTab = $('#' + id);
if ($activeTabs.length) {
$activeTabs.removeClass('v-tab--active');
}
$newTab.addClass('v-tab--active');
if ($activeBlocks.length) {
$activeBlocks.stop(true, true).animate({
opacity: 0,
}, 200, function () {
$(this).css('display', 'none').removeClass('active__block');
const $newBlock = $('#' + id + '__block');
$newBlock.css({
display: 'block',
opacity: 0
}).animate({
opacity: 1
}, 150, function () {
$(this).addClass('active__block');
});
});
} else {
// Если нет активных блоков, сразу показываем новый блок
$('#' + id + '__block').css({
display: 'block',
opacity: 0
}).animate({
opacity: 1
}, 150, function () {
$(this).addClass('active__block');
});
}
}

View file

@ -183,7 +183,42 @@ function LoadRecentPhotos()
.fail(function(jx) { if (jx.responseText != '') console.log(jx.responseText); });
}
function startCountdown(unixTimestamp) {
function padZero(num) {
return num < 10 ? '0' + num : num;
}
function getWord(num, words) {
if (num % 10 === 1 && num % 100 !== 11) return words[0];
if (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20)) return words[1];
return words[2];
}
function updateTimer() {
const now = Math.floor(Date.now() / 1000);
const diff = unixTimestamp - now;
if (diff <= 0) {
clearInterval(interval);
document.getElementById('countdown').textContent = "00 дней 00 часов 00 минут 00 секунд";
return;
}
const days = Math.floor(diff / 86400);
const hours = Math.floor((diff % 86400) / 3600);
const minutes = Math.floor((diff % 3600) / 60);
const seconds = diff % 60;
document.getElementById('countdown').textContent =
`${padZero(days)} ${getWord(days, ['день', 'дня', 'дней'])} ` +
`${padZero(hours)} ${getWord(hours, ['час', 'часа', 'часов'])} ` +
`${padZero(minutes)} ${getWord(minutes, ['минута', 'минуты', 'минут'])} ` +
`${padZero(seconds)} ${getWord(seconds, ['секунда', 'секунды', 'секунд'])}`;
}
updateTimer(); // сразу обновляем отображение
const interval = setInterval(updateTimer, 1000);
}
function LoadPubPhotos()
{

View file

@ -87,9 +87,8 @@ $(document).ready(function()
}
$('#votes').html(html)[html == '' ? 'hide' : 'show']();
$('.vote_btn[vote="1"]')[data.buttons[1] ? 'addClass' : 'removeClass']('voted');
$('.vote_btn[vote="0"]')[data.buttons[0] ? 'addClass' : 'removeClass']('voted');
$('.vote[pid="' + pid + '"][vote="1"]')[data.buttons.posbtn ? 'addClass' : 'removeClass']('voted');
$('.vote[pid="' + pid + '"][vote="0"]')[data.buttons.negbtn ? 'addClass' : 'removeClass']('voted')
var rating = parseInt(data.rating);
if (rating > 0) $('#rating').html('+' + rating); else
@ -119,7 +118,7 @@ $(document).ready(function()
if (vote != 0 && vote != 1 || $(this).is('.locked')) return false;
var pid = $(this).closest('.vote').attr('pid');
var cid = $(this).closest('.vote').attr('cid');
var savedClass1 = $('.vote[pid="' + pid + '"] .konk_btn[vote="1"]').attr('class');
var savedClass0 = $('.vote[pid="' + pid + '"] .konk_btn[vote="0"]').attr('class');
@ -127,19 +126,19 @@ $(document).ready(function()
$(this).toggleClass('voted');
if ($(this).is('.voted')) $('.vote[pid="' + pid + '"] .konk_btn[vote="' + Number(!Number(vote)) + '"]').removeClass('voted');
var self_p = 0;
if (!self_p) // Чужие фото
{
$(this).closest('.p20p').removeAttr('class').css('padding', '6px 6px 5px');
$.getJSON('/api.php', { action: 'vote-konk', pid: pid, vote: vote }, function (data)
$.getJSON('/api/photo/vote', { action: 'vote-konk', pid: pid, vote: vote, cid: cid }, function (data)
{
if (data && !data.errors)
{
$('.star[pid="' + pid + '"]').html(data.star ? '<img src="/img/star_' + data.star + '.png" alt="" />' : '');
$('.vote[pid="' + pid + '"] .konk_btn[vote="1"]')[data.buttons.posbtn_contest ? 'addClass' : 'removeClass']('voted');
$('.vote[pid="' + pid + '"] .konk_btn[vote="0"]')[data.buttons.negbtn_contest ? 'addClass' : 'removeClass']('voted');
$('.vote[pid="' + pid + '"] .konk_btn[vote="1"]')[data.buttons[1] ? 'addClass' : 'removeClass']('voted');
$('.vote[pid="' + pid + '"] .konk_btn[vote="0"]')[data.buttons[0] ? 'addClass' : 'removeClass']('voted');
var rat = $('.s_rating[pid="' + pid + '"]');
if (rat.length)
@ -164,14 +163,14 @@ $(document).ready(function()
}
else // Свои фото
{
$.getJSON('/api.php', { action: 'vote-author', pid: pid, vote: vote }, function (data)
$.getJSON('/api/photo/vote', { action: 'vote-author', pid: pid, vote: vote }, function (data)
{
if (data && !data.errors)
{
$('#star[pid="' + pid + '"]').html(data.star ? '<img src="/img/star_' + data.star + '.png" alt="" />' : '');
$('.konk_btn[vote="1"]')[data.buttons[1] ? 'addClass' : 'removeClass']('voted');
$('.konk_btn[vote="0"]')[data.buttons[0] ? 'addClass' : 'removeClass']('voted');
$('.vote[pid="' + pid + '"] .konk_btn[vote="1"]')[data.buttons.posbtn_contest ? 'addClass' : 'removeClass']('voted');
$('.vote[pid="' + pid + '"] .konk_btn[vote="0"]')[data.buttons.negbtn_contest ? 'addClass' : 'removeClass']('voted');
}
else
{

View file

@ -15,11 +15,13 @@ body {
}
</style>
<script src="/static/js/changeTab.js" defer></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/boxicons@latest/css/boxicons.min.css">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.5/dist/umd/popper.min.js" integrity="sha384-Xe+8cL9oJa6tN/veChSP7q+mnSPaj5Bcu9mPX5F5xIGE0DVittaqT5lorf0EI7Vk" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.min.js" integrity="sha384-ODmDIVzN+pFdexxHEHFBQH3/9/vQ9uori45z4JjnFsRydbmQbmL5t1tQ0culUzyK" crossorigin="anonymous"></script>
<link rel="stylesheet" href="/static/css/header.admin.css">
<link rel="stylesheet" href="/static/css/tabs.css">
<div class="layout__left-column layout__sticky">
<header style="background-color: #0d1012;" class="header">
<div class="header__container">
@ -66,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>
@ -82,10 +84,14 @@ body {
<i class="bx bx-world nav__icon"></i>
<span class="nav__name">GeoDB<span class="badge text-bg-warning">BETA</span></span>
</a>
<!--a href="/admin?type=Settings" class="nav__link">
<!--a href="/admin?type=Pages" class="nav__link">
<i class="bx bx-file-blank nav__icon"></i>
<span class="nav__name">Страницы</span>
</!--a-->
<a href="/admin?type=Settings" class="nav__link">
<i class="bx bx-cog nav__icon"></i>
<span class="nav__name">Настройки<span class="badge text-bg-warning">BETA</span></span>
<-->
</a>
</div>

View file

@ -51,7 +51,7 @@ if (NGALLERY['root']['registration']['emailverify'] === true && $user->i('status
</ul>
</div>
</li>
<li><a href="/comments.php" class="mm-item"><span class="mm-label">Комментарии</span></a></li>
<li><a href="/comments" class="mm-item"><span class="mm-label">Комментарии</span></a></li>
<li><a href="#" onclick="return false" class="mm-item"><span class="mm-label">Обновления</span><?=$nonrw?></a>
<div>
<ul class="mm-level-2">
@ -112,7 +112,7 @@ if (NGALLERY['root']['registration']['emailverify'] === true && $user->i('status
<?php } ?>
<li><a href="/lk/history" class="mm-item"><span class="mm-icon"><i class="fas fa-sm fa-fw fa-images"></i></span><span class="mm-label">Журнал</span></a></li>
<li><a href="/lk/konkurs.php" class="mm-item"><span class="mm-icon"><i class="fas fa-sm fa-fw fa-compass"></i></span><span class="mm-label">Конкурс</span></a></li>
<li><a href="/lk/vehicles.php" class="mm-item"><span class="mm-icon"><i class="fas fa-sm fa-fw fa-folder-plus"></i></span><span class="mm-label"><b>Правка БД</b></span></a></li>
<li><a href="/vehicle/edit" class="mm-item"><span class="mm-icon"><i class="fas fa-sm fa-fw fa-folder-plus"></i></span><span class="mm-label"><b>Правка БД</b></span></a></li>
<li><a href="/lk/ticket.php" class="mm-item"><span class="mm-icon"><i class="fas fa-sm fa-fw fa-question-circle"></i></span><span class="mm-label">Мои заявки</span></a></li>
<li><a href="/lk/profile" class="mm-item"><span class="mm-icon"><i class="fas fa-sm fa-fw fa-cog"></i></span><span class="mm-label">Настройки профиля</span></a></li>
<li><a href="/search?id=<?=Auth::userid()?>" class="mm-item"><span class="mm-icon"><i class="far fa-sm fa-fw fa-images"></i></span><span class="mm-label">Мои фотографии</span></a></li>

View file

@ -0,0 +1,260 @@
<?php
use \App\Services\{Auth, DB, Date, TaskScheduler};
use \App\Models\User;
$task = new TaskScheduler();
$contestCreate = true;
if (!$task->isTaskExists("ExecContests", "php ".$_SERVER['DOCUMENT_ROOT'].$task->findHandlerById(NGALLERY_TASKS, 'ExecContests'))) {
$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
if ($contestCreate === false) {
echo "<div class='alert alert-warning mt-3' role='alert'>У вас не добавлена задача на проведение конкурсов. Без неё, сервер не сможет завершать конкурс и проводить новый автоматически.<a href='/admin?type=Settings' type='button' style='margin-left: 5px;' class='btn btn-sm btn-outline-dark'>Включить</a></div>";
}
?>
<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'] === 02) {
$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">
<?php
$themes = DB::query('SELECT * FROM contests_themes');
foreach ($themes as $t) {
echo '<option value="'.$t['id'].'">'.$t['title'].'</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>

View file

@ -0,0 +1,151 @@
<script>
function submitUpload() {
$('#buttonUpload').html('<button style="border-radius: 10px 0px 0px 10px !important;" type="submit" id="createpost" class="btn btn-primary mb-3 mt-3" disabled><span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Загружаем...</button>');
$('#buttonUploadModal').html('<button type="submit" id="createpost" class="btn btn-primary" disabled><span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Загружаем...</button>');
$('#buttonPreView').html('<button style="border-radius: 0px 10px 10px 0px !important;" type="submit" id="createpost" class="btn btn-primarynew mb-3 mt-3" disabled>Предпросмотр</button>');
$.ajax({
type: "POST",
url: '/exapi/dialogs/create',
data: JSON.stringify( { "bodypost":$("#bodypost").val(), "title": $("#title").val(), "did": '00000' } ),
dataType: "json",
success: function(response) {
var jsonData = JSON.parse(JSON.stringify(response));
console.log(jsonData);
if (jsonData.errorcode == "1") {
$('#buttonUpload').html('<button href="#" data-bs-toggle="modal" data-bs-target="#createDialogModal" style="border-radius: 10px 0px 0px 10px !important;" type="submit" id="createpost" class="btn btn-primary mb-3 mt-3">Опубликовать</button>');
$('#buttonPreView').html('<button onclick="submitPreview()" style="border-radius: 0px 10px 10px 0px !important;" type="submit" id="createpost" class="btn btn-primarynew mb-3 mt-3">Предпросмотр</button>');
$('#buttonUploadModal').html('<button onclick="submitUpload()"type="submit" class="btn btn-primary">Да, я уверен</button>');
Notify.noty('danger', 'Мало контента!');
} else {
$('#buttonUpload').html('<button href="#" data-bs-toggle="modal" data-bs-target="#createDialogModal" style="border-radius: 10px 0px 0px 10px !important;" type="submit" id="createpost" class="btn btn-primary mb-3 mt-3">Опубликовать</button>');
$('#buttonPreView').html('<button onclick="submitPreview()" style="border-radius: 0px 10px 10px 0px !important;" type="submit" id="createpost" class="btn btn-primarynew mb-3 mt-3">Предпросмотр</button>');
$('#buttonUploadModal').html('<button onclick="submitUpload()"type="submit" class="btn btn-primary">Да, я уверен</button>');
window.location.replace("/dialogs/<?=$id_dialog?>/topic/<?=$id_topic?>/post/"+jsonData.id);
}
}
});
}
function submitPreview() {
$('#buttonUpload').html('<button style="border-radius: 10px 0px 0px 10px !important;" type="submit" id="createpost" class="btn btn-primary mb-3 mt-3" disabled>Опубликовать</button>');
$('#buttonPreView').html('<button style="border-radius: 0px 10px 10px 0px !important;" type="submit" id="createpost" class="btn btn-primarynew mb-3 mt-3" disabled><span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Загружаем...</button>');
$.ajax({
type: "POST",
url: '/exapi/dialogs/createPreview',
data: JSON.stringify( { "bodypost":$("#bodypost").val(), "title": $("#title").val() } ),
dataType: "json",
success: function(response) {
var jsonData = JSON.parse(JSON.stringify(response));
console.log(response);
console.log(jsonData);
if (jsonData.errorcode == "1") {
$('#buttonUpload').html('<button href="#" data-bs-toggle="modal" data-bs-target="#createDialogModal" style="border-radius: 10px 0px 0px 10px !important;" type="submit" id="createpost" class="btn btn-primary mb-3 mt-3">Опубликовать</button>');
$('#buttonPreView').html('<button onclick="submitPreview()" style="border-radius: 0px 10px 10px 0px !important;" type="submit" id="createpost" class="btn btn-primarynew mb-3 mt-3">Предпросмотр</button>');
$("#result").html("<div class='alert alert-dangernew container' role='alert'>Может, что-нибудь напишите в свой пост?</div>");
} else {
$('#buttonUpload').html('<button href="#" data-bs-toggle="modal" data-bs-target="#createDialogModal" style="border-radius: 10px 0px 0px 10px !important;" type="submit" id="createpost" class="btn btn-primary mb-3 mt-3">Опубликовать</button>');
$('#buttonPreView').html('<button onclick="submitPreview()" style="border-radius: 0px 10px 10px 0px !important;" type="submit" id="createpost" class="btn btn-primarynew mb-3 mt-3">Предпросмотр</button>');
window.open('/dialogs/preview?id='+jsonData.preid, '_blank');
}
}
});
}
</script>
<div class="mb-3">
<label for="exampleFormControlInput1" class="form-label">Заголовок</label>
<input name="title" id="title" type="text" class="form-control" id="exampleFormControlInput1">
</div>
<div class="col-md-auto d-flex align-items-center">
<button onclick="document.getElementById('bodypost').value += '[b] [/b]';" type="button" class="btn btn-primary btn-sm mb-2" style="margin-right: 6px;"><i class="bx bx-bold"></i></button>
<button onclick="document.getElementById('bodypost').value += '[i] [/i]';" type="button" class="btn btn-primary btn-sm mb-2" style="margin-right: 6px;"><i class="bx bx-italic"></i></button>
<button onclick="document.getElementById('bodypost').value += '[u] [/u]';" type="button" class="btn btn-primary btn-sm mb-2" style="margin-right: 6px;"><i class="bx bx-underline"></i></button>
<button onclick="document.getElementById('bodypost').value += '[s] [/s]';" type="button" class="btn btn-primary btn-sm mb-2" style="margin-right: 6px;"><i class="bx bx-strikethrough"></i></button>
<button onclick="document.getElementById('bodypost').value += '[link=] [/link]';" type="button" class="btn btn-primary btn-sm mb-2" style="margin-right: 36px;"><i class="bx bx-link"></i></button>
<button href="#" data-bs-toggle="modal" data-bs-target="#pickImageModal" type="button" class="btn btn-primary btn-sm mb-2" style="margin-right: 6px;"><i class="bx bx-image-alt"></i></button>
<button href="#" data-bs-toggle="modal" data-bs-target="#pickVideoModal" type="button" class="btn btn-primary btn-sm mb-2" style="margin-right: 6px;"><i class="bx bx-video"></i></button>
<button href="#" data-bs-toggle="modal" data-bs-target="#pickMusicModal" type="button" class="btn btn-primary btn-sm mb-2" style="margin-right: 6px;"><i class="bx bx-music"></i></button>
</div>
<textarea id="bodypost" class="form-control" name="bodypost" placeholder="Вы можете написать свою историю" cols="30" rows="10"></textarea>
<div class="btn-group" role="group" aria-label="Basic example">
<div id="buttonUpload">
<button href="#" data-bs-toggle="modal" data-bs-target="#createDialogModal" style="border-radius: 10px 0px 0px 10px !important;" type="submit" id="createpost" class="btn btn-primary mb-3 mt-3">Опубликовать</button>
</div>
<div id="buttonPreView">
<button onclick="submitPreview()" style="border-radius: 0px 10px 10px 0px !important;" type="submit" id="createpost" class="btn btn-outline-primary mb-3 mt-3">Предпросмотр</button>
</div>
</div>
</form>
<div class="modal fade" id="pickImageModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Прикрепление фотографии</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form enctype="multipart/form-data" id="pickImageForm">
<div class="modal-body">
<div class="mb-3">
<input id="filebody" type="file" name="filebodyImage" class="form-control" type="file">
</div>
</div>
<div class="modal-footer">
<div><button type="button" class="btn-r btn-secondary" data-bs-dismiss="modal">Отмена</button></div>
<div id="r"><button id="t" type="submit" class="btn btn-primary" data-bs-dismiss="modal">Прикрепить</button></div>
</div>
</form>
</div>
</div>
</div>
<div class="modal fade" id="pickMusicModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Прикрепление музыки</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<input id="filebody" type="file" name="filebody" class="form-control" type="file">
</div>
</div>
<div class="modal-footer">
<div><button type="button" class="btn-r btn-secondary" data-bs-dismiss="modal">Отмена</button></div>
<div id="r"><button id="t" type="submit" class="btn btn-primary">Прикрепить</button></div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="pickVideoModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Прикрепление видео</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form enctype="multipart/form-data" id="pickVideoForm">
<div class="modal-body">
<div class="mb-3">
<input id="filebody" type="file" name="filebodyVideo" class="form-control" type="file">
</div>
</div>
<div class="modal-footer">
<div><button type="button" class="btn-r btn-secondary" data-bs-dismiss="modal">Отмена</button></div>
<div id="r"><button id="t" type="submit" class="btn btn-primary" data-bs-dismiss="modal">Прикрепить</button></div>
</div>
</form>
</div>
</div>
</div>

View file

@ -0,0 +1,19 @@
<?php
use \App\Services\{Auth, DB, Date};
use \App\Models\User;
?>
<h1><b>Страницы</b></h1>
<a href="?type=PageCreate" class="btn btn-primary mb-3">Создать</a>
<div id="pages">
<?php
$pages = DB::query('SELECT * FROM pages ORDER BY id');
foreach ($pages as $p) {
echo '<div class="card mb-3"><div class="card-body">' . Date::zmdate($n['time']) . '<br>' . $n['body'] . '</div></div>';
}
?>
</div>

View file

@ -36,9 +36,25 @@ use \App\Models\User;
</style>
<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('full')" id="full" class="v-tab v-tab-b"><span class="v-tab__label">
Полный список
</span></!--a--><a href="#" onclick="changeTab('moderate')" id="moderate" class="v-tab v-tab-b v-tab--active"><span class="v-tab__label">
Ожидают модерации
</span></a>
</div>
</div>
</div>
</div>
<script src="/js/diff.js"></script>
<script src="/js/pwrite-compare.js"></script>
<br clear="all"><br>
<div id="moderate__block"class="active__block" >
<div class="p20w" style="display:block">
<table class="table">
<tbody>
@ -202,7 +218,10 @@ use \App\Models\User;
</tbody>
</table>
</div><br>
</div></div>
<div style="display: none;" id="full__block">
fgdfg
</div>
</td>
</tr>

View file

@ -1,12 +1,14 @@
<?php
use \App\Services\{KeyTranslation};
use \App\Services\{KeyTranslation, TaskScheduler};
use \App\Models\User;
use Symfony\Component\Yaml\Yaml;
$yamlFile = $_SERVER['DOCUMENT_ROOT'].'/ngallery.yaml';
function renderInputs($data, $prefix = '') {
$task = new TaskScheduler();
$yamlFile = $_SERVER['DOCUMENT_ROOT'] . '/ngallery.yaml';
function renderInputs($data, $prefix = '')
{
foreach ($data as $key => $value) {
$name = $prefix ? "{$prefix}[{$key}]" : $key;
$key = KeyTranslation::key($key);
@ -79,29 +81,91 @@ function renderInputs($data, $prefix = '') {
<?= \App\Controllers\AdminController::loadMenu(); ?>
<?= \App\Controllers\AdminController::loadContent(); ?>
<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('config')" id="config" class="v-tab v-tab-b v-tab--active"><span class="v-tab__label">
Конфиг сервера
</span></!--a--><a href="#" onclick="changeTab('tasks')" id="tasks" class="v-tab v-tab-b v-tab--active"><span class="v-tab__label">
Задачи
</span></a>
</div>
</div>
</div>
</div>
<div id="config__block" style="display: none;" >
<div class="alert alert-warning" role="alert">
Изменяйте только на свой страх и риск.
</div>
Изменяйте только на свой страх и риск.
</div>
<div class="p20w" style="display:block">
<?php
// Вывод формы
echo '<form method="post">';
<?php
// Вывод формы
echo '<form method="post">';
foreach (NGALLERY as $ng) {
renderInputs($ng);
}
echo '<button type="submit">Сохранить</button>';
echo '</form>';
?>
echo '<button type="submit">Сохранить</button>';
echo '</form>';
?>
</div><br>
</div>
<div class="active__block"id="tasks__block">
<table class="table">
<tbody>
<tr>
<th width="100">ID</th>
<th width="50%">Статус</th>
<th>Действия</th>
</tr>
<?php
foreach (NGALLERY_TASKS as $nt) {
$nt = $nt;
echo '<tr><td>
'.$nt['id'].'
</td><td>
'.$task->getTaskStatus($nt['id'], "php {$nt['handler']}").'
</td><td class="c">
<a onclick="taskManager(`'.$nt['id'].'`, 1)" class="btn btn-sm btn-primary">Запустить</a> <a onclick="taskManager(`'.$nt['id'].'`, 0)" class="btn btn-sm btn-danger">Остановить</a>
</td> <tr>';
}
?>
</tbody>
</table>
</div>
</div>
</body>
<script>
function taskManager(id, type) {
$.ajax({
type: "GET",
url: '/api/admin/settings/taskmanager?id='+id+'&type='+type,
success: function(response) {
Notify.noty('success', 'OK!');
}
});
}
</script>
</html>

View file

@ -0,0 +1,167 @@
<?php
use \App\Services\{Auth, DB, Date};
use \App\Models\{User, Photo, Vote};
?>
<!DOCTYPE html>
<html lang="ru">
<head>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/LoadHead.php'); ?>
</head>
<body>
<div id="backgr"></div>
<table class="tmain">
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Navbar.php'); ?>
<tr>
<td class="main">
<h1>Лента комментариев</h1>
<script src="/js/jquery-ui.js?1633005526"></script>
<script src="/js/selector.js?1730197663"></script>
<script>
$(document).ready(function() {
$('#cname').citySelector('cid', {
defaultLabel: 'Все города'
});
$('#type').val(0).change(function() {
$(this).attr('class', $('option:selected', this).attr('class'));
}).change();
$('#applyFilter').on('click', function() {
var cid = $('#cid').val();
var type = $('#type').val();
var redir = '/comments.php';
if (cid > 0 || type > 0) {
redir = redir + '?';
if (cid > 0) {
redir = redir + 'cid=' + cid;
if (type > 0) redir = redir + '&';
}
if (type > 0) redir = redir + 't=' + type;
}
window.location.href = redir;
});
});
</script>
<div id="upd_anchor"></div>
<?php
$comments = DB::query('SELECT * FROM photos_comments ORDER BY id DESC LIMIT 30');
foreach ($comments as $c) {
$user = new User($c['user_id']);
$content = json_decode($c['content'], true);
$photo = new Photo($c['photo_id']);
if ($user->i('admin') === 1) {
$admintype = ' · Администратор сервера';
} else if ($user->i('admin') === 2) {
$admintype = ' · Фотомодератор';
}
if ((int)Vote::countcommrates($c['id'], -1) >= 1) {
$commclass = 'pro';
$symb = '+';
} else if ((int)Vote::countcommrates($c['id'], -1) < 0) {
$commclass = 'con';
$symb = '';
} else if ((int)Vote::countcommrates($c['id'], -1) === 0) {
$commclass = '';
}
echo '<div class="p-comment p20p">
<div class="pc-photo"><a href="/photo/'.$c['photo_id'].'/?top=1" target="_blank" class="prw"><img src="/api/photo/compress?url='.$photo->i('photourl').'" class="f"></a></div>
<div class="pc-content">
<a class="pc-topost" href="/photo/'.$c['photo_id'].'/?top=1#' . $c['id'] . '" target="_blank">Ссылка</a>
<div class="pc-text">
<div><span class="cmt-aname">
<b><a href="/author/'.$c['user_id'].'/">'.$user->i('username').'</a></b></span> &middot; <span class="sm nw">'.Date::zmdate($c['posted_at']).'</span>
<div class="rank">Фото: '.Photo::fetchAll($c['user_id']).''.$admintype.'</div>
<div class="message-text feed">'.$c['body'].'</div>
</div>
</div>
<div class="pc-compl">
<div class="comment-votes-block">
<div class="wvote" wid="' . $c['id'] . '">
<a href="#" vote="1" class="w-btn s2"><span>+</span></a>
<div class="w-rating '.$commclass.' active">' . $symb . Vote::countcommrates($c['id'], -1) . '</div>
<div class="w-rating-ext">
<div><span class="pro">+' . Vote::countcommrates($c['id'], 1) . '</span> / <span class="con">' . Vote::countcommrates($c['id'], 0) . '</span></div>
</div>
<a href="#" vote="0" class="w-btn s5"><span></span></a>
</div>
</div>
</div>
</div>
</div>';
}
?>
<div id="scroll_anchor"></div>
<script src="/js/endless.js?031021"></script>
<script>
var ltime = 1739362440;
var last_k = 20;
var st = 20;
var cnt = -1;
var ajaxQuery = '/comments.php?ajax=1&cnt=-1';
</script>
<script>
var ftime = 1739367547;
function markAllRead(force) {
if (confirm('Вы действительно хотите отметить эти комментарии как прочитанные?')) {
var ts = force ? 0 : ltime + 1;
window.location.href = '?markread=' + ts;
}
return false;
}
var k = 20;
var new_cnt = 0;
function updateTitle() {
document.title = (new_cnt ? '(' + new_cnt + ') ' : '') + $('h1').text();
}
var updateInterval = setInterval(function() {
$.get('/comments.php?ajax=1&upd=1', {
ltime: ftime
}, function(r) {
if (!r) return;
if (r == 'logout') {
clearInterval(updateInterval);
document.location.href = '/login.php';
return;
}
if ($(window).scrollTop() > 100) {
var diff = $(document).height();
var wrapper = $('<div id="wrapper" style="display:none">' + r + '</div>').insertAfter('#upd_anchor');
$(window).scrollTop($(window).scrollTop() + wrapper.height());
wrapper.show();
wrapper.children().eq(0).unwrap();
} else $('#upd_anchor').after(r);
}, 'html');
}, 30000);
</script>
<div id="loader-anchor"></div>
</td>
</tr>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Footer.php'); ?>
</table>
</body>
</html>

View file

@ -1,7 +1,7 @@
<?php
use \App\Services\{Auth, DB, Date};
use \App\Models\User;
use \App\Models\{User};
?>
<!DOCTYPE html>
@ -18,60 +18,169 @@ use \App\Models\User;
<div id="backgr"></div>
<table class="tmain">
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Navbar.php'); ?>
<script>
var kid = <?=DB::query('SELECT id FROM contests WHERE status=2')[0]['id']?>;
var tipTimeout = null;
function hideTip()
{
$('#tip').fadeOut('fast', function()
{
$(this).attr('lock', 0);
$('#img').html('');
});
}
$(document).ready(function()
{
$('.contestBtn').click(function()
{
var pid = $(this).attr('pid');
var savedClass = $(this).attr('class');
$(this).addClass('loading');
$.getJSON('/api/photo/contests/rate', { action: 'vote-contest', kid: kid, pid: pid }, function (data)
{
if (data[0])
{
for (var pid in data[0])
$('.contestBtn[pid="' + pid + '"]').attr('class', 'contestBtn' + (data[0][pid] == 0 ? '' : ' voted'));
}
else $('.contestBtn[pid="' + pid + '"]').attr('class', savedClass);
if (data[1]) alert(data[1]);
})
.fail(function(jx) { alert(jx.responseText); });
return false;
});
$(document).on('mouseenter', '.f', function()
{
var hidden_img = $(this).closest('.p20p').prev('img');
$('#img').html('<a href="/photo/' + hidden_img.attr('pid') + '/" target="_blank"><img src="' + (hidden_img.length ? hidden_img.attr('src') : this.src.replace('_s', '')) + '"></a>');
$('#tip').css('top', $(window).scrollTop() + 20).show();
})
.on('mouseenter', '.f, #tip', function()
{
clearTimeout(tipTimeout);
var lock = Math.min(parseInt($('#tip').attr('lock')) + 1, 2);
$('#tip').attr('lock', lock);
})
.on('mouseleave', '.f, #tip', function()
{
var lock = Math.max(parseInt($('#tip').attr('lock')) - 1, 0);
$('#tip').attr('lock', lock);
tipTimeout = setTimeout(function() { if ($('#tip').attr('lock') == 0) hideTip(); }, 100);
})
.on('mousemove', '.f, #tip', function(e)
{
if (e.pageX > $(document).width() * 0.5) hideTip();
});
});
</script>
<tr>
<td class="main">
<center>
<h1>Фотоконкурс</h1>
<p class="narrow" style="font-size:19px"><b>Голосование</b> &nbsp;&middot;&nbsp; <a href="?show=results">Победители</a> &nbsp;&middot;&nbsp; <a href="?show=rating">Рейтинг</a> &nbsp;&middot;&nbsp; <a href="?show=waiting">Претенденты</a></p>
<p class="narrow" style="font-size:19px"><b>Голосование</b> &nbsp;&middot;&nbsp; <a href="/voting/results">Победители</a> &nbsp;&middot;&nbsp; <a href="/voting/rating">Рейтинг</a> &nbsp;&middot;&nbsp; <a href="/voting/waiting">Претенденты</a></p>
<div style="margin-top:20px">Чтобы проголосовать, отметьте одну, две или три фотографии, которые Вам понравились</div><br><br>
<div class="p20">
<?php
if (DB::query('SELECT status FROM contests WHERE status=2')[0]['status'] != 2) {
$contest = DB::query('SELECT * FROM contests WHERE status=1')[0];
echo '<div class="p20">
<h4>Сейчас конкурс не проводится. Пожалуйста, заходите позже.</h4>
</div>
<h2>Следующий Фотоконкурс будет через:</h2>
<h1 id="countdown"></h1>
<br>
<script>startCountdown(' . $contest['openpretendsdate'] . ');</script>
<h2>Следующий Фотоконкурс будет через:</h2>
<h1 id="countdown"></h1>';
} else { ?>
<div id="tip" lock="0"><span id="img"></span></div>
<?php
$contest = DB::query('SELECT * FROM contests WHERE status=2')[0];
$photos_contest = DB::query('SELECT * FROM photos WHERE on_contest=2 AND contest_id=:id', array(':id'=>$contest['id']));
foreach ($photos_contest as $pc) {
$user = new User($pc['user_id']);
$class = '';
if ((int)DB::query('SELECT photo_id FROM contests_rates WHERE photo_id=:pid AND user_id=:uid AND contest_id=:cid', array(':uid' => Auth::userid(), ':pid' => $pc['id'], ':cid' => $contest['id']))[0]['photo_id'] === (int)$pc['id']) {
$class = ' voted';
}
echo '<img pid="'.$pc['id'].'" src="'.$pc['photourl'].'" style="display:none">
<div class="p20p">
<table>
<tr>
<td><a href="#" pid="'.$pc['id'].'" class="contestBtn'.$class.'"></a></td>
<td class="pb_photo" id="p2068176"><a href="/photo/'.$pc['id'].'/" target="_blank" class="prw"><img class="f" src="/api/photo/compress?url='.$pc['photourl'].'" data-src="/api/photo/compress?url='.$pc['photourl'].'" alt="630 КБ">
<div class="hpshade">
<div class="eye-icon">'.DB::query('SELECT COUNT(*) FROM photos_views WHERE photo_id=:id', array(':id'=>$pc['id']))[0]['COUNT(*)'].'</div>
</div>
</a></td>
<td class="pb_descr">
<p>'.htmlspecialchars($pc['postbody']).'</p>
<p><b class="pw-place">'.htmlspecialchars($pc['place']).'</b></p>
<p class="sm"><b>'.Date::zmdate($pc['posted_at']).'</b><br>Автор: <a href="/author/'.$pc['user_id'].'/">'.$user->i('username').'</a></p>
</td>
</tr>
</table>
</div>';
}
?>
<br>Число проголосовавших: <b><?=DB::query('SELECT COUNT(DISTINCT user_id) AS unique_user_count FROM contests_rates WHERE contest_id=:id', array(':id'=>$contest['id']))[0]['unique_user_count']?></b><br>Число голосов: <b><?=DB::query('SELECT COUNT(*) FROM contests_rates WHERE contest_id=:id', array(':id'=>$contest['id']))[0]['COUNT(*)']?></b><br><br>
</center>
</td>
</tr>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Footer.php'); ?>
<?php }
?>
<br>
</center>
</td>
</tr>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Footer.php'); ?>
</tr>
</tr>
</table>
<script>
// Установите дату и время, до которого нужно отсчитывать
const countdownDate = new Date("Mar 1, 2025 00:00:00").getTime();
// Установите дату и время, до которого нужно отсчитывать
const countdownDate = new Date("Mar 1, 2025 00:00:00").getTime();
// Обновляем отсчет каждую секунду
const x = setInterval(function() {
// Обновляем отсчет каждую секунду
const x = setInterval(function() {
// Получаем текущее время
const now = new Date().getTime();
// Получаем текущее время
const now = new Date().getTime();
// Вычисляем разницу между целевой датой и текущим временем
const distance = countdownDate - now;
// Вычисляем разницу между целевой датой и текущим временем
const distance = countdownDate - now;
// Вычисляем дни, часы, минуты и секунды
const days = Math.floor(distance / (1000 * 60 * 60 * 24));
const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
// Вычисляем дни, часы, минуты и секунды
const days = Math.floor(distance / (1000 * 60 * 60 * 24));
const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
// Отображаем результат в элементе с id "countdown"
document.getElementById("countdown").innerHTML =
days + ":" + hours + ":" + minutes + ":" + seconds;
// Отображаем результат в элементе с id "countdown"
document.getElementById("countdown").innerHTML =
days + ":" + hours + ":" + minutes + ":" + seconds;
// Если отсчет завершен, выводим сообщение
if (distance < 0) {
clearInterval(x);
document.getElementById("countdown").innerHTML = "Время истекло!";
}
}, 1000);
</script>
// Если отсчет завершен, выводим сообщение
if (distance < 0) {
clearInterval(x);
document.getElementById("countdown").innerHTML = "Время истекло!";
}
}, 1000);
</script>
</body>
</html>

View file

@ -1,7 +1,7 @@
<?php
use \App\Services\{Auth, DB, Date};
use \App\Models\User;
use \App\Models\{User, Photo};
?>
<!DOCTYPE html>
@ -18,94 +18,57 @@ use \App\Models\User;
<div id="backgr"></div>
<table class="tmain">
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Navbar.php'); ?>
<?php
?>
<tr>
<td class="main">
<center>
<h1>Победители фотоконкурса</h1>
<p class="narrow" style="font-size:19px"><a href="/voting.php">Голосование</a> &nbsp;&middot;&nbsp; <b>Победители</b> &nbsp;&middot;&nbsp; <a href="?show=rating">Рейтинг</a> &nbsp;&middot;&nbsp; <a href="?show=waiting">Претенденты</a></p>
<div style="margin:20px">Для вывода подробного отчёта о конкурсе нажмите на интересующую вас дату.</div>
<div class="pages"><span class="pg">&laquo;&laquo;</span><span class="ps">1</span><a href="?show=results&amp;st=10" class="pg">2</a><a href="?show=results&amp;st=20" class="pg">3</a><a href="?show=results&amp;st=30" class="pg">4</a> &middot;&middot;&middot; <a href="?show=results&amp;st=2090" class="pg">210</a><a href="?show=results&amp;st=10" class="pg" id="NextLink">&raquo;&raquo;</a></div>
<p><span class="narrow" style="font-size:21px"><b><a href="?show=table&amp;date=2025-02-04" title="Подробный отчёт о конкурсе">04.02.2025</a></b></span><br><span class="sm">Линии и пейзажи</span></p>
<table>
<tr>
<a href="/photo/2066028/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/66/02/2066028_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs3.png" style="position:relative; top:-2px"> &nbsp;</a>
<a href="/photo/2065380/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/65/38/2065380_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs2.png" style="position:relative; top:-2px"> &nbsp;</a>
<a href="/photo/2064449/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/64/44/2064449_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs1.png" style="position:relative; top:-2px"> &nbsp;</a>
</tr>
</table><br>
<p><span class="narrow" style="font-size:21px"><b><a href="?show=table&amp;date=2025-02-03" title="Подробный отчёт о конкурсе">03.02.2025</a></b></span><br><span class="sm">Линии и пейзажи</span></p>
<table>
<tr>
<a href="/photo/1894111/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/18/94/11/1894111_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs3.png" style="position:relative; top:-2px"> &nbsp;</a>
<a href="/photo/2063989/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/63/98/2063989_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs2.png" style="position:relative; top:-2px"> &nbsp;</a>
<a href="/photo/2061805/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/61/80/2061805_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs1.png" style="position:relative; top:-2px"> &nbsp;</a>
</tr>
</table><br>
<p><span class="narrow" style="font-size:21px"><b><a href="?show=table&amp;date=2025-02-02" title="Подробный отчёт о конкурсе">02.02.2025</a></b></span><br><span class="sm">Фотографии транспорта</span></p>
<table>
<tr>
<a href="/photo/2065272/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/65/27/2065272_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs3.png" style="position:relative; top:-2px"> &nbsp;</a>
<a href="/photo/2064912/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/64/91/2064912_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs2.png" style="position:relative; top:-2px"> &nbsp;</a>
<a href="/photo/2026071/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/26/07/2026071_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs1.png" style="position:relative; top:-2px"> &nbsp;</a>
</tr>
</table><br>
<p><span class="narrow" style="font-size:21px"><b><a href="?show=table&amp;date=2025-02-01" title="Подробный отчёт о конкурсе">01.02.2025</a></b></span><br><span class="sm">Фотографии транспорта</span></p>
<table>
<tr>
<a href="/photo/2064843/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/64/84/2064843_s.jpg?1" class="f" style="margin-bottom:7px"><br><img src="/img/vs3.png" style="position:relative; top:-2px"> &nbsp;</a>
<a href="/photo/2065143/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/65/14/2065143_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs2.png" style="position:relative; top:-2px"> &nbsp;</a>
<a href="/photo/2063982/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/63/98/2063982_s.jpg?1" class="f" style="margin-bottom:7px"><br><img src="/img/vs1.png" style="position:relative; top:-2px"> &nbsp;</a>
</tr>
</table><br>
<p><span class="narrow" style="font-size:21px"><b><a href="?show=table&amp;date=2025-01-31" title="Подробный отчёт о конкурсе">31.01.2025</a></b></span><br><b class="sm">Итоговое голосование</b></p>
<table>
<tr>
<a href="/photo/2042060/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/42/06/2042060_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs5.png" style="position:relative; top:-2px"> &nbsp;</a>
</tr>
</table><br>
<p><span class="narrow" style="font-size:21px"><b><a href="?show=table&amp;date=2025-01-30" title="Подробный отчёт о конкурсе">30.01.2025</a></b></span><br><span class="sm">Линии и пейзажи</span></p>
<table>
<tr>
<a href="/photo/2058534/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/58/53/2058534_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs3.png" style="position:relative; top:-2px"> &nbsp;</a>
<a href="/photo/2057575/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/57/57/2057575_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs2.png" style="position:relative; top:-2px"> &nbsp;</a>
<a href="/photo/2058630/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/58/63/2058630_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs1.png" style="position:relative; top:-2px"> &nbsp;</a>
</tr>
</table><br>
<p><span class="narrow" style="font-size:21px"><b><a href="?show=table&amp;date=2025-01-29" title="Подробный отчёт о конкурсе">29.01.2025</a></b></span><br><span class="sm">Фотографии транспорта</span></p>
<table>
<tr>
<a href="/photo/2064029/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/64/02/2064029_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs3.png" style="position:relative; top:-2px"> &nbsp;</a>
<a href="/photo/2065381/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/65/38/2065381_s.jpg?1" class="f" style="margin-bottom:7px"><br><img src="/img/vs3.png" style="position:relative; top:-2px"> &nbsp;</a>
<a href="/photo/2065050/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/65/05/2065050_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs1.png" style="position:relative; top:-2px"> &nbsp;</a>
<a href="/photo/2065800/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/65/80/2065800_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs1.png" style="position:relative; top:-2px"> &nbsp;</a>
</tr>
</table><br>
<p><span class="narrow" style="font-size:21px"><b><a href="?show=table&amp;date=2025-01-28" title="Подробный отчёт о конкурсе">28.01.2025</a></b></span><br><span class="sm">Фотографии транспорта</span></p>
<table>
<tr>
<a href="/photo/2062445/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/62/44/2062445_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs3.png" style="position:relative; top:-2px"> &nbsp;</a>
<a href="/photo/2048251/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/48/25/2048251_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs2.png" style="position:relative; top:-2px"> &nbsp;</a>
<a href="/photo/2062446/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/62/44/2062446_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs1.png" style="position:relative; top:-2px"> &nbsp;</a>
</tr>
</table><br>
<p><span class="narrow" style="font-size:21px"><b><a href="?show=table&amp;date=2025-01-26" title="Подробный отчёт о конкурсе">26.01.2025</a></b></span><br><span class="sm">Фотографии транспорта</span></p>
<table>
<tr>
<a href="/photo/2061877/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/61/87/2061877_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs3.png" style="position:relative; top:-2px"> &nbsp;</a>
<a href="/photo/2047310/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/47/31/2047310_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs2.png" style="position:relative; top:-2px"> &nbsp;</a>
<a href="/photo/2060964/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/60/96/2060964_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs1.png" style="position:relative; top:-2px"> &nbsp;</a>
</tr>
</table><br>
<p><span class="narrow" style="font-size:21px"><b><a href="?show=table&amp;date=2025-01-25" title="Подробный отчёт о конкурсе">25.01.2025</a></b></span><br><span class="sm">Фотографии транспорта</span></p>
<table>
<tr>
<a href="/photo/2061294/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/61/29/2061294_s.jpg?2" class="f" style="margin-bottom:7px"><br><img src="/img/vs4.png" style="position:relative; top:-2px"> &nbsp;</a>
<a href="/photo/2061425/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/61/42/2061425_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs2.png" style="position:relative; top:-2px"> &nbsp;</a>
<a href="/photo/2048649/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="/img/prw-loader.gif" data-src="/photo/20/48/64/2048649_s.jpg" class="f" style="margin-bottom:7px"><br><img src="/img/vs1.png" style="position:relative; top:-2px"> &nbsp;</a>
</tr>
</table><br>
<div class="pages"><span class="pg">&laquo;&laquo;</span><span class="ps">1</span><a href="?show=results&amp;st=10" class="pg">2</a><a href="?show=results&amp;st=20" class="pg">3</a><a href="?show=results&amp;st=30" class="pg">4</a> &middot;&middot;&middot; <a href="?show=results&amp;st=2090" class="pg">210</a><a href="?show=results&amp;st=10" class="pg" id="NextLink">&raquo;&raquo;</a></div>
<p class="narrow" style="font-size:19px"><a href="/voting.php">Голосование</a> &nbsp;&middot;&nbsp; <b>Победители</b> &nbsp;&middot;&nbsp; <a href="?show=rating">Рейтинг</a> &nbsp;&middot;&nbsp; <a href="?show=waiting">Претенденты</a></p>
<p class="narrow" style="font-size:19px"><a href="/voting">Голосование</a> &nbsp;&middot;&nbsp; <b>Победители</b> &nbsp;&middot;&nbsp; <a href="/voting/rating">Рейтинг</a> &nbsp;&middot;&nbsp; <a href="/voting/waiting">Претенденты</a></p>
<?php
$photos = DB::query("SELECT * FROM contests_winners
WHERE place BETWEEN 1 AND 3
ORDER BY contest_id, place;
");
$grouped = [];
foreach ($photos as $row) {
$grouped[$row['contest_id']][] = $row;
}
$final_result = [];
foreach ($grouped as $contest_id => $rows) {
$chunks = array_chunk($rows, 3);
foreach ($chunks as $chunk) {
$final_result[] = $chunk;
}
}
foreach ($final_result as $fc) {
$themeid = DB::query('SELECT themeid FROM contests WHERE id=:id', array(':id'=>$fc[0]['contest_id']))[0]['themeid'];
$theme = DB::query('SELECT title FROM contests_themes WHERE id=:id', array(':id'=>$themeid))[0]['title'];
echo '<p><span class="narrow" style="font-size:21px"><b><a href="?show=table&amp;date=2025-02-04" title="Подробный отчёт о конкурсе">'.date('d.m.Y', $fc[0]['date']).'</a></b></span><br><span class="sm">'.$theme.'</span></p>
<table>
<tr>';
foreach ($fc as $f) {
$photo = new Photo($f['photo_id']);
if ($f['place'] === 1) {
$img = 'vs3';
} else if ($f['place'] === 2) {
$img = 'vs2';
} else if ($f['place'] === 3) {
$img = 'vs1';
}
echo '<a href="/photo/'.$f['photo_id'].'/" class="p20" style="display:table-cell; text-align:center; vertical-align:bottom; padding:20px 20px 10px; font-size:17px"><img src="'.$photo->i('photourl').'" class="f" style="margin-bottom:7px"><br><img src="/static/img/'.$img.'.png" style="position:relative; top:-2px"> &nbsp;</a>';
}
echo '
</tr>
</table><br>';
}
?>
<p class="narrow" style="font-size:19px"><a href="/voting">Голосование</a> &nbsp;&middot;&nbsp; <b>Победители</b> &nbsp;&middot;&nbsp; <a href="/voting/rating">Рейтинг</a> &nbsp;&middot;&nbsp; <a href="/voting/waiting">Претенденты</a></p>
</center>
</td>
</tr>

View file

@ -0,0 +1,190 @@
<?php
use \App\Services\{Auth, DB, Date};
use \App\Models\{Vehicle, User};
function convertUnixToRussianDateTime($unixTime)
{
// Создаем объект DateTime из Unix-времени
$dateTime = new DateTime("@$unixTime");
// Устанавливаем временную зону (можно изменить на нужную)
$dateTime->setTimezone(new DateTimeZone('Europe/Moscow'));
// Форматируем дату и время с использованием IntlDateFormatter
$formatter = new IntlDateFormatter(
'ru_RU',
IntlDateFormatter::LONG,
IntlDateFormatter::NONE,
'Europe/Moscow',
IntlDateFormatter::GREGORIAN,
'd MMMM yyyy года в H:mm'
);
return $formatter->format($dateTime);
}
?>
<!DOCTYPE html>
<html lang="ru">
<head>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/LoadHead.php'); ?>
</head>
<body>
<div id="backgr"></div>
<table class="tmain">
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Navbar.php'); ?>
<tr>
<td class="main">
<h1>Принять участие в Фотоконкурсе</h1>
<script src="/js/jquery-ui.js?1633005526"></script>
<script src="/js/selector.js?1730197663"></script>
<form id="sendForm" method="post" id="mform">
<h4>В каком Фотоконкурсе вы хотите принять участие?</h4>
<div class="p20w">
<table>
<tbody>
<tr>
<th></th>
<th>Тематика</th>
<th>Старт набора претендентов</th>
<th>Закрытие набора претендентов</th>
<th>Начало проведения</th>
<th>Итоги и победители</th>
</tr>
<?php
$entities = DB::query('SELECT * FROM contests WHERE closepretendsdate>=:id', array(':id' => time()));
foreach ($entities as $e) {
$theme = DB::query('SELECT * FROM contests_themes WHERE id=:id', array(':id' => $e['themeid']))[0];
echo '<tr>
<td class="ds"><input type="radio" name="cid" id="n' . $e['id'] . '" value="' . $e['id'] . '" onclick="fillFields(' . $e['id'] . ')"></td>
<td class="n">' . $theme['title'] . '</td>
<td class="ds">' . convertUnixToRussianDateTime($e['openpretendsdate']) . '</td>
<td class="ds">' . convertUnixToRussianDateTime($e['closepretendsdate']) . '</td>
<td class="ds">' . convertUnixToRussianDateTime($e['opendate']) . '</td>
<td class="ds">' . convertUnixToRussianDateTime($e['closedate']) . '</td>
</tr>';
}
?>
</tbody>
</table>
</div>
<br clear="all"><br>
<div class="p20" style="padding-left:5px; margin-bottom:15px">
<table class="nospaces" width="100%">
<tbody>
<?php
$vehicle = DB::query('SELECT * FROM entities WHERE id=:id', array(':id' => $_GET['type']))[0];
$data = json_decode($vehicle['sampledata'], true);
$count = 1;
foreach ($data as $d) {
if ($d['important'] === "1") {
$imp = 'required';
}
echo '
<tr>
<td class="lcol">' . $d['name'] . '</td>
<td style="padding-bottom:15px"><input type="text" name="modelinput_' . $count . '" id="num" style="width:80px" maxlength="21" value=""></td>
</tr>';
$count++;
}
?>
<tr>
<td style="width: 10%"></td>
</tr>
<tr>
<tr>
<td class="lcol">Фотография, которую вы хотите отправить на Фотоконкурс</td>
<td style="padding-bottom:15px">
<select id="photoId" name="photo_id">
<option value="'.$p['id'].'" disabled selected>Выберите фотографию</option>
<?php
$photos = DB::query('SELECT * FROM photos WHERE user_id=:uid AND on_contest=0', array(':uid' => Auth::userid()));
foreach ($photos as $p) {
$content = json_decode($p['content'], true);
if (($content['video'] === null || $content['type'] === 'image') && $p['moderated'] === 1) {
echo '<option photourl="/api/photo/compress?url=' . $p['photourl'] . '" value="' . $p['id'] . '">[ID: ' . $p['id'] . '] ' . $p['place'] . '</option>';
}
}
?>
</select>
</td>
</tr>
<td>
<div id="result"></div>
</td>
<td>
<br>
<input type="submit" value="&nbsp; &nbsp; &nbsp; Отправить &nbsp; &nbsp; &nbsp;">
</td>
</tr>
</tbody>
</table>
</div>
</form>
</td>
</tr>
<script>
$('#sendForm').submit(function(e) {
e.preventDefault();
$.ajax({
type: "POST",
url: '/api/photo/contests/sendpretend',
data: $(this).serialize(),
success: function(response) {
var jsonData = JSON.parse(response);
if (jsonData.errorcode === 0) {
alert('Фотография успешно отправлена на претенденты на Фотоконкурс');
} else {
alert('Пожалуйста, выберите Фотоконкурс на который вы хотите отправить фотографию!');
}
}
});
});
document.getElementById('photoId').addEventListener('change', function() {
const selectedOption = this.options[this.selectedIndex];
const photoUrl = selectedOption.getAttribute('photourl');
if (photoUrl) {
const imgElement = document.createElement('img');
imgElement.src = photoUrl;
imgElement.alt = 'Изображение';
imgElement.style.maxWidth = '500px';
const resultDiv = document.getElementById('result');
resultDiv.innerHTML = '';
resultDiv.appendChild(imgElement);
}
});
</script>
<tr>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Footer.php'); ?>
</tr>
</table>
</body>
</html>

View file

@ -0,0 +1,140 @@
<?php
use \App\Services\{Auth, DB, Date};
use \App\Models\{User, VoteContest, Vote};
?>
<!DOCTYPE html>
<html lang="ru">
<head>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/LoadHead.php'); ?>
</head>
<body>
<div id="backgr"></div>
<table class="tmain">
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Navbar.php'); ?>
<tr>
<td class="main">
<center>
<h1>Претенденты на участие в конкурсе</h1>
<script>
var self_p = false;
var pid = 0;
</script>
<p class="narrow" style="font-size:19px"><a href="/voting">Голосование</a> &nbsp;·&nbsp; <a href="/voting/results">Победители</a> &nbsp;·&nbsp; <a href="/voting/rating">Рейтинг</a> &nbsp;·&nbsp; <b>Претенденты</b></p>
<p style="margin:20px">На этой странице собраны фотографии, предложенные для участия в конкурсе их авторами либо пользователями сайта, для того, чтобы Вы проголосовали за их участие или против. Снимки отсортированы по времени публикации.<br><br>Пожалуйста, не стесняйтесь нажимать синюю кнопку.</p>
<?php
if (DB::query('SELECT status FROM contests WHERE status=1')[0]['status'] === 1) {
$contest = DB::query('SELECT * FROM contests WHERE status=1')[0];
$photos_contest = DB::query('SELECT p.*, COUNT(prc.photo_id) AS rates_count
FROM photos p
LEFT JOIN photos_rates_contest prc ON p.id = prc.photo_id
WHERE p.on_contest = 1 AND p.contest_id = :id
GROUP BY p.id
ORDER BY rates_count DESC;
', array(':id'=>$contest['id']));
foreach ($photos_contest as &$photo) {
$photo['votes'] = VoteContest::count($pc['id'], $contest['id']);
}
usort($photos_contest, function ($a, $b) {
return $b['votes'] <=> $a['votes'];
});
foreach ($photos_contest as $pc) {
$user = new User($pc['user_id']);
if (VoteContest::photo(Auth::userid(), $pc['id'], $contest['id']) === 1) {
$classp = 'voted';
} else if (VoteContest::photo(Auth::userid(), $pc['id'], $contest['id']) === 0) {
$classm = 'voted';
}
echo '<div class="p20p">
<table>
<tbody>
<tr>
<td class="pb_pre vote" style="padding-left:15px; padding-right:10px; display:table-cell" cid="'.$contest['id'].'" pid="'.$pc['id'].'">
<a href="#" vote="1" class="konk_btn '.$classp.'"><span>Красиво, на&nbsp;конкурс!</span></a>
<table style="margin:5px 0 7px; width:100px">
<tbody>
<tr>
<td style="width:20px"><img class="loader" pid="2072294" src="/img/loader.gif"></td>
<td align="center" style="padding:2px"><b class="s_rating" pid="'.$pc['id'].'">'.VoteContest::count($pc['id'], $contest['id']).'</b></td>
<td style="width:20px; display:table-cell" class="star" pid="2072294"><img src="/img/star_people.png" alt=""></td>
</tr>
</tbody>
</table>
<a href="#" vote="0" class="konk_btn '.$classm.'"><span>Неконкурсное фото</span></a>
</td>
<td class="pb_photo" id="p2072294"><a href="/photo/'.$pc['id'].'" target="_blank" class="prw"><img class="f" src="/api/photo/compress?url='.$pc['photourl'].'" alt="597 КБ" style="display: inline;">
<div class="hpshade">
<div class="eye-icon">'.DB::query('SELECT COUNT(*) FROM photos_views WHERE photo_id=:id', array(':id'=>$pc['id']))[0]['COUNT(*)'].'</div>
</div>
</a></td>
<td class="pb_descr">
<p>'.htmlspecialchars($pc['postbody']).'</p>
<p><b class="pw-place">'.htmlspecialchars($pc['place']).'</b></p>
<p class="sm"><b>'.Date::zmdate($pc['posted_at']).'</b><br>Автор: <a href="/author/'.$pc['user_id'].'/">'.$user->i('username').'</a></p>
</td>
</tr>
</tbody>
</table>
</div>';
}
} else {
echo '<h2><b>Следующего конкурса нет. Пожалуйста, заходите сюда позже.</b></h2>';
}
?>
<br>
<p class="narrow" style="font-size:19px"><a href="/voting">Голосование</a> &nbsp;·&nbsp; <a href="/voting/results">Победители</a> &nbsp;·&nbsp; <a href="/voting/rating">Рейтинг</a> &nbsp;·&nbsp; <b>Претенденты</b></p>
</center>
</td>
</tr>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Footer.php'); ?>
</tr>
</table>
<script>
// Установите дату и время, до которого нужно отсчитывать
const countdownDate = new Date("Mar 1, 2025 00:00:00").getTime();
// Обновляем отсчет каждую секунду
const x = setInterval(function() {
// Получаем текущее время
const now = new Date().getTime();
// Вычисляем разницу между целевой датой и текущим временем
const distance = countdownDate - now;
// Вычисляем дни, часы, минуты и секунды
const days = Math.floor(distance / (1000 * 60 * 60 * 24));
const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
// Отображаем результат в элементе с id "countdown"
document.getElementById("countdown").innerHTML =
days + ":" + hours + ":" + minutes + ":" + seconds;
// Если отсчет завершен, выводим сообщение
if (distance < 0) {
clearInterval(x);
document.getElementById("countdown").innerHTML = "Время истекло!";
}
}, 1000);
</script>
</body>
</html>

0
views/pages/Live.php Normal file
View file

View file

@ -79,10 +79,10 @@ LIMIT 10;');
<div class="hpshade">
<div class="eye-icon">+' . $pd['view_count'] . '</div>
</div>';
if ((int)$p['priority'] === 1) {
echo '<div class="temp" style="background-image:url(/static/img/cond.png)"></div>';
}
echo '
if ((int)$p['priority'] === 1) {
echo '<div class="temp" style="background-image:url(/static/img/cond.png)"></div>';
}
echo '
</a>';
}
}
@ -122,6 +122,85 @@ LIMIT 10;');
}
?>
</div>
<style>
#contestNotify {
background-size: 550px 211.2px;
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 550 211.2" width="550" height="211.2" style="opacity: 0.3; filter: grayscale(0);"><text x="0em" y="1em" font-size="88" transform="rotate(17 55 52.8)">🎁</text><text x="1.25em" y="2em" font-size="88" transform="rotate(17 165 140.8)">🎈</text><text x="2.5em" y="1em" font-size="88" transform="rotate(17 275 52.8)">🎀</text><text x="3.75em" y="2em" font-size="88" transform="rotate(17 385 140.8)">🎊</text><text x="5em" y="1em" font-size="88" transform="rotate(17 495 52.8)">🎉</text></svg>');
}
</style>
<?php
if (DB::query('SELECT status FROM contests WHERE status=2')[0]['status'] === 2) {
$contest = DB::query('SELECT * FROM contests WHERE status=2')[0];
$theme = DB::query('SELECT * FROM contests_themes WHERE id=:id', array(':id' => $contest['themeid']))[0];
echo ' <div id="contestNotify" style="float:left; border:solid 1px #171022; padding:6px 10px 7px; margin-bottom:13px; background-color:#E5D6FF"><h4>Фотоконкурс!</h4>
<span id="timett">Закончится через:</span> <b id="countdown"></b><br>
Тематика: <b>' . $theme['title'] . '</b><br>
<b style="color: #412378;">Голосуйте за лучшие фотографии, которые должны стать победителями сегодняшнего конкурса!</b><br><br>
<div id="contestBtns"><a href="/voting" style="background-color: #37009D; color: #fff;" type="button">Голосовать!</a></div>
<script>startCountdown(' . $contest['closedate'] . ');</script>';
} else if (DB::query('SELECT status FROM contests WHERE status=1')[0]['status'] === 1) {
$contest = DB::query('SELECT * FROM contests WHERE status=1')[0];
$theme = DB::query('SELECT * FROM contests_themes WHERE id=:id', array(':id' => $contest['themeid']))[0];
echo ' <div id="contestNotify" style="float:left; border:solid 1px #171022; padding:6px 10px 7px; margin-bottom:13px; background-color:#E5D6FF"><h4>Фотоконкурс!</h4>
<span id="timett">Начнётся через:</span> <b id="countdown"></b><br>
Тематика: <b>' . $theme['title'] . '</b><br>
<b id="textContest" style="color: #412378;">Лучшие фотографии по мнению сообщества ' . NGALLERY['root']['title'] . ' будут отмечены</b><br><br>
<div id="contestBtns"><a href="/voting/sendpretend" style="background-color: #37009D; color: #fff;" type="button">Участвовать!</a> <a href="/voting/waiting" style="background-color: #37009D; color: #fff;" type="button">Голосовать за претендентов</a></div>
<script>
$(document).ready(function () {
let unixThreshold = '.$contest['closepretendsdate'].'; // Задайте нужное значение UNIX
let checkInterval = 1000; // Интервал проверки в миллисекундах (1 секунда)
let isRequestSent = false;
function checkUnixTime() {
let currentUnixTime = Math.floor(Date.now() / 1000);
if (currentUnixTime > unixThreshold) {
$("#countdown").text("Ожидаем ответ от сервера...");
$.ajax({
url: "/api/contests/getinfo", // Укажите свой URL
method: "GET",
success: function (response) {
let data = typeof response === "string" ? JSON.parse(response) : response;
if (data.statuses.pretends === "closed" && data.statuses.public === "opened") {
clearInterval(pingInterval); // Останавливаем старый пинг
$("#textContest").text("Голосуйте за лучшие фотографии, которые должны стать победителями сегодняшнего конкурса!");
$("#timett").text("Закончится через:");
$("#contestBtns").html(`<a href="/voting" style="background-color: #37009D; color: #fff;" type="button">Голосовать!</a>`)
unixThreshold = data.contest.closedate;
startCountdown(data.contest.closedate);
pingInterval = setInterval(checkUnixTime, checkInterval);
}
},
error: function (xhr, status, error) {
console.error("Ошибка запроса:", error);
}
});
} else {
console.log(currentUnixTime);
}
}
// Запускаем периодический пинг
let pingInterval = setInterval(checkUnixTime, checkInterval);
});
</script>';
}
?>
</div>
</div>
@ -135,26 +214,26 @@ LIMIT 10;');
$first_id = $photos[0]['id'];
$last_id = end($photos)['id'];
?>
<div id="recent-photos" class="ix-photos ix-photos-multiline" lastpid="<?=$first_id?>" firstpid="<?=$last_id?>">
</div>
</div>
<div style="text-align:center; margin:10px 0"><input type="button" name="button" id="loadmore" class="" value="Загрузить ещё"></div>
<div id="recent-photos" class="ix-photos ix-photos-multiline" lastpid="<?= $first_id + 1 ?>" firstpid="<?= $last_id ?>">
</div>
</div>
<div style="text-align:center; margin:10px 0"><input type="button" name="button" id="loadmore" class="" value="Загрузить ещё"></div>
<h4>Сейчас на сайте (<?= DB::query('SELECT COUNT(*) FROM users WHERE online>=:time-300 ORDER BY online DESC', array(':time' => time()))[0]['COUNT(*)'] ?>)</h4>
<div>
<?php
$online = DB::query('SELECT * FROM users WHERE online>=:time-300 ORDER BY online DESC', array(':time' => time()));
foreach ($online as $o) {
echo '<a href="/author/' . $o['id'] . '/">' . htmlspecialchars($o['username']) . '</a>, ';
}
?>
<h4>Сейчас на сайте (<?= DB::query('SELECT COUNT(*) FROM users WHERE online>=:time-300 ORDER BY online DESC', array(':time' => time()))[0]['COUNT(*)'] ?>)</h4>
<div>
<?php
$online = DB::query('SELECT * FROM users WHERE online>=:time-300 ORDER BY online DESC', array(':time' => time()));
foreach ($online as $o) {
echo '<a href="/author/' . $o['id'] . '/">' . htmlspecialchars($o['username']) . '</a>, ';
}
?>
</div>
</div>
</td>
<td style="padding-left:20px; width:254px; vertical-align:top">
@ -163,8 +242,8 @@ LIMIT 10;');
<?php
$news = DB::query('SELECT * FROM news ORDER BY id DESC LIMIT 10');
foreach ($news as $n) {
echo '<div class="ix-news-item"><b>'.Date::zmdate($n['time']).'</b>
<div class="break-links" style="padding-top:3px">'.$n['body'].'</div>
echo '<div class="ix-news-item"><b>' . Date::zmdate($n['time']) . '</b>
<div class="break-links" style="padding-top:3px">' . $n['body'] . '</div>
</div>';
}
?>

0
views/pages/Page.php Normal file
View file

View file

@ -125,6 +125,25 @@ if ($photo->i('id') !== null) {
<img onerror="errimg(); this.onerror = null;" id="ph" src="<?= $photo->i('photourl') ?>" alt="" title="Фотография">
<?php
}
if ($photo->i('on_contest') === 2) { ?>
<a class="underphoto" href="/voting"><img style="margin-top:-4px" src="/static/img/star_people.png"> &nbsp;Фотография участвует в голосовании</a>
<?php }
foreach ($photo->content('contests') as $c) {
if ($c['place'] === 1) {
$img = '3';
}
if ($c['place'] === 2) {
$img = '2';
}
if ($c['place'] === 3) {
$img = '1';
}
echo '<a class="underphoto" style="font-weight:bold" href="/pk.php?pid=2068816&amp;type=d"><img style="margin-top:-4px" src="/static/img/vs'.$img.'.png"> &nbsp;'.$c['place'].'-е место на фотоконкурсе</a>';
}
if ($photo->i('priority') === 1) { ?>
<div class="underphoto s17" style="cursor:help" title="Фотография не удовлетворяет действующим на момент публикации критериям качества снимков."><i style="position:relative; top:1px" class="fas fa-info-circle"></i>&ensp;<b class="dot">Условная публикация</b></div>
<?php } else if ($photo->i('priority') === 2) { ?>
@ -172,8 +191,8 @@ if ($photo->i('id') !== null) {
<table class="pwrite">
<tr>
<?php
if ($photo->i('postbody') != null) { ?>
<td class="nw" valign="top" align="right"><b><?= htmlspecialchars($photo->i('postbody')) ?></b></td>
if ($photo->i('place') != null) { ?>
<td class="nw" valign="top" align="right"><b><?= htmlspecialchars($photo->i('place')) ?></b></td>
<?php } ?>
</tr>
@ -197,7 +216,7 @@ if ($photo->i('id') !== null) {
<?php } ?>
<div>
<?php
if ($photo->content('comment') != null) { ?>
if ($photo->content('comment') != null) { ?>
<div style="padding-top:8px"><?= htmlspecialchars($photo->content('comment')) ?></div>
<?php } ?>
</div><br>
@ -258,15 +277,24 @@ if ($photo->i('id') !== null) {
<a href="#" vote="0" class="vote_btn <?php if (Vote::photo(Auth::userid(), $id) === 0) {
echo 'voted';
} ?>"><span>Мне не&nbsp;нравится</span></a>
<!--a class="konk_btn" vote="1" href="#"><span>Красиво, на&nbsp;конкурс!</span></!--a>
<a-- href="#" vote="0" class="konk_btn"><span>Неконкурсное фото</span></a-->
<?php
if (($photo->content('video') === null && $photo->i('user_id') != Auth::userid()) || $photo->i('on_contest') != 2) { ?>
<a class="konk_btn <?php if (Vote::photoContest(Auth::userid(), $id) === 1) {
echo 'voted';
} ?>" vote="1" href="#"><span>Красиво, на&nbsp;конкурс!</span></a>
<a href="#" vote="0" class="konk_btn <?php if (Vote::photoContest(Auth::userid(), $id) === 0) {
echo 'voted';
} ?>"><span>Неконкурсное фото</span></a>
<?php } else if ($photo->i('user_id') === Auth::userid() && $photo->i('on_contest') != 2) { ?>
<a href="#" vote="1" class="konk_btn"><span>Выставить на&nbsp;конкурс</span></a><a href="#" vote="0" class="konk_btn"><span>Не участвовать в&nbsp;конкурсе</span></a></div>
<?php } ?>
</div>
<?php } ?>
<div id="votes" class="votes">
<table class="vblock pro">
<?php
$votespos = DB::query('SELECT * FROM photos_rates WHERE photo_id=:pid AND type=1 ORDER BY id DESC', array(':pid' => $id));
$votespos = DB::query('SELECT * FROM photos_rates WHERE photo_id=:pid AND type=1 AND contest=0 ORDER BY id DESC', array(':pid' => $id));
foreach ($votespos as $ps) {
$uservote = new User($ps['user_id']);
echo ' <tr>
@ -279,7 +307,7 @@ if ($photo->i('id') !== null) {
</table>
<table class="vblock coN">
<?php
$votespos = DB::query('SELECT * FROM photos_rates WHERE photo_id=:pid AND type=0 ORDER BY id DESC', array(':pid' => $id));
$votespos = DB::query('SELECT * FROM photos_rates WHERE photo_id=:pid AND type=0 AND contest=0 ORDER BY id DESC', array(':pid' => $id));
foreach ($votespos as $ps) {
$uservote = new User($ps['user_id']);
echo ' <tr>
@ -334,8 +362,9 @@ if ($photo->i('id') !== null) {
</colgroup>
<tbody>
<?php
$entity = DB::query('SELECT * FROM entities_data WHERE id=:id', array(':id'=>$photo->i('entitydata_id')))[0];
$vehiclevariables = json_decode($vehicle->i('sampledata'), true);
$vehicledatavariables = json_decode($vehicle->i('content'), true);
$vehicledatavariables = json_decode($entity['content'], true);
$num = 1;
foreach ($vehiclevariables as $vb) {
echo ' <tr class="s11 h21">

View file

@ -225,7 +225,7 @@ $birthdate = json_decode($userprofile->i('content'), true)['aboutbirthday']['val
<div class="p20" style="margin-top: 8px; background-color: white !important;">
<h4>О себе</h4>
<?=
$about
htmlspecialchars($about)
?>
</div>
<?php } else if ($usercttc === True) {

View file

@ -43,7 +43,7 @@ $user = new User(Auth::userid());
var pub_pid = 0;
</script>
<td class="main">
<?php if (NGALLERY['root']['registration']['emailverify'] != true || $user->i('status') === 3) {
<?php if (NGALLERY['root']['registration']['emailverify'] != false || $user->i('status') === 3) {
die('Чтобы публиковать Фотографии и Видео, нужно подтвердить почту.');
} ?>
<h1>Предложить медиа на публикацию</h1>

View file

@ -90,7 +90,7 @@ if (Auth::userid() > 0) {
</div>
<div style="color:#e00" id="err_email"></div>
<div class="styled-input">
<input name="password" id="password" type="text" required="">
<input name="password" id="password" type="password" required="">
<label for="password">Ваш пароль</label>
</div>
<div style="color:#e00" id="err_password"></div>
@ -151,7 +151,7 @@ if (Auth::userid() > 0) {
</center>
<?php } else { ?>
<center>
<h1>К сожалению, регистрация на сервере <?= NGALLERY['root']['title'] ?> запрещена.</h1>
<h1>К сожалению, регистрация на сервере <?= NGALLERY['root']['title'] ?> закрыта.</h1>
</center?
<?php } ?>
</td>

View file

@ -1,58 +0,0 @@
<?php
use App\Services\{Router, Auth, DB, Date};
?>
<html lang="ru">
<head>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/LoadHead.php'); ?>
</head>
<body>
<div id="backgr"></div>
<table class="tmain">
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Navbar.php'); ?>
<tr>
<td class="main">
<h1>Результаты поиска</h1>
<div>Найдено изображений: <b><?=DB::query('SELECT COUNT(*) FROM photos WHERE user_id=:uid AND moderated=1 ORDER BY id DESC', array(':uid'=>$_GET['id']))[0]['COUNT(*)']?></b> &nbsp;·&nbsp; <a href="#sf">Новый поиск</a></div><br>
<?php
$photos = DB::query('SELECT * FROM photos WHERE user_id=:uid AND moderated=1 ORDER BY id DESC', array(':uid'=>$_GET['id']));
foreach ($photos as $p) {
echo '<div class="p20p">
<table>
<tbody>
<tr>
<td class="pb_photo" id="p1936120"><a href="/photo/'.$p['id'].'" target="_blank" class="prw"><img class="f" src="'.$p['photourl'].'">
<div class="hpshade">
';
if (DB::query('SELECT COUNT(*) FROM photos_comments WHERE photo_id=:id', array(':id'=>$p['id']))[0]['COUNT(*)'] >= 1) {
echo '<div class="com-icon">'.DB::query('SELECT COUNT(*) FROM photos_comments WHERE photo_id=:id', array(':id'=>$p['id']))[0]['COUNT(*)'].'</div>';
}
echo '
<div class="eye-icon">'.DB::query('SELECT COUNT(*) FROM photos_views WHERE photo_id=:id', array(':id'=>$p['id']))[0]['COUNT(*)'].'</div></div>
</a></td>
<td class="pb_descr">
<p><b class="pw-place">'.htmlspecialchars($p['place']).'</b></p>
<span class="pw-descr">'.htmlspecialchars($p['postbody']).'</span>
<p class="sm"><b>'.Date::zmdate($p['timeupload']).'</b><br>Автор: <a href="/author/'.$p['user_id'].'/">'.htmlspecialchars($p['username']).'</a></p>
</td>
</tr>
</tbody>
</table>
</div>';
}
?>
</tbody>
</table>
</body>
</html>

View file

@ -0,0 +1,515 @@
<?php
use App\Services\{Router, Auth, DB, Date};
?>
<html lang="ru">
<head>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/LoadHead.php'); ?>
</head>
<body>
<div id="backgr"></div>
<table class="tmain">
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Navbar.php'); ?>
<tr>
<td class="main">
<h1>Результаты поиска</h1>
<div>Найдено изображений: <b><?=DB::query('SELECT COUNT(*) FROM photos WHERE user_id=:uid AND moderated=1 ORDER BY id DESC', array(':uid'=>$_GET['id']))[0]['COUNT(*)']?></b> &nbsp;·&nbsp; <a href="#sf">Новый поиск</a></div><br>
<?php
$photos = DB::query('SELECT * FROM photos WHERE user_id=:uid AND moderated=1 ORDER BY id DESC', array(':uid'=>$_GET['id']));
foreach ($photos as $p) {
echo '<div class="p20p">
<table>
<tbody>
<tr>
<td class="pb_photo" id="p1936120"><a href="/photo/'.$p['id'].'" target="_blank" class="prw"><img class="f" src="'.$p['photourl'].'">
<div class="hpshade">
';
if (DB::query('SELECT COUNT(*) FROM photos_comments WHERE photo_id=:id', array(':id'=>$p['id']))[0]['COUNT(*)'] >= 1) {
echo '<div class="com-icon">'.DB::query('SELECT COUNT(*) FROM photos_comments WHERE photo_id=:id', array(':id'=>$p['id']))[0]['COUNT(*)'].'</div>';
}
echo '
<div class="eye-icon">'.DB::query('SELECT COUNT(*) FROM photos_views WHERE photo_id=:id', array(':id'=>$p['id']))[0]['COUNT(*)'].'</div></div>
</a></td>
<td class="pb_descr">
<p><b class="pw-place">'.htmlspecialchars($p['place']).'</b></p>
<span class="pw-descr">'.htmlspecialchars($p['postbody']).'</span>
<p class="sm"><b>'.Date::zmdate($p['timeupload']).'</b><br>Автор: <a href="/author/'.$p['user_id'].'/">'.htmlspecialchars($p['username']).'</a></p>
</td>
</tr>
</tbody>
</table>
</div>';
}
?>
<form method="get" id="mform" class="p20w" style="padding:10px 20px 10px 10px">
<table>
<tbody><tr>
<td colspan="2"><h4 style="margin:-5px 0 10px">Условия, относящиеся к ТС:</h4></td>
</tr>
<tr>
<td class="lcol">Страна:</td>
<td>
<input type="hidden" name="vrid" id="vrid" value="0">
<div class="ac-loader"></div><span role="status" aria-live="polite" class="ui-helper-hidden-accessible"></span><input type="text" id="vrname" style="width: 250px; padding-left: 3px; padding-right: 3px;" value="Не имеет значения" class="ui-autocomplete-input" autocomplete="off"><div class="xsign" style="display: none;"></div>
</td>
</tr>
<tr>
<td class="lcol">Город ТС:</td>
<td>
<input type="hidden" name="vcid" id="vcid" value="-1" data-vrid="0">
<div class="ac-loader"></div><span role="status" aria-live="polite" class="ui-helper-hidden-accessible"></span><input type="text" id="vcname" style="width: 250px; padding-left: 3px; padding-right: 3px;" value="Не имеет значения" class="ui-autocomplete-input" autocomplete="off"><div class="xsign" style="display: none;"></div>
</td>
</tr>
<tr>
<td class="lcol">Вид транспорта:</td>
<td>
<select name="vtype" id="vtype" class="">
<option value="-1" class="" selected="">Не имеет значения</option>
<option value="1" class="s5">Трамвай</option>
<option value="2" class="s8">Троллейбус</option>
<option value="3" class="s7">Метрополитен</option>
<option value="4" class="s9">Монорельс</option>
<option value="5" class="s2">Фуникулёр</option>
<option value="6" class="s6">Транслор</option>
<option value="7" class="s9">Мувер (АТН)</option>
<option value="8" class="s9">Маглев</option>
<option value="9" class="s3">Электробус</option>
</select> </td>
</tr>
<tr>
<td class="lcol">Локация:</td>
<td>
<select name="loid" id="loid" style="width:400px" data-vcid="-1" disabled="">
<option value="0">Не имеет значения</option>
</select>
</td>
</tr>
<tr>
<td class="lcol">Депо/Парк:</td>
<td>
<select name="did" id="did" style="width:400px" data-vcid="-1" data-vtype="-1" data-loid="0" disabled="">
<option value="0">Не имеет значения</option>
</select>
</td>
</tr>
<tr>
<td class="lcol">Система:</td>
<td>
<input type="hidden" name="vgrid" id="vgrid" value="0">
<div class="ac-loader"></div><span role="status" aria-live="polite" class="ui-helper-hidden-accessible"></span><input type="text" id="vgrname" style="width: 400px; padding-left: 3px; padding-right: 3px;" value="Не имеет значения" class="ui-autocomplete-input" autocomplete="off"><div class="xsign" style="display: none;"></div>
</td>
</tr>
<tr>
<td class="lcol">Назначение:</td>
<td style="padding-bottom:17px">
<select name="serv">
<option value="-1" selected="">Не имеет значения</option>
<option value="0">Пассажирский</option>
<option value="1">Служебный</option>
<option value="2">Музейный</option>
</select> </td>
</tr>
<tr>
<td class="lcol">Номер:</td>
<td><input type="text" name="num" style="width:100px" value=""></td>
</tr>
<tr>
<td class="lcol">Госномер:</td>
<td style="padding-bottom:17px"><input type="text" name="gos" style="width:100px" value=""></td>
</tr>
<tr>
<td class="lcol">Модель:</td>
<td>
<input type="hidden" name="mid" id="mid" value="-1" data-vtype="-1">
<div class="ac-loader"></div><span role="status" aria-live="polite" class="ui-helper-hidden-accessible"></span><input type="text" id="mname" style="width: 250px; padding-left: 3px; padding-right: 3px;" value="Не имеет значения" disabled="" class="ui-autocomplete-input" autocomplete="off"><div class="xsign" style="display: none;"></div>&nbsp;
<input type="checkbox" name="sub" id="sub" value="1"> <label for="sub">Учесть подмодели</label>
</td>
</tr>
<tr>
<td class="lcol">Шасси:</td>
<td style="padding-bottom:17px">
<input type="hidden" name="chid" id="chid" value="-1" data-vtype="-1">
<div class="ac-loader"></div><span role="status" aria-live="polite" class="ui-helper-hidden-accessible"></span><input type="text" id="chname" style="width: 250px; padding-left: 3px; padding-right: 3px;" value="Не имеет значения" disabled="" class="ui-autocomplete-input" autocomplete="off"><div class="xsign" style="display: none;"></div>&nbsp;
<input type="checkbox" name="sub2" id="sub2" value="1"> <label for="sub2">Учесть подмодели</label>
</td>
</tr>
<tr>
<td colspan="2"><h4 style="margin:0 0 10px">Условия, относящиеся к галереям:</h4></td>
</tr>
<tr>
<td class="lcol">Город галереи:</td>
<td>
<input type="hidden" name="gcid" id="gcid" value="-1">
<div class="ac-loader"></div><span role="status" aria-live="polite" class="ui-helper-hidden-accessible"></span><input type="text" id="gcname" style="width: 250px; padding-left: 3px; padding-right: 3px;" value="Не имеет значения" class="ui-autocomplete-input" autocomplete="off"><div class="xsign" style="display: none;"></div>
</td>
</tr>
<tr>
<td class="lcol">Вид транспорта:</td>
<td>
<select name="gtype" id="gtype" class="">
<option value="-1" class="" selected="">Не имеет значения</option>
<option value="0" class="s0">Без вида транспорта</option>
<option value="1" class="s5">Трамвай</option>
<option value="2" class="s8">Троллейбус</option>
<option value="3" class="s7">Метрополитен</option>
<option value="4" class="s9">Монорельс</option>
<option value="5" class="s2">Фуникулёр</option>
<option value="6" class="s6">Транслор</option>
<option value="7" class="s9">Мувер (АТН)</option>
<option value="8" class="s9">Маглев</option>
<option value="9" class="s3">Электробус</option>
</select> </td>
</tr>
<tr>
<td class="lcol">Раздел:</td>
<td>
<select name="sid" id="sid" style="width:400px">
<option value="0" selected="">Не имеет значения</option>
<option value="1">События ГЭТ</option>
<option value="2">Фотогалереи ГЭТ</option>
<option value="6">Транспортное сообщество</option>
<option value="7">Выставки</option>
<option value="8">Обзоры</option>
<option value="9">Строительство и реконструкция</option>
<option value="13">Железная дорога</option>
<option value="14">Оборудование электротранспорта</option>
<option value="15">Творчество</option>
<option value="20">Метрополитены</option>
<option value="21">Монорельсы</option>
<option value="22">Фуникулёры</option>
<option value="112">События метрополитена</option>
<option value="113">Карты и схемы</option>
<option value="114">Временный раздел</option>
</select> </td>
</tr>
<tr>
<td class="lcol">Галерея:</td>
<td style="padding-bottom:17px">
<select name="gid" id="gid" style="width:400px" data-gcid="-1" data-gtype="-1" data-sid="0" disabled="">
<option value="0">Не имеет значения</option>
</select>
</td>
</tr>
<tr>
<td colspan="2"><h4 style="margin:0 0 10px">Условия, относящиеся к фото:</h4></td>
</tr>
<tr>
<td class="lcol">Вид транспорта:</td>
<td><select name="ptype" id="ptype" class="">
<option value="-1" class="" selected="">Не имеет значения</option>
<option value="0" class="s0">Без вида транспорта</option>
<option value="1" class="s5">Трамвай</option>
<option value="2" class="s8">Троллейбус</option>
<option value="3" class="s7">Метрополитен</option>
<option value="4" class="s9">Монорельс</option>
<option value="5" class="s2">Фуникулёр</option>
<option value="6" class="s6">Транслор</option>
<option value="7" class="s9">Мувер (АТН)</option>
<option value="8" class="s9">Маглев</option>
<option value="9" class="s3">Электробус</option>
</select></td>
</tr>
<tr>
<td class="lcol">Страна:</td>
<td>
<input type="hidden" name="prid" id="prid" value="0">
<div class="ac-loader"></div><span role="status" aria-live="polite" class="ui-helper-hidden-accessible"></span><input type="text" id="prname" style="width: 250px; padding-left: 3px; padding-right: 3px;" value="Не имеет значения" class="ui-autocomplete-input" autocomplete="off"><div class="xsign" style="display: none;"></div>
</td>
</tr>
<tr>
<td class="lcol">Система:</td>
<td>
<input type="hidden" name="pgrid" id="pgrid" value="0">
<div class="ac-loader"></div><span role="status" aria-live="polite" class="ui-helper-hidden-accessible"></span><input type="text" id="pgrname" style="width: 400px; padding-left: 3px; padding-right: 3px;" value="Не имеет значения" class="ui-autocomplete-input" autocomplete="off"><div class="xsign" style="display: none;"></div>
</td>
</tr>
<tr>
<td class="lcol">Город съёмки:</td>
<td>
<input type="hidden" name="pcid" id="pcid" value="-1" data-prid="0">
<div class="ac-loader"></div><span role="status" aria-live="polite" class="ui-helper-hidden-accessible"></span><input type="text" id="pcname" style="width: 400px; padding-left: 3px; padding-right: 3px;" value="Не имеет значения" class="ui-autocomplete-input" autocomplete="off"><div class="xsign" style="display: none;"></div>
</td>
</tr>
<tr>
<td class="lcol">Место съёмки:</td>
<td style="padding-bottom:15px">
<div class="ac-loader"></div><span role="status" aria-live="polite" class="ui-helper-hidden-accessible"></span><input type="text" name="place" id="place" style="width:400px; margin-bottom:3px" value="" class="ui-autocomplete-input" autocomplete="off"><br>
<input type="checkbox" name="strict" id="strict" value="1"> <label for="strict">Строгое соответствие места съёмки</label><br>
<input type="checkbox" name="no_ren" id="no_ren" value="1" disabled=""> <label for="no_ren" style="color:#888">Без учёта переименований</label>
</td>
</tr>
<tr>
<td class="lcol">Маршрут:</td>
<td><input type="text" name="route" style="width:60px" value=""></td>
</tr>
<tr>
<td class="lcol">Примечание:</td>
<td><input type="text" name="notes" style="width:200px" value=""></td>
</tr>
<tr>
<td class="lcol">Описание:</td>
<td style="padding-bottom:17px"><input type="text" name="descr" style="width:400px" value=""></td>
</tr>
<tr>
<td class="lcol">Конкурсное:</td>
<td><select name="konk">
<option value="0" selected="">Не имеет значения</option>
<option value="10">Все участники</option>
<option value="9">3 место и выше</option>
<option value="8">2 место и выше</option>
<option value="7">1 место и выше</option>
<option value="5">Пятёрка лучших за месяц</option>
<option value="4">Фото месяца</option>
<option value="2">Тройка лучших за год</option>
<option value="1">Фото года</option>
</select></td>
</tr>
<tr>
<td class="lcol">Ракурс:</td>
<td>
<input type="hidden" name="view" id="view" value="-1">
<input type="text" id="view_txt" value="Не имеет значения" style="width:300px; cursor:pointer" readonly="">
<div id="views-selector" style="position:absolute; padding:5px; z-index:20; display:none" class="p20 shadow">
<table id="views">
<tbody><tr>
<td colspan="3" style="text-align:center"><input type="checkbox" name="view_top" value="20" id="v20"> <label for="v20">Вид сверху</label></td>
<td></td>
</tr>
<tr>
<td><input type="radio" name="view_s" value="4" title="Сзади-слева (окна)" class="views-radio-single" style="position:relative; top:7px; left:7px"></td>
<td style="text-align:center">
<input type="radio" name="view_s" value="8" title="Левый борт" class="views-radio-single">
</td>
<td><input type="radio" name="view_s" value="2" title="Спереди-слева (окна)" style="position:relative; top:7px; left:-7px"></td>
<td style="padding:0 35px; line-height:23px" rowspan="3">
<div><input type="radio" name="view_s" value="12" id="v12"> <label for="v12">Заводская табличка</label></div>
<div><input type="radio" name="view_s" value="13" id="v13"> <label for="v13">Отдельные элементы ТС</label></div>
<div class="twoside-old"><input type="radio" name="view_s" value="14" id="v14"> <label for="v14">Не определяется (двухстороннее ТС)</label></div>
<div><input type="radio" name="view_s" value="0" id="v0"> <label for="v0">Не указан</label></div>
<div><input type="radio" name="view_s" value="-1" id="vnone"> <label for="vnone">Не имеет значения</label></div>
<div class="sm" style="margin-top:15px"><a href="#" class="views-toggle-link dot">Переключить на: <span class="twoside-single">Одностороннее ТС</span><span class="twoside-twoside">Двухстороннее ТС</span></a></div>
</td>
</tr>
<tr>
<td style="padding:0 2px"><input type="radio" name="view_s" value="7" title="Вид строго сзади" class="views-radio-single"></td>
<td class="views-image">
<table style="width:138px; height:82px">
<tbody><tr>
<td style="text-align:left; padding-left:25px">
<input type="radio" name="view_s" value="9" title="Салон, вид вперёд">
</td>
<td style="text-align:right; padding:0">
<input type="radio" name="view_s" value="10" title="Салон, вид назад" class="views-radio-single">
<input type="radio" name="view_s" value="11" title="Кабина" style="position:relative; top:-7px">
</td>
</tr>
</tbody></table>
</td>
<td style="padding:0 2px"><input type="radio" name="view_s" value="5" title="Вид строго спереди"></td>
</tr>
<tr>
<td><input type="radio" name="view_s" value="3" title="Сзади-справа (двери)" class="views-radio-single" style="position:relative; top:-7px; left:7px"></td>
<td style="text-align:center">
<input type="radio" name="view_s" value="6" title="Правый борт">
</td>
<td><input type="radio" name="view_s" value="1" title="Спереди-справа (двери)" style="position:relative; top:-7px; left:-7px"></td>
</tr>
<tr>
<td colspan="3" style="text-align:center"><input type="checkbox" name="view_bottom" value="40" id="v40"> <label for="v40">Вид снизу</label></td>
<td></td>
</tr>
</tbody></table>
<script>
function openViewSelector(val, el, twoside)
{
var selector = $('#views-selector');
var view = val % 20;
var modifier = val - view;
$('input[value="' + view + '"]', selector).prop('checked', true);
$('#v20').prop('checked', modifier == 20);
$('#v40').prop('checked', modifier == 40);
if (view != 14)
{
selector.attr('data-twoside', twoside);
$('.twoside-old').hide();
}
else
{
selector.attr('data-twoside', 1);
$('.twoside-old').show();
}
var p = el.offset();
selector.css('left', p.left + 'px').css('top', (p.top + el.height() + 3) + 'px').show();
}
function setView(e, func)
{
var selector = $('#views-selector');
var view = parseInt($('input[type="radio"]:checked', selector).val());
var modifier = parseInt($('input[type="checkbox"]:checked', selector).val());
if (isNaN(modifier)) modifier = 0;
var label = view || !modifier ? views[view] : '';
if (label != '' && modifier) label += ' + ';
if (modifier) label += views[modifier];
func(e, view, modifier, label);
selector.hide();
}
function setViewSelectorCallback(func)
{
var selector = $('#views-selector');
$('input[type="radio"]', selector).on('click', function(e)
{
setView(e, func);
});
$('input[type="checkbox"]', selector).on('click', function()
{
if ($(this).is('#v20:checked')) $('#v40').prop('checked', false); else
if ($(this).is('#v40:checked')) $('#v20').prop('checked', false);
});
$(document).on('click', function(e)
{
if ($(e.target).closest('#views-selector').length == 0 && $('#views-selector').is(':visible'))
{
setView(e, func);
}
})
.on('keydown', function(e)
{
// Закрытие селектора ракурса по Esc или Backspace
if ((e.which == 27 || e.which == 8) && $('#views-selector').is(':visible'))
{
e.preventDefault();
setView(e, func);
}
});
}
$(document).ready(function()
{
$('.views-toggle-link').on('click', function()
{
var selector = $('#views-selector');
var twoside = selector.attr('data-twoside');
selector.attr('data-twoside', twoside == 1 ? 0 : 1);
return false;
});
});
</script>
</div>
</td>
</tr>
<!--tr>
<td class="lcol">Модель камеры:</td>
<td style="padding-bottom:17px"><input type="text" name="cammod" style="width:300px" value=""></td>
</!--tr>
<tr>
<td class="lcol">Пользователь:</td>
<td>
<input type="hidden" name="aid" id="aid" value="0">
<div class="ac-loader"></div><span role="status" aria-live="polite" class="ui-helper-hidden-accessible"></span><input type="text" id="aname" style="width: 200px; padding-left: 4px; padding-right: 3px;" value="Не имеет значения" class="ui-autocomplete-input" autocomplete="off"><div class="xsign" style="display: none;"></div>
</td>
</tr>
<tr>
<td class="lcol">Авторство:</td>
<td><select name="auth">
<option value="0" selected="">Не имеет значения</option>
<option value="1">только авторские</option>
<option value="2">присланные этим пользователем</option>
</select> </td>
</tr>
<tr>
<td></td>
<td><input type="checkbox" name="fav" id="fav" value="1"> <label for="fav">Поиск в Избранном</label></td>
</tr>
<tr>
<td></td>
<td><input type="checkbox" name="lost" id="lost" value="1"> <label for="lost">Потерянные фотографии</label><br>&nbsp;</td>
</tr>
<tr>
<td class="lcol">Дата съёмки с</td>
<td>
<input type="text" name="date1" id="date1" size="10" maxlength="10" value="12.02.2025" disabled=""> &nbsp;по&nbsp;
<input type="text" name="date2" id="date2" size="10" maxlength="10" value="12.02.2025" disabled="">&nbsp;
<input type="checkbox" name="anydate" id="anydate" value="1" checked="checked"> <label for="anydate">Не имеет значения</label>
</td>
</tr>
<tr>
<td class="lcol">Опубликовано с</td>
<td>
<input type="text" name="pub1" id="pub1" size="10" maxlength="10" value="12.02.2025" disabled=""> &nbsp;по&nbsp;
<input type="text" name="pub2" id="pub2" size="10" maxlength="10" value="12.02.2025" disabled="">&nbsp;
<input type="checkbox" name="anypub" id="anypub" value="1" checked="checked"> <label for="anypub">Не имеет значения</label>
</td>
</tr>
<tr>
<td></td>
<td class="sm" style="color:#888">Даты в формате ДД.ММ.ГГГГ<br>&nbsp;</td>
</tr>
<tr>
<td></td><td>&nbsp;</td>
</tr>
<tr>
<td class="lcol">Лицензии:</td>
<td>
<input type="checkbox" id="license_cc1" value="1" name="license_cc"> <label for="license_cc1">Выбрать только с свободными лицензиями</label><br>
<input type="checkbox" id="license_cc2" value="1" name="license_cc_commerce" disabled=""> <label for="license_cc2">Материалы для коммерческого использования</label><br>
<input type="checkbox" id="license_cc3" value="1" name="license_cc_derivatives" disabled=""> <label for="license_cc3">Материалы, которые можно изменять, адаптировать или использовать как основу</label>
</td>
</tr>
<tr>
<td></td><td>&nbsp;</td>
</tr>
<tr>
<td align="right">Сортировать по&nbsp;</td>
<td><select name="order">
<option value="0">городу, бортовому номеру, дате съёмки</option>
<option value="1">дате съёмки, городу, бортовому номеру</option>
<option value="2">времени публикации (сверху старые)</option>
<option value="3" selected="">времени публикации (сверху новые)</option>
<option value="4">числу просмотров</option>
<option value="5">рейтингу</option>
<option value="6">числу комментариев</option>
</select> </td>
</tr>
<tr>
<td></td>
<td><br><input type="submit" value="&nbsp; &nbsp; &nbsp; Искать &nbsp; &nbsp; &nbsp;"></td>
</tr-->
</tbody></table>
</form>
</tbody>
</table>
</body>
</html>

View file

@ -0,0 +1,274 @@
<?php
use \App\Services\{Auth, DB, Date};
use \App\Models\{Vehicle, User};
?>
<!DOCTYPE html>
<html lang="ru">
<head>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/LoadHead.php'); ?>
</head>
<body>
<div id="backgr"></div>
<table class="tmain">
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Navbar.php'); ?>
<tr>
<td class="main">
<h1>Внесение изменений в БД</h1>
<script src="/js/jquery-ui.js?1633005526"></script>
<script src="/js/selector.js?1730197663"></script>
<script>
addTexts({
'VF_MAXLENGTH': 'Буфер обмена содержит %s знаков, но значение в этом поле не может быть длиннее %s знаков!\nВероятно, вы пытаетесь вставить некорректные данные'
});
$(document).ready(function() {
$('#mname').autocompleteSelector('mid', '/api.php?action=get-models&type=2', {
minLength: 1,
defaultLabel: '(модель неизвестна)',
defaultValue: 632
});
$('#chname').autocompleteSelector('chid', '/api.php?action=get-chassis&type=2', {
minLength: 1,
defaultLabel: '(нет)'
});
$('#state, #service').change(function() {
$(this).attr('class', $('option:selected', this).attr('class'));
}).change();
$('#mform').on('submit', function() {
var built_y_len = $('#built_y').val().length;
var scrap_y_len = $('#scrap_y').val().length;
if (built_y_len > 1 && built_y_len < 4 ||
scrap_y_len > 1 && scrap_y_len < 4) {
alert('Неверное значение в поле «год» (0, 1 либо 4 символа).');
return false;
}
var source = $('#source');
if (source.val().trim().length < 4) {
alert('Не указан источник сведений. Пожалуйста, заполните соответствующее поле..');
source[0].focus();
return false;
}
$('input[type="submit"]', this).prop('disabled', true);
return true;
});
// Фильтрация вставляемых из буфера данных
$('#num, #gos, #zn, #vin, #cn, #start_y, #leave_y, #built_y, #scrap_y').on('paste', function(e) {
var field = $(this);
var text = e.originalEvent.clipboardData.getData('Text').trim();
var maxlength = parseInt(field.attr('maxlength'));
if (maxlength && text.length > maxlength)
alert(_text['VF_MAXLENGTH'].replace('%s', text.length).replace('%s', maxlength) + '.');
else field.insertAtCaret(text);
return false;
});
// Опции даты
$('.approx-aprx').css('font-weight', 'normal').on('change', function() {
$(this).attr('class', 'approx-aprx ' + $('option:selected', this).attr('class'))
}).change();
});
$.fn.insertAtCaret = function(myValue) {
return this.each(function() {
if (document.selection) {
// For browsers like Internet Explorer
this.focus();
var sel = document.selection.createRange();
sel.text = myValue;
this.focus();
} else
if (this.selectionStart || this.selectionStart == '0') {
// For browsers like Firefox and Webkit based
var startPos = this.selectionStart;
var endPos = this.selectionEnd;
var scrollTop = this.scrollTop;
this.value = this.value.substring(0, startPos) + myValue + this.value.substring(endPos, this.value.length);
this.focus();
this.selectionStart = startPos + myValue.length;
this.selectionEnd = startPos + myValue.length;
this.scrollTop = scrollTop;
} else {
this.value += myValue;
this.focus();
}
})
};
</script>
<form method="post" id="mform" action="?action=write">
<input type="hidden" name="cid" value="14">
<input type="hidden" name="type" value="2">
<input type="hidden" name="link_gos" value="0">
<input type="hidden" name="num" id="num" value="">
<h4>Какую запись вы хотите уточнить?</h4>
<div class="p20w">
<table>
<tbody>
<tr>
<th></th>
<th></th>
<th>Название</th>
</tr>
<tr class="s1">
<td class="ds"><input type="radio" name="base_nid" value="0" checked="checked" onclick="fillFields(0)"></td>
<td class="d" colspan="7">Никакую, я хочу добавить новое ТС</td>
</tr>
<?php
$entities = DB::query('SELECT * FROM entities_data WHERE entityid=:id AND (LOWER(title) LIKE :title) OR id=:title', array(':title'=>$_GET['num'], ':id'=>$_GET['type']));
foreach ($entities as $e) {
echo '<tr>
<td class="ds"><input type="radio" name="base_nid" id="n'.$e['id'].'" value="'.$e['id'].'" onclick="fillFields('.$e['id'].')"></td>
<td class="n"><a href="/vehicle/'.$e['id'].'" target="_blank">'.$e['id'].'</a></td>
<td class="ds">'.$e['title'].'</td>
</tr>';
}
?>
</tbody>
</table>
</div>
<br clear="all"><br>
<div class="p20" style="padding-left:5px; margin-bottom:15px">
<table class="nospaces" width="100%">
<input type="hidden" name="did" value="27">
<tbody>
<?php
$vehicle = DB::query('SELECT * FROM entities WHERE id=:id', array(':id' => $_GET['type']))[0];
$data = json_decode($vehicle['sampledata'], true);
$count = 1;
foreach ($data as $d) {
if ($d['important'] === "1") {
$imp = 'required';
}
echo '
<tr>
<td class="lcol">' . $d['name'] . '</td>
<td style="padding-bottom:15px"><input type="text" name="modelinput_'.$count.'" id="num" style="width:80px" maxlength="21" value=""></td>
</tr>';
$count++;
}
?>
<tr>
<td style="width: 10%"></td>
<script>
var vdata = {};
vdata[0] = [0, '', '', '', 632, '(модель неизвестна)', 0, '(нет)', 0, 1, '', '', '', 0, '', 0, 0, '', 0, '', 0, '', 0, '', 0, '', 0, '', ''];
vdata[594939] = [27, '48', '', '', 135, 'ПТЗ-5283', 0, '(нет)', 0, 5, '14', '', '', 11, '2002', 10, 0, '', 10, '2018-11-30', 10, '0000-00-00', 0, '0000-00-00', 0, '2022-00-00', 0, '', ''];
function setDateByYM(field, y, m, approx) {
$('#' + field + '_m').val(m == 0 ? '' : m);
$('#' + field + '_y').val(y == '0000' ? '' : y);
$('#' + field + '_approx_aprx').val(approx).change();
}
function setDateByDate(field, date, approx) {
var d = date.substring(8, 10);
var m = date.substring(5, 7);
var y = date.substring(0, 4);
$('#' + field + '_d').val(d == 0 ? '' : d);
$('#' + field + '_m').val(m == 0 ? '' : m);
$('#' + field + '_y').val(y == 0 ? '' : y);
$('#' + field + '_approx_aprx').val(approx).change();
}
function fillFields(nid) {
var i = 0;
$('#did').val(vdata[nid][i++]);
$('#num').val(vdata[nid][i++]);
$('#gos').val(vdata[nid][i++]);
$('#nu2').val(vdata[nid][i++]);
$('#mid').val(vdata[nid][i++]);
$('#mname').val(vdata[nid][i++]);
$('#chid').val(vdata[nid][i++]);
$('#chname').val(vdata[nid][i++]);
$('#service').val(vdata[nid][i++]).change();
$('#state').val(vdata[nid][i++]).change();
$('#zn').val(vdata[nid][i++]);
$('#cn').val(vdata[nid][i++]);
$('#vin').val(vdata[nid][i++]);
setDateByYM('built', vdata[nid][i + 1], vdata[nid][i], vdata[nid][i + 2]);
i += 3;
setDateByYM('scrap', vdata[nid][i + 1], vdata[nid][i], vdata[nid][i + 2]);
i += 3;
setDateByDate('start', vdata[nid][i], vdata[nid][i + 1]);
i += 2;
setDateByDate('launc', vdata[nid][i], vdata[nid][i + 1]);
i += 2;
setDateByDate('haltd', vdata[nid][i], vdata[nid][i + 1]);
i += 2;
setDateByDate('leave', vdata[nid][i], vdata[nid][i + 1]);
i += 2;
$('#note').val(vdata[nid][i++]);
$('#history').val(vdata[nid][i++]);
}
</script>
</tr>
<tr>
<td></td>
<td>
<br>
<input type="submit" value="&nbsp; &nbsp; &nbsp; Отправить &nbsp; &nbsp; &nbsp;">
</td>
</tr>
</tbody>
</table>
</div>
</form>
<div><a href="vehicles.php?cid=14&amp;type=2&amp;mid=632">Вернуться назад</a></div><br>
<div class="p20">
<h4>Правила заполнения формы</h4>
<ul class="straight">
<li>Обязательные для заполнения поля выделены жирным шрифтом.</li>
<li>Если какие-либо данные отсутствуют, оставьте соответствующее поле пустым. Пожалуйста, не вписывайте дефис и тому подобные знаки.</li>
<li>Если требуемой модели нет в списке укажите её в поле «Примечание». После публикации фотографии модель будет добавлена в список.</li>
<li>Если Вы обладаете информацией о приписке данного ТС, а поле «Депо/Парк» отсутствует, укажите эти данные в поле «Примечание».</li>
</ul>
</div>
</td>
</tr>
<tr>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Footer.php'); ?>
</tr>
</table>
</body>
</html>

View file

@ -49,7 +49,7 @@ $vehicledatavariables = json_decode($data['content'], true);
foreach ($photos as $p) {
$author = new User($p['user_id']);
echo '<div class="p20p s11"><table><tbody><tr>
<td class="pb_photo" id="p1987895"><a href="/photo/'.$p['id'].'/ target="_blank" class="prw"><img class="f" src="/api/photo/compress?url='.$p['photourl'].'" alt="678 КБ">
<td class="pb_photo" id="p1987895"><a href="/photo/'.$p['id'].'" target="_blank" class="prw"><img class="f" src="/api/photo/compress?url='.$p['photourl'].'" alt="678 КБ">
<div class="hpshade">';
if (DB::query('SELECT COUNT(*) FROM photos_comments WHERE photo_id=:id', array(':id'=>$p['id']))[0]['COUNT(*)'] >= 1) {
echo '<div class="com-icon">'.DB::query('SELECT COUNT(*) FROM photos_comments WHERE photo_id=:id', array(':id'=>$p['id']))[0]['COUNT(*)'].'</div>';

View file

@ -0,0 +1,104 @@
<?php
use \App\Services\{Auth, DB, Date};
use \App\Models\{Vehicle, User};
?>
<!DOCTYPE html>
<html lang="ru">
<head>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/LoadHead.php'); ?>
</head>
<body>
<div id="backgr"></div>
<table class="tmain">
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Navbar.php'); ?>
<tr><td class="main">
<h1>Внесение изменений в БД</h1>
<p>На этой странице Вы можете ввести данные о Сущности, которые отсутствуют в базе данных сайта, либо требуют уточнения.<br />Информация добавляется в базу после проверки редактором.</p>
<script src="/js/jquery-ui.js?1633005526"></script>
<script src="/js/selector.js?1730197663"></script>
<form action="dbedit" id="mform" method="get" class="p20" style="float:left">
<input type="hidden" name="action" value="add">
<h4>Добавить/редактировать Сущность</h4>
<table>
<tr>
<td class="lcol">Вид сущности:</td>
<td><select name="type" id="type">
<?php
$entities = DB::query('SELECT * FROM entities');
foreach ($entities as $e) {
echo ' <option value="' . $e['id'] . '" style="background-color: ' . $e['color'] . '">' . $e['title'] . '</option>';
}
?>
</select></td>
</tr>
<tr>
<td class="lcol">
<input type="radio" name="link_gos" id="link_gos0" value="0" checked="checked">
<label for="link_gos0">ID:</label>
</td>
<td style="padding-right:10px">
<input type="text" name="num" id="num" maxlength="20" style="width:80px" value=''> &nbsp;
<input type="radio" name="link_gos" id="link_gos1" value="1">
<label for="link_gos1">Название:</label>
<input type="text" name="gos" id="gos" maxlength="20" style="width:120px" value=''>
</td>
</tr>
<tr>
<td></td>
<td><input type="submit" id="submit" style="width:100px; margin-top:15px" value="Далее &gt;&gt;" disabled="disabled"></td>
</tr>
</table>
<input type="hidden" name="mid" value="0">
</form>
<br clear="all">
<br>
<script>
function numKeyUp()
{
$('#submit').prop('disabled', $('#num').val().trim() + $('#gos').val().trim() == '');
}
function radioClick()
{
$('#num').prop('disabled', $('#link_gos1').is(':checked'));
$('#gos').prop('disabled', $('#link_gos0').is(':checked'));
}
$(document).ready(function()
{
$('#cname').citySelector('cid', { params: { with_null: true } });
$('#type').change(function() { $(this).attr('class', $('option:selected', this).attr('class')); }).change();
$('#num, #gos').on('keyup', numKeyUp);
$('input[name="link_gos"]').on('click', radioClick);
numKeyUp();
radioClick();
});
</script>
</td></tr>
<tr>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Footer.php'); ?>
</tr>
</table>
</body>
</html>

View file

@ -1,69 +0,0 @@
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mini Vidéoplayer</title>
<style>
body { font-family: Arial, sans-serif; text-align: center; }
.player { width: 60%; margin: auto; position: relative; }
video { width: 100%; display: block; }
.controls { display: flex; align-items: center; justify-content: space-between; padding: 10px; background: #333; color: white; }
.controls button { background: none; border: none; color: white; cursor: pointer; }
.progress-bar { width: 100%; height: 5px; background: gray; position: relative; cursor: pointer; }
.progress { width: 0%; height: 100%; background: red; position: absolute; }
</style>
</head>
<body>
<div class="player">
<video id="video" src="video.mp4"></video>
<div class="controls">
<button id="playPause"></button>
<input type="range" id="volume" min="0" max="1" step="0.1" value="1">
<button id="fullscreen"></button>
</div>
<div class="progress-bar" id="progressBar">
<div class="progress" id="progress"></div>
</div>
</div>
<script>
const video = document.getElementById('video');
const playPause = document.getElementById('playPause');
const volume = document.getElementById('volume');
const progressBar = document.getElementById('progressBar');
const progress = document.getElementById('progress');
const fullscreen = document.getElementById('fullscreen');
playPause.addEventListener('click', () => {
if (video.paused) {
video.play();
playPause.textContent = '⏸';
} else {
video.pause();
playPause.textContent = '▶';
}
});
volume.addEventListener('input', () => {
video.volume = volume.value;
});
video.addEventListener('timeupdate', () => {
const progressPercent = (video.currentTime / video.duration) * 100;
progress.style.width = progressPercent + '%';
});
progressBar.addEventListener('click', (e) => {
const newTime = (e.offsetX / progressBar.offsetWidth) * video.duration;
video.currentTime = newTime;
});
fullscreen.addEventListener('click', () => {
if (!document.fullscreenElement) {
video.requestFullscreen();
} else {
document.exitFullscreen();
}
});
</script>
</body>
</html>