mirror of
https://github.com/openvk/openvk
synced 2025-04-23 00:23:01 +03:00
Compare commits
5 commits
8603721bf7
...
877ce0ccbd
Author | SHA1 | Date | |
---|---|---|---|
|
877ce0ccbd | ||
|
b92bf7f41a | ||
def76226b7 | |||
|
756dcf68e3 | ||
|
153206f9ba |
60 changed files with 552 additions and 226 deletions
36
.github/workflows/analyse.yaml
vendored
Normal file
36
.github/workflows/analyse.yaml
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
name: Static analysis
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
phpstan:
|
||||
name: PHPStan
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
# 'push' runs on inner branches, 'pull_request' will run only on outer PRs
|
||||
if: >
|
||||
github.event_name == 'push'
|
||||
|| (github.event_name == 'pull_request'
|
||||
&& github.event.pull_request.head.repo.full_name != github.repository)
|
||||
|
||||
steps:
|
||||
- name: Code Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build and start Docker container
|
||||
working-directory: install/automated/docker
|
||||
run: |
|
||||
docker build -t openvk ../../.. -f openvk.Dockerfile
|
||||
|
||||
- name: Run Docker container with PHPStan
|
||||
working-directory: install/automated/docker
|
||||
run: |
|
||||
docker container run --rm \
|
||||
-v ./chandler.example.yml:/opt/chandler/chandler.yml \
|
||||
-v ./openvk.example.yml:/opt/chandler/extensions/available/openvk/openvk.yml \
|
||||
openvk vendor/bin/phpstan analyse --memory-limit 1G
|
|
@ -18,6 +18,7 @@ define("NANOTON", 1000000000);
|
|||
class FetchToncoinTransactions extends Command
|
||||
{
|
||||
private $images;
|
||||
private $transactions;
|
||||
|
||||
protected static $defaultName = "fetch-ton";
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ class Wall implements Handler
|
|||
protected $user;
|
||||
protected $posts;
|
||||
protected $notes;
|
||||
protected $videos;
|
||||
|
||||
public function __construct(?User $user)
|
||||
{
|
||||
|
|
|
@ -248,8 +248,9 @@ final class Board extends VKAPIRequestHandler
|
|||
return 1;
|
||||
}
|
||||
|
||||
public function editComment(int $comment_id, int $group_id = 0, int $topic_id = 0, string $message, string $attachments)
|
||||
public function editComment(string $message, string $attachments, int $comment_id, int $group_id = 0, int $topic_id = 0)
|
||||
{
|
||||
# FIXME
|
||||
/*
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
|
|
@ -45,7 +45,7 @@ final class Groups extends VKAPIRequestHandler
|
|||
$clbsCount = $user->getClubCount();
|
||||
}
|
||||
|
||||
$rClubs;
|
||||
$rClubs = [];
|
||||
|
||||
$ic = sizeof($clbs);
|
||||
if (sizeof($clbs) > $count) {
|
||||
|
|
|
@ -52,7 +52,7 @@ final class Newsfeed extends VKAPIRequestHandler
|
|||
return $response;
|
||||
}
|
||||
|
||||
public function getGlobal(string $fields = "", int $start_from = 0, int $start_time = 0, int $end_time = 0, int $offset = 0, int $count = 30, int $extended = 0, int $rss = 0)
|
||||
public function getGlobal(string $fields = "", int $start_from = 0, int $start_time = 0, int $end_time = 0, int $offset = 0, int $count = 30, int $extended = 0, int $rss = 0, int $return_banned = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
|
|
|
@ -185,12 +185,14 @@ final class Notes extends VKAPIRequestHandler
|
|||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
$nodez = (object) [
|
||||
"count" => 0,
|
||||
"notes" => [],
|
||||
];
|
||||
if (empty($note_ids)) {
|
||||
$nodez->count = (new NotesRepo())->getUserNotesCount($user);
|
||||
|
||||
$notes = array_slice(iterator_to_array((new NotesRepo())->getUserNotes($user, 1, $count + $offset, $sort == 0 ? "ASC" : "DESC")), $offset);
|
||||
$nodez = (object) [
|
||||
"count" => (new NotesRepo())->getUserNotesCount((new UsersRepo())->get($user_id)),
|
||||
"notes" => [],
|
||||
];
|
||||
|
||||
foreach ($notes as $note) {
|
||||
if ($note->isDeleted()) {
|
||||
|
@ -210,6 +212,7 @@ final class Notes extends VKAPIRequestHandler
|
|||
$note = (new NotesRepo())->getNoteById((int) $id[0], (int) $id[1]);
|
||||
if ($note && !$note->isDeleted()) {
|
||||
$nodez->notes[] = $note->toVkApiStruct();
|
||||
$nodez->count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use Nette\Utils\ImageException;
|
|||
use openvk\Web\Models\Entities\{Photo, Album, Comment};
|
||||
use openvk\Web\Models\Repositories\Albums;
|
||||
use openvk\Web\Models\Repositories\Photos as PhotosRepo;
|
||||
use openvk\Web\Models\Repositories\Videos as VideosRepo;
|
||||
use openvk\Web\Models\Repositories\Clubs;
|
||||
use openvk\Web\Models\Repositories\Users as UsersRepo;
|
||||
use openvk\Web\Models\Repositories\Comments as CommentsRepo;
|
||||
|
|
|
@ -292,14 +292,14 @@ final class Users extends VKAPIRequestHandler
|
|||
break;
|
||||
case 'blacklisted_by_me':
|
||||
if (!$authuser) {
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
$response[$i]->blacklisted_by_me = (int) $usr->isBlacklistedBy($this->getUser());
|
||||
break;
|
||||
case 'blacklisted':
|
||||
if (!$authuser) {
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
$response[$i]->blacklisted = (int) $this->getUser()->isBlacklistedBy($usr);
|
||||
|
@ -383,7 +383,8 @@ final class Users extends VKAPIRequestHandler
|
|||
string $fav_music = "",
|
||||
string $fav_films = "",
|
||||
string $fav_shows = "",
|
||||
string $fav_books = ""
|
||||
string $fav_books = "",
|
||||
string $interests = ""
|
||||
) {
|
||||
if ($count > 100) {
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: count should be less or equal to 100");
|
||||
|
|
|
@ -20,7 +20,7 @@ abstract class VKAPIRequestHandler
|
|||
$this->platform = $platform;
|
||||
}
|
||||
|
||||
protected function fail(int $code, string $message): void
|
||||
protected function fail(int $code, string $message): never
|
||||
{
|
||||
throw new APIErrorException($message, $code);
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
$this->fail(15, "Access denied: wall is disabled");
|
||||
} // Don't search for logic here pls
|
||||
|
||||
$iteratorv;
|
||||
$iteratorv = null;
|
||||
|
||||
switch ($filter) {
|
||||
case "all":
|
||||
|
@ -722,7 +722,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
$post->attach($attachment);
|
||||
}
|
||||
|
||||
if ($wall > 0 && $wall !== $this->user->identity->getId()) {
|
||||
if ($owner_id > 0 && $owner_id !== $this->user->identity->getId()) {
|
||||
(new WallPostNotification($wallOwner, $post, $this->user->identity))->emit();
|
||||
}
|
||||
|
||||
|
@ -734,7 +734,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$postArray;
|
||||
$postArray = [];
|
||||
if (preg_match('/(wall|video|photo)((?:-?)[0-9]+)_([0-9]+)/', $object, $postArray) == 0) {
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: object is incorrect");
|
||||
}
|
||||
|
|
|
@ -351,7 +351,7 @@ class Document extends Media
|
|||
return $this->getRecord()->owner;
|
||||
}
|
||||
|
||||
public function toApiPreview(): object
|
||||
public function toApiPreview(): ?object
|
||||
{
|
||||
$preview = $this->getPreview();
|
||||
if ($preview instanceof Photo) {
|
||||
|
@ -360,6 +360,8 @@ class Document extends Media
|
|||
"sizes" => array_values($preview->getVkApiSizes()),
|
||||
],
|
||||
];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -112,7 +112,6 @@ class Gift extends RowModel
|
|||
|
||||
public function setImage(string $file): bool
|
||||
{
|
||||
$imgBlob;
|
||||
try {
|
||||
$image = Image::fromFile($file);
|
||||
$image->resize(512, 512, Image::SHRINK_ONLY);
|
||||
|
|
|
@ -33,6 +33,8 @@ class Message extends RowModel
|
|||
return (new Users())->get($this->getRecord()->sender_id);
|
||||
} elseif ($this->getRecord()->sender_type === 'openvk\Web\Models\Entities\Club') {
|
||||
return (new Clubs())->get($this->getRecord()->sender_id);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,6 +51,8 @@ class Message extends RowModel
|
|||
return (new Users())->get($this->getRecord()->recipient_id);
|
||||
} elseif ($this->getRecord()->recipient_type === 'openvk\Web\Models\Entities\Club') {
|
||||
return (new Clubs())->get($this->getRecord()->recipient_id);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,7 +151,7 @@ class Message extends RowModel
|
|||
"id" => $author->getId(),
|
||||
"link" => $_SERVER['REQUEST_SCHEME'] . "://" . $_SERVER['HTTP_HOST'] . $author->getURL(),
|
||||
"avatar" => $author->getAvatarUrl(),
|
||||
"name" => $author->getFirstName() . $unreadmsg,
|
||||
"name" => $author->getFirstName(),
|
||||
],
|
||||
"timing" => [
|
||||
"sent" => (string) $this->getSendTimeHumanized(),
|
||||
|
|
|
@ -64,13 +64,15 @@ class Notification
|
|||
return $this->recipient;
|
||||
}
|
||||
|
||||
public function getModel(int $index): RowModel
|
||||
public function getModel(int $index): ?RowModel
|
||||
{
|
||||
switch ($index) {
|
||||
case 0:
|
||||
return $this->originModel;
|
||||
case 1:
|
||||
return $this->targetModel;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -385,9 +385,9 @@ class Photo extends Media
|
|||
}
|
||||
}
|
||||
|
||||
public static function fastMake(int $owner, string $description = "", array $file, ?Album $album = null, bool $anon = false): Photo
|
||||
public static function fastMake(int $owner, string $description, array $file, ?Album $album = null, bool $anon = false): Photo
|
||||
{
|
||||
$photo = new static();
|
||||
$photo = new Photo();
|
||||
$photo->setOwner($owner);
|
||||
$photo->setDescription(iconv_substr($description, 0, 36) . "...");
|
||||
$photo->setAnonymous($anon);
|
||||
|
|
|
@ -45,11 +45,7 @@ class Report extends RowModel
|
|||
|
||||
public function isDeleted(): bool
|
||||
{
|
||||
if ($this->getRecord()->deleted === 0) {
|
||||
return false;
|
||||
} elseif ($this->getRecord()->deleted === 1) {
|
||||
return true;
|
||||
}
|
||||
return $this->getRecord()->deleted === 1;
|
||||
}
|
||||
|
||||
public function authorId(): int
|
||||
|
|
|
@ -558,6 +558,7 @@ class User extends RowModel
|
|||
"poster",
|
||||
"apps",
|
||||
"docs",
|
||||
"fave",
|
||||
],
|
||||
])->get($id);
|
||||
}
|
||||
|
@ -932,6 +933,7 @@ class User extends RowModel
|
|||
case 1:
|
||||
return tr('female');
|
||||
case 2:
|
||||
default:
|
||||
return tr('neutral');
|
||||
}
|
||||
}
|
||||
|
@ -1195,6 +1197,7 @@ class User extends RowModel
|
|||
"poster",
|
||||
"apps",
|
||||
"docs",
|
||||
"fave",
|
||||
],
|
||||
])->set($id, (int) $status)->toInteger();
|
||||
|
||||
|
@ -1559,14 +1562,14 @@ class User extends RowModel
|
|||
break;
|
||||
case "blacklisted_by_me":
|
||||
if (!$user) {
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
$res->blacklisted_by_me = (int) $this->isBlacklistedBy($user);
|
||||
break;
|
||||
case "blacklisted":
|
||||
if (!$user) {
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
$res->blacklisted = (int) $user->isBlacklistedBy($this);
|
||||
|
|
|
@ -9,12 +9,13 @@ use openvk\Web\Util\Shell\Exceptions\{ShellUnavailableException, UnknownCommandE
|
|||
use openvk\Web\Models\VideoDrivers\VideoDriver;
|
||||
use Nette\InvalidStateException as ISE;
|
||||
|
||||
define("VIDEOS_FRIENDLY_ERROR", "Uploads are disabled on this instance :<", false);
|
||||
define("VIDEOS_FRIENDLY_ERROR", "Uploads are disabled on this instance :<");
|
||||
|
||||
class Video extends Media
|
||||
{
|
||||
public const TYPE_DIRECT = 0;
|
||||
public const TYPE_EMBED = 1;
|
||||
public const TYPE_DIRECT = 0;
|
||||
public const TYPE_EMBED = 1;
|
||||
public const TYPE_UNKNOWN = -1;
|
||||
|
||||
protected $tableName = "videos";
|
||||
protected $fileExtension = "mp4";
|
||||
|
@ -108,6 +109,7 @@ class Video extends Media
|
|||
} elseif (!is_null($this->getRecord()->link)) {
|
||||
return Video::TYPE_EMBED;
|
||||
}
|
||||
return Video::TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
public function getVideoDriver(): ?VideoDriver
|
||||
|
@ -238,7 +240,7 @@ class Video extends Media
|
|||
$this->save();
|
||||
}
|
||||
|
||||
public static function fastMake(int $owner, string $name = "Unnamed Video.ogv", string $description = "", array $file, bool $unlisted = true, bool $anon = false): Video
|
||||
public static function fastMake(int $owner, string $name, string $description, array $file, bool $unlisted = true, bool $anon = false): Video
|
||||
{
|
||||
if (OPENVK_ROOT_CONF['openvk']['preferences']['videos']['disableUploading']) {
|
||||
exit(VIDEOS_FRIENDLY_ERROR);
|
||||
|
@ -269,7 +271,7 @@ class Video extends Media
|
|||
return false;
|
||||
}
|
||||
|
||||
$streams = Shell::ffprobe("-i", $path, "-show_streams", "-select_streams v", "-loglevel error")->execute($error);
|
||||
$streams = Shell::ffprobe("-i", $path, "-show_streams", "-select_streams v", "-loglevel error")->execute();
|
||||
$durations = [];
|
||||
preg_match_all('%duration=([0-9\.]++)%', $streams, $durations);
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ class ChandlerGroups
|
|||
{
|
||||
private $context;
|
||||
private $groups;
|
||||
private $members;
|
||||
private $perms;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
|
|
|
@ -91,7 +91,7 @@ class Clubs
|
|||
return (clone $this->clubs)->count('*');
|
||||
}
|
||||
|
||||
public function getPopularClubs(): \Traversable
|
||||
public function getPopularClubs(): ?\Traversable
|
||||
{
|
||||
// TODO rewrite
|
||||
|
||||
|
@ -106,6 +106,8 @@ class Clubs
|
|||
"subscriptions" => $entry["subscriptions"],
|
||||
];
|
||||
*/
|
||||
trigger_error("Clubs::getPopularClubs() is currently commented out and returns null", E_USER_WARNING);
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getWriteableClubs(int $id): \Traversable
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Repositories;
|
||||
|
||||
use openvk\Web\Models\Entities\{Messages as M, User};
|
||||
use Chandler\Database\DatabaseConnection as DB;
|
||||
use Nette\Database\Table\ActiveRow;
|
||||
|
||||
class Conversations
|
||||
{
|
||||
private $context;
|
||||
private $convos;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->context = DB::i()->getContext();
|
||||
$this->convos = $this->context->table("conversations");
|
||||
}
|
||||
|
||||
private function toConversation(?ActiveRow $ar): ?M\AbstractConversation
|
||||
{
|
||||
if (is_null($ar)) {
|
||||
return null;
|
||||
} elseif ($ar->is_pm) {
|
||||
return new M\PrivateConversation($ar);
|
||||
} else {
|
||||
return new M\Conversation($ar);
|
||||
}
|
||||
}
|
||||
|
||||
public function get(int $id): ?M\AbstractConversation
|
||||
{
|
||||
return $this->toConversation($this->convos->get($id));
|
||||
}
|
||||
|
||||
public function getConversationsByUser(User $user, int $page = 1, ?int $perPage = null): \Traversable
|
||||
{
|
||||
$rels = $this->context->table("conversation_members")->where([
|
||||
"deleted" => false,
|
||||
"user" => $user->getId(),
|
||||
])->page($page, $perPage ?? OPENVK_DEFAULT_PER_PAGE);
|
||||
foreach ($rels as $rel) {
|
||||
yield $this->get($rel->conversation);
|
||||
}
|
||||
}
|
||||
|
||||
public function getPrivateConversation(User $user, int $peer): M\PrivateConversation
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
|
@ -152,7 +152,7 @@ class Documents
|
|||
switch ($paramName) {
|
||||
case "type":
|
||||
if ($paramValue < 1 || $paramValue > 8) {
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
$result->where("type", $paramValue);
|
||||
break;
|
||||
|
|
52
Web/Models/Repositories/Faves.php
Normal file
52
Web/Models/Repositories/Faves.php
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Repositories;
|
||||
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
use openvk\Web\Models\Entities\User;
|
||||
use Nette\Database\Table\ActiveRow;
|
||||
|
||||
class Faves
|
||||
{
|
||||
private $context;
|
||||
private $likes;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->context = DatabaseConnection::i()->getContext();
|
||||
$this->likes = $this->context->table("likes");
|
||||
}
|
||||
|
||||
private function fetchLikes(User $user, string $class = 'Post')
|
||||
{
|
||||
$fetch = $this->likes->where([
|
||||
"model" => "openvk\\Web\\Models\\Entities\\" . $class,
|
||||
"origin" => $user->getRealId(),
|
||||
]);
|
||||
|
||||
return $fetch;
|
||||
}
|
||||
|
||||
public function fetchLikesSection(User $user, string $class = 'Post', int $page = 1, ?int $perPage = null): \Traversable
|
||||
{
|
||||
$perPage ??= OPENVK_DEFAULT_PER_PAGE;
|
||||
$fetch = $this->fetchLikes($user, $class)->page($page, $perPage)->order("index DESC");
|
||||
foreach ($fetch as $like) {
|
||||
$className = "openvk\\Web\\Models\\Repositories\\" . $class . "s";
|
||||
$repo = new $className();
|
||||
if (!$repo) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$entity = $repo->get($like->target);
|
||||
yield $entity;
|
||||
}
|
||||
}
|
||||
|
||||
public function fetchLikesSectionCount(User $user, string $class = 'Post')
|
||||
{
|
||||
return $this->fetchLikes($user, $class)->count();
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ use openvk\Web\Models\Entities\{User, SupportAgent};
|
|||
class SupportAgents
|
||||
{
|
||||
private $context;
|
||||
private $tickets;
|
||||
private $agents;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
|
|
|
@ -57,7 +57,7 @@ class Tickets
|
|||
{
|
||||
$requests = $this->tickets->where(["id" => $requestId])->fetch();
|
||||
if (!is_null($requests)) {
|
||||
return new Req($requests);
|
||||
return new Ticket($requests);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -255,7 +255,7 @@ final class AdminPresenter extends OpenVKPresenter
|
|||
{
|
||||
$this->warnIfNoCommerce();
|
||||
|
||||
$cat;
|
||||
$cat = null;
|
||||
$gen = false;
|
||||
if ($id !== 0) {
|
||||
$cat = $this->gifts->getCat($id);
|
||||
|
|
|
@ -34,7 +34,8 @@ final class BlobPresenter extends OpenVKPresenter
|
|||
}
|
||||
|
||||
if (isset($_SERVER["HTTP_IF_NONE_MATCH"])) {
|
||||
exit(header("HTTP/1.1 304 Not Modified"));
|
||||
header("HTTP/1.1 304 Not Modified");
|
||||
exit();
|
||||
}
|
||||
|
||||
header("Content-Type: " . mime_content_type($path));
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace openvk\Web\Presenters;
|
|||
use openvk\Web\Models\Entities\{Comment, Notifications\MentionNotification, Photo, Video, User, Topic, Post};
|
||||
use openvk\Web\Models\Entities\Notifications\CommentNotification;
|
||||
use openvk\Web\Models\Repositories\{Comments, Clubs, Videos, Photos, Audios};
|
||||
use Nette\InvalidStateException as ISE;
|
||||
|
||||
final class CommentPresenter extends OpenVKPresenter
|
||||
{
|
||||
|
|
|
@ -8,17 +8,17 @@ use openvk\Web\Models\Repositories\ContentSearchRepository;
|
|||
|
||||
final class ContentSearchPresenter extends OpenVKPresenter
|
||||
{
|
||||
private $repo;
|
||||
protected $repo;
|
||||
|
||||
public function __construct(ContentSearchRepository $repo)
|
||||
public function __construct(ContentSearchRepository $repository)
|
||||
{
|
||||
$this->repo = $repo;
|
||||
$this->repo = $repository;
|
||||
}
|
||||
|
||||
public function renderIndex(): void
|
||||
{
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
$this->template->results = $repo->find([
|
||||
$this->template->results = $this->repo->find([
|
||||
"query" => $this->postParam("query"),
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use Nette\InvalidStateException;
|
|||
use openvk\Web\Models\Entities\Notifications\ClubModeratorNotification;
|
||||
use openvk\Web\Models\Repositories\{Clubs, Users, Albums, Managers, Topics, Audios, Posts, Documents};
|
||||
use Chandler\Security\Authenticator;
|
||||
use Nette\InvalidStateException as ISE;
|
||||
|
||||
final class GroupPresenter extends OpenVKPresenter
|
||||
{
|
||||
|
@ -288,7 +289,6 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
|
||||
(new Albums())->getClubAvatarAlbum($club)->addPhoto($photo);
|
||||
} catch (ISE $ex) {
|
||||
$name = $album->getName();
|
||||
$this->flashFail("err", tr("error"), tr("error_when_uploading_photo"));
|
||||
}
|
||||
}
|
||||
|
@ -373,6 +373,7 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
public function renderDeleteAvatar(int $id)
|
||||
{
|
||||
$this->assertUserLoggedIn();
|
||||
$this->assertNoCSRF();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$club = $this->clubs->get($id);
|
||||
|
|
|
@ -93,9 +93,11 @@ final class MessengerPresenter extends OpenVKPresenter
|
|||
header("Content-Type: application/json");
|
||||
|
||||
if ($this->queryParam("act") !== "a_check") {
|
||||
exit(header("HTTP/1.1 400 Bad Request"));
|
||||
header("HTTP/1.1 400 Bad Request");
|
||||
exit();
|
||||
} elseif (!$this->queryParam("key")) {
|
||||
exit(header("HTTP/1.1 403 Forbidden"));
|
||||
header("HTTP/1.1 403 Forbidden");
|
||||
exit();
|
||||
}
|
||||
|
||||
$key = $this->queryParam("key");
|
||||
|
@ -158,7 +160,8 @@ final class MessengerPresenter extends OpenVKPresenter
|
|||
|
||||
$sel = $this->getCorrespondent($sel);
|
||||
if ($sel->getId() !== $this->user->id && !$sel->getPrivacyPermission('messages.write', $this->user->identity)) {
|
||||
exit(header("HTTP/1.1 403 Forbidden"));
|
||||
header("HTTP/1.1 403 Forbidden");
|
||||
exit();
|
||||
}
|
||||
|
||||
$cor = new Correspondence($this->user->identity, $sel);
|
||||
|
|
|
@ -151,77 +151,6 @@ final class NoSpamPresenter extends OpenVKPresenter
|
|||
$this->assertNoCSRF();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
function searchByAdditionalParams(?string $table = null, ?string $where = null, ?string $ip = null, ?string $useragent = null, ?int $ts = null, ?int $te = null, $user = null)
|
||||
{
|
||||
$db = DatabaseConnection::i()->getContext();
|
||||
if ($table && ($ip || $useragent || $ts || $te || $user)) {
|
||||
$conditions = [];
|
||||
|
||||
if ($ip) {
|
||||
$conditions[] = "`ip` REGEXP '$ip'";
|
||||
}
|
||||
if ($useragent) {
|
||||
$conditions[] = "`useragent` REGEXP '$useragent'";
|
||||
}
|
||||
if ($ts) {
|
||||
$conditions[] = "`ts` < $ts";
|
||||
}
|
||||
if ($te) {
|
||||
$conditions[] = "`ts` > $te";
|
||||
}
|
||||
if ($user) {
|
||||
$users = new Users();
|
||||
|
||||
$_user = $users->getByChandlerUser((new ChandlerUsers())->getById($user))
|
||||
?? $users->get((int) $user)
|
||||
?? $users->getByAddress($user)
|
||||
?? null;
|
||||
|
||||
if ($_user) {
|
||||
$conditions[] = "`user` = '" . $_user->getChandlerGUID() . "'";
|
||||
}
|
||||
}
|
||||
|
||||
$whereStart = "WHERE `object_table` = '$table'";
|
||||
if ($table === "profiles") {
|
||||
$whereStart .= "AND `type` = 0";
|
||||
}
|
||||
|
||||
$conditions = count($conditions) > 0 ? "AND (" . implode(" AND ", $conditions) . ")" : "";
|
||||
$response = [];
|
||||
|
||||
if ($conditions) {
|
||||
$logs = $db->query("SELECT * FROM `ChandlerLogs` $whereStart $conditions GROUP BY `object_id`, `object_model`");
|
||||
|
||||
foreach ($logs as $log) {
|
||||
$log = (new Logs())->get($log->id);
|
||||
$object = $log->getObject()->unwrap();
|
||||
|
||||
if (!$object) {
|
||||
continue;
|
||||
}
|
||||
if ($where) {
|
||||
if (str_starts_with($where, " AND")) {
|
||||
$where = substr_replace($where, "", 0, strlen(" AND"));
|
||||
}
|
||||
|
||||
$a = $db->query("SELECT * FROM `$table` WHERE $where")->fetchAll();
|
||||
foreach ($a as $o) {
|
||||
if ($object->id == $o["id"]) {
|
||||
$response[] = $object;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
$response[] = $object;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$response = [];
|
||||
$processed = 0;
|
||||
|
@ -290,7 +219,7 @@ final class NoSpamPresenter extends OpenVKPresenter
|
|||
}
|
||||
|
||||
if ($ip || $useragent || $ts || $te || $user) {
|
||||
$rows = searchByAdditionalParams($table, $where, $ip, $useragent, $ts, $te, $user);
|
||||
$rows = $this->searchByAdditionalParams($table, $where, $ip, $useragent, $ts, $te, $user);
|
||||
} else {
|
||||
if (!$where) {
|
||||
$rows = [];
|
||||
|
@ -408,4 +337,75 @@ final class NoSpamPresenter extends OpenVKPresenter
|
|||
$this->returnJson(["success" => false, "error" => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
private function searchByAdditionalParams(?string $table = null, ?string $where = null, ?string $ip = null, ?string $useragent = null, ?int $ts = null, ?int $te = null, $user = null)
|
||||
{
|
||||
$db = DatabaseConnection::i()->getContext();
|
||||
if ($table && ($ip || $useragent || $ts || $te || $user)) {
|
||||
$conditions = [];
|
||||
|
||||
if ($ip) {
|
||||
$conditions[] = "`ip` REGEXP '$ip'";
|
||||
}
|
||||
if ($useragent) {
|
||||
$conditions[] = "`useragent` REGEXP '$useragent'";
|
||||
}
|
||||
if ($ts) {
|
||||
$conditions[] = "`ts` < $ts";
|
||||
}
|
||||
if ($te) {
|
||||
$conditions[] = "`ts` > $te";
|
||||
}
|
||||
if ($user) {
|
||||
$users = new Users();
|
||||
|
||||
$_user = $users->getByChandlerUser((new ChandlerUsers())->getById($user))
|
||||
?? $users->get((int) $user)
|
||||
?? $users->getByAddress($user)
|
||||
?? null;
|
||||
|
||||
if ($_user) {
|
||||
$conditions[] = "`user` = '" . $_user->getChandlerGUID() . "'";
|
||||
}
|
||||
}
|
||||
|
||||
$whereStart = "WHERE `object_table` = '$table'";
|
||||
if ($table === "profiles") {
|
||||
$whereStart .= "AND `type` = 0";
|
||||
}
|
||||
|
||||
$conditions = count($conditions) > 0 ? "AND (" . implode(" AND ", $conditions) . ")" : "";
|
||||
$response = [];
|
||||
|
||||
if ($conditions) {
|
||||
$logs = $db->query("SELECT * FROM `ChandlerLogs` $whereStart $conditions GROUP BY `object_id`, `object_model`");
|
||||
|
||||
foreach ($logs as $log) {
|
||||
$log = (new Logs())->get($log->id);
|
||||
$object = $log->getObject()->unwrap();
|
||||
|
||||
if (!$object) {
|
||||
continue;
|
||||
}
|
||||
if ($where) {
|
||||
if (str_starts_with($where, " AND")) {
|
||||
$where = substr_replace($where, "", 0, strlen(" AND"));
|
||||
}
|
||||
|
||||
$a = $db->query("SELECT * FROM `$table` WHERE $where")->fetchAll();
|
||||
foreach ($a as $o) {
|
||||
if ($object->id == $o["id"]) {
|
||||
$response[] = $object;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
$response[] = $object;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use Chandler\MVC\SimplePresenter;
|
|||
use Chandler\Session\Session;
|
||||
use Chandler\Security\Authenticator;
|
||||
use Latte\Engine as TemplatingEngine;
|
||||
use Nette\InvalidStateException as ISE;
|
||||
use openvk\Web\Models\Entities\IP;
|
||||
use openvk\Web\Themes\Themepacks;
|
||||
use openvk\Web\Models\Repositories\{IPs, Users, APITokens, Tickets, Reports, CurrentUser, Posts};
|
||||
|
@ -74,7 +75,6 @@ abstract class OpenVKPresenter extends SimplePresenter
|
|||
protected function logInUserWithToken(): void
|
||||
{
|
||||
$header = $_SERVER["HTTP_AUTHORIZATION"] ?? "";
|
||||
$token;
|
||||
|
||||
preg_match("%Bearer (.*)$%", $header, $matches);
|
||||
$token = $matches[1] ?? "";
|
||||
|
@ -130,7 +130,7 @@ abstract class OpenVKPresenter extends SimplePresenter
|
|||
}
|
||||
|
||||
if ($throw) {
|
||||
throw new SecurityPolicyViolationException("Permission error");
|
||||
throw new ISE("Permission error");
|
||||
} else {
|
||||
$this->flashFail("err", tr("not_enough_permissions"), tr("not_enough_permissions_comment"));
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ final class SearchPresenter extends OpenVKPresenter
|
|||
case 'marital_status':
|
||||
case 'polit_views':
|
||||
if ((int) $param_value == 0) {
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
$parameters[$param_name] = $param_value;
|
||||
|
||||
|
@ -96,7 +96,7 @@ final class SearchPresenter extends OpenVKPresenter
|
|||
# дай бог работал этот case
|
||||
case 'from_me':
|
||||
if ((int) $param_value != 1) {
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
$parameters['from_me'] = $this->user->id;
|
||||
|
||||
|
|
|
@ -314,17 +314,20 @@ final class SupportPresenter extends OpenVKPresenter
|
|||
$comment = $this->comments->get($id);
|
||||
|
||||
if ($this->user->id !== $comment->getTicket()->getUser()->getId()) {
|
||||
exit(header("HTTP/1.1 403 Forbidden"));
|
||||
header("HTTP/1.1 403 Forbidden");
|
||||
exit();
|
||||
}
|
||||
|
||||
if ($mark !== 1 && $mark !== 2) {
|
||||
exit(header("HTTP/1.1 400 Bad Request"));
|
||||
header("HTTP/1.1 400 Bad Request");
|
||||
exit();
|
||||
}
|
||||
|
||||
$comment->setMark($mark);
|
||||
$comment->save();
|
||||
|
||||
exit(header("HTTP/1.1 200 OK"));
|
||||
header("HTTP/1.1 200 OK");
|
||||
exit();
|
||||
}
|
||||
|
||||
public function renderQuickBanInSupport(int $id): void
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace openvk\Web\Presenters;
|
|||
|
||||
use openvk\Web\Models\Entities\{Topic, Club, Comment, Photo, Video};
|
||||
use openvk\Web\Models\Repositories\{Topics, Clubs};
|
||||
use Nette\InvalidStateException as ISE;
|
||||
|
||||
final class TopicsPresenter extends OpenVKPresenter
|
||||
{
|
||||
|
@ -112,9 +113,6 @@ final class TopicsPresenter extends OpenVKPresenter
|
|||
$video = null;
|
||||
if ($_FILES["_pic_attachment"]["error"] === UPLOAD_ERR_OK) {
|
||||
$album = null;
|
||||
if ($wall > 0 && $wall === $this->user->id) {
|
||||
$album = (new Albums())->getUserWallAlbum($wallOwner);
|
||||
}
|
||||
|
||||
$photo = Photo::fastMake($this->user->id, $this->postParam("text"), $_FILES["_pic_attachment"], $album);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use openvk\Web\Util\Sms;
|
|||
use openvk\Web\Themes\Themepacks;
|
||||
use openvk\Web\Models\Entities\{Photo, Post, EmailChangeVerification};
|
||||
use openvk\Web\Models\Entities\Notifications\{CoinsTransferNotification, RatingUpNotification};
|
||||
use openvk\Web\Models\Repositories\{Users, Clubs, Albums, Videos, Notes, Vouchers, EmailChangeVerifications, Audios};
|
||||
use openvk\Web\Models\Repositories\{Users, Clubs, Albums, Videos, Notes, Vouchers, EmailChangeVerifications, Audios, Faves};
|
||||
use openvk\Web\Models\Exceptions\InvalidUserNameException;
|
||||
use openvk\Web\Util\Validator;
|
||||
use Chandler\Security\Authenticator;
|
||||
|
@ -474,6 +474,7 @@ final class UserPresenter extends OpenVKPresenter
|
|||
public function renderDeleteAvatar()
|
||||
{
|
||||
$this->assertUserLoggedIn();
|
||||
$this->assertNoCSRF();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$avatar = $this->user->identity->getAvatarPhoto();
|
||||
|
@ -666,6 +667,7 @@ final class UserPresenter extends OpenVKPresenter
|
|||
"menu_standardo" => "poster",
|
||||
"menu_aplikoj" => "apps",
|
||||
"menu_doxc" => "docs",
|
||||
"menu_feva" => "fave",
|
||||
];
|
||||
foreach ($settings as $checkbox => $setting) {
|
||||
$user->setLeftMenuItemStatus($setting, $this->checkbox($checkbox));
|
||||
|
@ -942,4 +944,65 @@ final class UserPresenter extends OpenVKPresenter
|
|||
$this->redirect("/settings");
|
||||
}
|
||||
}
|
||||
|
||||
public function renderFave(): void
|
||||
{
|
||||
$this->assertUserLoggedIn();
|
||||
|
||||
$page = (int) ($this->queryParam("p") ?? 1);
|
||||
$section = $this->queryParam("section") ?? "posts";
|
||||
$display_section = "posts";
|
||||
$data = null;
|
||||
$count = 0;
|
||||
|
||||
switch ($section) {
|
||||
default:
|
||||
$this->notFound();
|
||||
break;
|
||||
case 'wall':
|
||||
case 'post':
|
||||
case 'posts':
|
||||
$data = (new Faves())->fetchLikesSection($this->user->identity, 'Post', $page);
|
||||
$count = (new Faves())->fetchLikesSectionCount($this->user->identity, 'Post');
|
||||
$display_section = "posts";
|
||||
break;
|
||||
case 'comment':
|
||||
case 'comments':
|
||||
$data = (new Faves())->fetchLikesSection($this->user->identity, 'Comment', $page);
|
||||
$count = (new Faves())->fetchLikesSectionCount($this->user->identity, 'Comment');
|
||||
$display_section = "comments";
|
||||
break;
|
||||
case 'photo':
|
||||
case 'photos':
|
||||
$data = (new Faves())->fetchLikesSection($this->user->identity, 'Photo', $page);
|
||||
$count = (new Faves())->fetchLikesSectionCount($this->user->identity, 'Photo');
|
||||
$display_section = "photos";
|
||||
break;
|
||||
case 'video':
|
||||
case 'videos':
|
||||
$data = (new Faves())->fetchLikesSection($this->user->identity, 'Video', $page);
|
||||
$count = (new Faves())->fetchLikesSectionCount($this->user->identity, 'Video');
|
||||
$display_section = "videos";
|
||||
break;
|
||||
}
|
||||
|
||||
$this->template->data = iterator_to_array($data);
|
||||
$this->template->count = $count;
|
||||
$this->template->page = $page;
|
||||
$this->template->perPage = OPENVK_DEFAULT_PER_PAGE;
|
||||
$this->template->section = $display_section;
|
||||
|
||||
$this->template->paginatorConf = (object) [
|
||||
"page" => $page,
|
||||
"count" => $count,
|
||||
"amount" => sizeof($this->template->data),
|
||||
"perPage" => $this->template->perPage,
|
||||
"atBottom" => false,
|
||||
"tidy" => true,
|
||||
'pageCount' => ceil($count / $this->template->perPage),
|
||||
];
|
||||
$this->template->extendedPaginatorConf = clone $this->template->paginatorConf;
|
||||
$this->template->extendedPaginatorConf->space = 11;
|
||||
$this->template->paginatorConf->atTop = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -273,7 +273,7 @@ final class VKAPIPresenter extends OpenVKPresenter
|
|||
}
|
||||
}
|
||||
|
||||
define("VKAPI_DECL_VER", $this->requestParam("v") ?? "4.100", false);
|
||||
define("VKAPI_DECL_VER", $this->requestParam("v") ?? "4.100");
|
||||
|
||||
try {
|
||||
$res = $handler->{$method}(...$params);
|
||||
|
|
|
@ -265,8 +265,11 @@ final class WallPresenter extends OpenVKPresenter
|
|||
$this->assertUserLoggedIn();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$wallOwner = ($wall > 0 ? (new Users())->get($wall) : (new Clubs())->get($wall * -1))
|
||||
?? $this->flashFail("err", tr("failed_to_publish_post"), tr("error_4"));
|
||||
$wallOwner = ($wall > 0 ? (new Users())->get($wall) : (new Clubs())->get($wall * -1));
|
||||
|
||||
if ($wallOwner === null) {
|
||||
$this->flashFail("err", tr("failed_to_publish_post"), tr("error_4"));
|
||||
}
|
||||
|
||||
if ($wallOwner->isBanned()) {
|
||||
$this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
|
@ -568,8 +571,11 @@ final class WallPresenter extends OpenVKPresenter
|
|||
}
|
||||
$user = $this->user->id;
|
||||
|
||||
$wallOwner = ($wall > 0 ? (new Users())->get($wall) : (new Clubs())->get($wall * -1))
|
||||
?? $this->flashFail("err", tr("failed_to_delete_post"), tr("error_4"));
|
||||
$wallOwner = ($wall > 0 ? (new Users())->get($wall) : (new Clubs())->get($wall * -1));
|
||||
|
||||
if ($wallOwner === null) {
|
||||
$this->flashFail("err", tr("failed_to_delete_post"), tr("error_4"));
|
||||
}
|
||||
|
||||
if ($wallOwner->isBanned()) {
|
||||
$this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
|
|
|
@ -198,10 +198,11 @@
|
|||
</a>
|
||||
<a href="/settings" class="link">{_my_settings}</a>
|
||||
|
||||
{if $thisUser->getLeftMenuItemStatus('docs') || $thisUser->getLeftMenuItemStatus('apps')}
|
||||
{if $thisUser->getLeftMenuItemStatus('docs') || $thisUser->getLeftMenuItemStatus('apps') || $thisUser->getLeftMenuItemStatus('fave')}
|
||||
<div class="menu_divider"></div>
|
||||
<a n:if="$thisUser->getLeftMenuItemStatus('apps')" href="/apps?act=installed" class="link">{_apps}</a>
|
||||
<a n:if="$thisUser->getLeftMenuItemStatus('docs')" href="/docs" class="link">{_my_documents}</a>
|
||||
<a n:if="$thisUser->getLeftMenuItemStatus('fave')" href="/fave" class="link">{_bookmarks_tab}</a>
|
||||
{/if}
|
||||
|
||||
{var $canAccessAdminPanel = $thisUser->getChandlerUser()->can("access")->model("admin")->whichBelongsTo(NULL)}
|
||||
|
|
80
Web/Presenters/templates/User/Fave.xml
Normal file
80
Web/Presenters/templates/User/Fave.xml
Normal file
|
@ -0,0 +1,80 @@
|
|||
{extends "../@layout.xml"}
|
||||
|
||||
{block title}{_bookmarks_tab}{/block}
|
||||
|
||||
{block header}
|
||||
{_bookmarks_tab}
|
||||
{/block}
|
||||
|
||||
{block wrap}
|
||||
<div class="wrap2">
|
||||
<div class="wrap1">
|
||||
<div class="page_wrap">
|
||||
<div class='summaryBar summaryBarFlex padding'>
|
||||
<div class='summary'>
|
||||
<b>{tr("faves", $count)} {*tr("showing_x_y", $page, $count)*}</b>
|
||||
</div>
|
||||
|
||||
{include "../components/paginator.xml", conf => $paginatorConf}
|
||||
</div>
|
||||
|
||||
<div class='page_wrap_content' id='search_page'>
|
||||
<div n:class='page_wrap_content_main, scroll_container, ($section == "photos" && $count > 0) ? album-flex'>
|
||||
<style>
|
||||
.scroll_node:first-of-type .comment {
|
||||
border-top: unset;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.scroll_node:last-of-type .post {
|
||||
border-bottom: unset;
|
||||
}
|
||||
|
||||
.content_page_error {
|
||||
min-height: 400px;
|
||||
}
|
||||
</style>
|
||||
{if $count > 0}
|
||||
{foreach $data as $dat}
|
||||
{if $section == "posts"}
|
||||
<div class="scroll_node">
|
||||
{include "../components/post.xml", post => $dat, commentSection => true}
|
||||
</div>
|
||||
{elseif $section == "comments"}
|
||||
<div class="scroll_node">
|
||||
{include "../components/comment.xml", comment => $dat, correctLink => true, no_reply_button => true}
|
||||
</div>
|
||||
{elseif $section == "photos"}
|
||||
<div class="album-photo scroll_node" onclick="OpenMiniature(event, {$dat->getURLBySizeId('larger')}, null, {$dat->getPrettyId()}, null)">
|
||||
<a href="/photo{$dat->getPrettyId()}">
|
||||
<img class="album-photo--image" src="{$dat->getURLBySizeId('tinier')}" alt="{$dat->getDescription()}" loading="lazy" />
|
||||
</a>
|
||||
</div>
|
||||
{elseif $section == "videos"}
|
||||
<div class="scroll_node">
|
||||
{include "../components/video.xml", video => $dat}
|
||||
</div>
|
||||
{/if}
|
||||
{/foreach}
|
||||
{else}
|
||||
{include "../components/content_error.xml", description => tr("faves_".$section."_empty_tip")}
|
||||
{/if}
|
||||
</div>
|
||||
<div class='page_wrap_content_options verticalGrayTabsWrapper'>
|
||||
<div class="page_wrap_content_options_list verticalGrayTabs with_padding">
|
||||
<a n:attr="id => $section === 'posts' ? 'used'" href="/fave?section=posts">{_s_posts}</a>
|
||||
<a n:attr="id => $section === 'comments' ? 'used'" href="/fave?section=comments">{_s_comments}</a>
|
||||
<a n:attr="id => $section === 'photos' ? 'used'" href="/fave?section=photos">{_s_photos}</a>
|
||||
<a n:attr="id => $section === 'videos' ? 'used'" href="/fave?section=videos">{_s_videos}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div n:if='$paginatorConf->pageCount > 1' class='page_content_paginator_bottom'>
|
||||
{include "../components/paginator.xml", conf => $extendedPaginatorConf}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
|
@ -696,6 +696,17 @@
|
|||
<span class="nobold">{_my_documents}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="120" valign="top" align="right" align="right">
|
||||
<input
|
||||
n:attr="checked => $user->getLeftMenuItemStatus('fave')"
|
||||
type="checkbox"
|
||||
name="menu_feva" />
|
||||
</td>
|
||||
<td>
|
||||
<span class="nobold">{_bookmarks_tab}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr n:if="sizeof(OPENVK_ROOT_CONF['openvk']['preferences']['menu']['links']) > 0">
|
||||
<td width="120" valign="top" align="right" align="right">
|
||||
<input
|
||||
|
|
|
@ -458,7 +458,8 @@
|
|||
</tr>
|
||||
<tr n:if="!is_null($user->getBirthday())">
|
||||
<td class="label"><span class="nobold">{_birth_date}:</span></td>
|
||||
<td n:if="$user->getBirthdayPrivacy() == 0" class="data">{$user->getBirthday()->format('%e %B %Y')},
|
||||
<td n:if="$user->getBirthdayPrivacy() == 0 && $user->onlineStatus() == 2" class="data">{$user->getBirthday()->format('%e %B %Y')}</td>
|
||||
<td n:if="$user->getBirthdayPrivacy() == 0 && $user->onlineStatus() != 2" class="data">{$user->getBirthday()->format('%e %B %Y')},
|
||||
{tr("years", $user->getAge())}</td>
|
||||
<td n:if="$user->getBirthdayPrivacy() == 1" class="data">{$user->getBirthday()->format('%e %B')}</td>
|
||||
</tr>
|
||||
|
|
|
@ -60,8 +60,9 @@
|
|||
<a href="javascript:reportComment({$comment->getId()})">{_report}</a>
|
||||
{/if}
|
||||
<div style="float: right; font-size: .7rem;">
|
||||
{var $isLiked = $comment->hasLikeFrom($thisUser)}
|
||||
<a class="post-like-button" href="/comment{$comment->getId()}/like?hash={rawurlencode($csrfToken)}" data-likes='{$likesCount}' data-id="1_{$comment->getPrettyId()}" data-type='comment'>
|
||||
<div class="heart" style="{if $comment->hasLikeFrom($thisUser)}opacity: 1;{else}opacity: 0.4;{/if}"></div>
|
||||
<div class="heart" n:attr="id => $isLiked ? liked" style="{if $isLiked}opacity: 1;{else}opacity: 0.4;{/if}"></div>
|
||||
<span class="likeCnt">{if $likesCount > 0}{$likesCount}{/if}</span>
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
@ -128,6 +128,6 @@ class Themepack
|
|||
throw new Exceptions\IncompatibleThemeException("Theme is built for newer OVK (themeEngine" . $manifest->openvk_version . ")");
|
||||
}
|
||||
|
||||
return new static($manifest->id, $manifest->version, (bool) ($manifest->inherit_master ?? true), (bool) ($manifest->override_templates ?? false), (bool) ($manifest->enabled ?? true), (object) $manifest->metadata);
|
||||
return new Themepack($manifest->id, $manifest->version, (bool) ($manifest->inherit_master ?? true), (bool) ($manifest->override_templates ?? false), (bool) ($manifest->enabled ?? true), (object) $manifest->metadata);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,25 +88,6 @@ class Themepacks implements \ArrayAccess
|
|||
|
||||
/* /ArrayAccess */
|
||||
|
||||
public function install(string $archivePath): bool
|
||||
{
|
||||
if (!file_exists($archivePath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$tmpDir = mkdir(tempnam(OPENVK_ROOT . "/tmp/themepack_artifacts/", "themex_"));
|
||||
try {
|
||||
$archive = new \CabArchive($archivePath);
|
||||
$archive->extract($tmpDir);
|
||||
|
||||
return $this->installUnpacked($tmpDir);
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
} finally {
|
||||
rmdir($tmpDir);
|
||||
}
|
||||
}
|
||||
|
||||
public function uninstall(string $id): bool
|
||||
{
|
||||
if (!isset($loadedThemepacks[$id])) {
|
||||
|
|
|
@ -78,7 +78,7 @@ class Bitmask
|
|||
} elseif (gettype($key) === "int") {
|
||||
$this->setByOffset($key, $data);
|
||||
} else {
|
||||
throw new TypeError("Key must be either offset (int) or a string index");
|
||||
throw new \TypeError("Key must be either offset (int) or a string index");
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
@ -89,7 +89,7 @@ class Bitmask
|
|||
if (gettype($key) === "string") {
|
||||
$key = $this->getOffsetByKey($key);
|
||||
} elseif (gettype($key) !== "int") {
|
||||
throw new TypeError("Key must be either offset (int) or a string index");
|
||||
throw new \TypeError("Key must be either offset (int) or a string index");
|
||||
}
|
||||
|
||||
return $this->length === 1 ? $this->getBoolByOffset($key) : $this->getNumberByOffset($key);
|
||||
|
|
|
@ -66,6 +66,7 @@ class DateTime
|
|||
case static::RELATIVE_FORMAT_LOWER:
|
||||
return $this->zmdate();
|
||||
case static::RELATIVE_FORMAT_SHORT:
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -188,9 +188,9 @@ class Makima
|
|||
|
||||
$tries = [];
|
||||
|
||||
$firstLine;
|
||||
$secondLine;
|
||||
$thirdLine;
|
||||
$firstLine = null;
|
||||
$secondLine = null;
|
||||
$thirdLine = null;
|
||||
|
||||
# Try one line:
|
||||
$tries[$firstLine = $count] = [$this->calculateMultiThumbsHeight($ratiosCropped, $maxWidth, $marginWidth)];
|
||||
|
@ -234,7 +234,7 @@ class Makima
|
|||
}
|
||||
}
|
||||
|
||||
if (!$optimalConfiguration || $confDigff < $optimalDifference) {
|
||||
if (!$optimalConfiguration || $confDiff < $optimalDifference) {
|
||||
$optimalConfiguration = $config;
|
||||
$optimalDifference = $confDiff;
|
||||
}
|
||||
|
|
|
@ -54,5 +54,6 @@ services:
|
|||
- openvk\Web\Models\Repositories\BannedLinks
|
||||
- openvk\Web\Models\Repositories\ChandlerGroups
|
||||
- openvk\Web\Models\Repositories\Documents
|
||||
- openvk\Web\Models\Repositories\Faves
|
||||
- openvk\Web\Presenters\MaintenancePresenter
|
||||
- openvk\Web\Presenters\NoSpamPresenter
|
||||
|
|
|
@ -413,6 +413,8 @@ routes:
|
|||
handler: "InternalAPI->getPostTemplate"
|
||||
- url: "/tour"
|
||||
handler: "About->tour"
|
||||
- url: "/fave"
|
||||
handler: "User->fave"
|
||||
- url: "/{?shortCode}"
|
||||
handler: "UnknownTextRouteStrategy->delegate"
|
||||
placeholders:
|
||||
|
|
|
@ -478,8 +478,8 @@ return (function () {
|
|||
define('YEAR', 365 * DAY);
|
||||
|
||||
define("nullptr", null);
|
||||
define("OPENVK_DEFAULT_INSTANCE_NAME", "OpenVK", false);
|
||||
define("OPENVK_VERSION", "Altair Preview ($ver)", false);
|
||||
define("OPENVK_DEFAULT_PER_PAGE", 10, false);
|
||||
define("__OPENVK_ERROR_CLOCK_IN_FUTURE", "Server clock error: FK1200-DTF", false);
|
||||
define("OPENVK_DEFAULT_INSTANCE_NAME", "OpenVK");
|
||||
define("OPENVK_VERSION", "Altair Preview ($ver)");
|
||||
define("OPENVK_DEFAULT_PER_PAGE", 10);
|
||||
define("__OPENVK_ERROR_CLOCK_IN_FUTURE", "Server clock error: FK1200-DTF");
|
||||
});
|
||||
|
|
10
chandler_loader.php
Normal file
10
chandler_loader.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk;
|
||||
|
||||
$_SERVER["HTTP_ACCEPT_LANGUAGE"] = false;
|
||||
$bootstrap = require(__DIR__ . "/../../../chandler/Bootstrap.php");
|
||||
$bootstrap->ignite(true);
|
|
@ -1,7 +1,8 @@
|
|||
{
|
||||
"scripts": {
|
||||
"fix": "php-cs-fixer fix",
|
||||
"lint": "php-cs-fixer fix --dry-run --diff --verbose"
|
||||
"lint": "php-cs-fixer fix --dry-run --diff --verbose",
|
||||
"analyse": "phpstan analyse --memory-limit 1G"
|
||||
},
|
||||
"require": {
|
||||
"php": "~7.3||~8.1",
|
||||
|
@ -28,6 +29,7 @@
|
|||
},
|
||||
"minimum-stability": "beta",
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.68"
|
||||
"friendsofphp/php-cs-fixer": "^3.68",
|
||||
"phpstan/phpstan": "^2.1"
|
||||
}
|
||||
}
|
||||
|
|
60
composer.lock
generated
60
composer.lock
generated
|
@ -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": "b92d2ddd207f394a31c429c65d1785a7",
|
||||
"content-hash": "fe88a04383a75cc5c6591abac3128201",
|
||||
"packages": [
|
||||
{
|
||||
"name": "al/emoji-detector",
|
||||
|
@ -3092,6 +3092,64 @@
|
|||
],
|
||||
"time": "2025-01-30T17:00:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "2.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "7d08f569e582ade182a375c366cbd896eccadd3a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/7d08f569e582ade182a375c366cbd896eccadd3a",
|
||||
"reference": "7d08f569e582ade182a375c366cbd896eccadd3a",
|
||||
"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-01-21T14:54:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/event-dispatcher",
|
||||
"version": "1.0.0",
|
||||
|
|
|
@ -641,6 +641,8 @@
|
|||
"my_feed" = "My Feed";
|
||||
"my_feedback" = "My Feedback";
|
||||
"my_settings" = "My Settings";
|
||||
"bookmarks" = "Bookmarks";
|
||||
"bookmarks_tab" = "Saved";
|
||||
"bug_tracker" = "Bug Tracker";
|
||||
|
||||
"menu_settings" = "Settings";
|
||||
|
@ -2113,6 +2115,7 @@
|
|||
"s_apps" = "Applications";
|
||||
"s_posts" = "Posts";
|
||||
"s_comments" = "Comments";
|
||||
"s_photos" = "Photos";
|
||||
"s_videos" = "Videos";
|
||||
"s_audios" = "Music";
|
||||
"s_audios_playlists" = "Playlists";
|
||||
|
@ -2385,3 +2388,17 @@
|
|||
"select_doc" = "Attach document";
|
||||
"no_documents" = "No documents found";
|
||||
"go_to_my_documents" = "Go to own documents";
|
||||
|
||||
/* Fave */
|
||||
|
||||
"faves" = "Bookmarks";
|
||||
"faves_empty_tip" = "There will be your liked content.";
|
||||
"faves_posts_empty_tip" = "There will be posts liked by you.";
|
||||
"faves_comments_empty_tip" = "There will be comments liked by you.";
|
||||
"faves_photos_empty_tip" = "There will be photos liked by you.";
|
||||
"faves_videos_empty_tip" = "There will be videos liked by you.";
|
||||
"faves_zero" = "No bookmarks";
|
||||
"faves_one" = "One bookmark";
|
||||
"faves_few" = "$1 bookmarks";
|
||||
"faves_many" = "$1 bookmarks";
|
||||
"faves_other" = "$1 bookmarks";
|
||||
|
|
|
@ -624,6 +624,8 @@
|
|||
"my_feed" = "Мои Новости";
|
||||
"my_feedback" = "Мои Ответы";
|
||||
"my_settings" = "Мои Настройки";
|
||||
"bookmarks" = "Закладки";
|
||||
"bookmarks_tab" = "Избранное";
|
||||
"bug_tracker" = "Баг-трекер";
|
||||
|
||||
"menu_settings" = "Настройки";
|
||||
|
@ -2008,6 +2010,7 @@
|
|||
"s_apps" = "Приложения";
|
||||
"s_posts" = "Записи";
|
||||
"s_comments" = "Комментарии";
|
||||
"s_photos" = "Фотографии";
|
||||
"s_videos" = "Видео";
|
||||
"s_audios" = "Аудио";
|
||||
"s_audios_playlists" = "Плейлисты";
|
||||
|
@ -2280,3 +2283,17 @@
|
|||
"select_doc" = "Выбор документа";
|
||||
"no_documents" = "Документов нет";
|
||||
"go_to_my_documents" = "Перейти к своим документам";
|
||||
|
||||
/* Fave */
|
||||
|
||||
"faves" = "Закладки";
|
||||
"faves_empty_tip" = "Здесь будет отображаться понравившийся Вам контент...";
|
||||
"faves_posts_empty_tip" = "Здесь будут отображаться понравившиеся Вам записи.";
|
||||
"faves_comments_empty_tip" = "Здесь будут отображаться понравившиеся Вам комментарии.";
|
||||
"faves_photos_empty_tip" = "Здесь будут отображаться понравившиеся Вам фотографии.";
|
||||
"faves_videos_empty_tip" = "Здесь будут отображаться понравившиеся Вам видео.";
|
||||
"faves_zero" = "Ни одной закладки"; /* на украинском можно как ни одной вподобайки */
|
||||
"faves_one" = "Одна закладка";
|
||||
"faves_few" = "$1 закладки";
|
||||
"faves_many" = "$1 закладок";
|
||||
"faves_other" = "$1 закладок";
|
||||
|
|
|
@ -7,9 +7,7 @@ namespace openvk;
|
|||
|
||||
use Symfony\Component\Console\Application;
|
||||
|
||||
$_SERVER["HTTP_ACCEPT_LANGUAGE"] = false;
|
||||
$bootstrap = require(__DIR__ . "/../../../chandler/Bootstrap.php");
|
||||
$bootstrap->ignite(true);
|
||||
require(__DIR__ . "/chandler_loader.php");
|
||||
|
||||
$application = new Application();
|
||||
$application->add(new CLI\RebuildImagesCommand());
|
||||
|
|
14
phpstan.neon
Normal file
14
phpstan.neon
Normal file
|
@ -0,0 +1,14 @@
|
|||
parameters:
|
||||
level: 0
|
||||
paths:
|
||||
- CLI
|
||||
- ServiceAPI
|
||||
- VKAPI
|
||||
- Web
|
||||
- bootstrap.php
|
||||
- openvkctl
|
||||
- chandler_loader.php
|
||||
|
||||
bootstrapFiles:
|
||||
- chandler_loader.php
|
||||
- bootstrap.php
|
Loading…
Reference in a new issue