mirror of
https://github.com/openvk/openvk
synced 2025-07-03 14:29:53 +03:00
Merge branch 'master' into predictable-thumbnail-id-fix
This commit is contained in:
commit
b834f39c09
85 changed files with 1094 additions and 693 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-latest
|
||||
|
||||
# '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
|
2
.github/workflows/lint.yaml
vendored
2
.github/workflows/lint.yaml
vendored
|
@ -6,7 +6,7 @@ on:
|
|||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# 'push' runs on inner branches, 'pull_request' will run only on outer PRs
|
||||
if: >
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -18,7 +18,7 @@ final class Audio extends VKAPIRequestHandler
|
|||
if (!$audio) {
|
||||
$this->fail(0o404, "Audio not found");
|
||||
} elseif (!$audio->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(201, "Access denied to audio(" . $audio->getPrettyId() . ")");
|
||||
$this->fail(201, "Access denied to audio(" . $audio->getId() . ")");
|
||||
}
|
||||
|
||||
# рофлан ебало
|
||||
|
@ -201,7 +201,7 @@ final class Audio extends VKAPIRequestHandler
|
|||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
if ($uploaded_only) {
|
||||
if ($uploaded_only && $owner_id == $this->getUser()->getRealId()) {
|
||||
return DatabaseConnection::i()->getContext()->table("audios")
|
||||
->where([
|
||||
"deleted" => false,
|
||||
|
@ -283,7 +283,7 @@ final class Audio extends VKAPIRequestHandler
|
|||
}
|
||||
|
||||
$dbCtx = DatabaseConnection::i()->getContext();
|
||||
if ($uploaded_only == 1) {
|
||||
if ($uploaded_only == 1 && $owner_id == $this->getUser()->getRealId()) {
|
||||
if ($owner_id <= 0) {
|
||||
$this->fail(8, "uploaded_only can only be used with owner_id > 0");
|
||||
}
|
||||
|
|
|
@ -14,8 +14,7 @@ use openvk\Web\Models\Entities\{Topic, Comment, User, Photo, Video};
|
|||
|
||||
final class Board extends VKAPIRequestHandler
|
||||
{
|
||||
# 13/13
|
||||
public function addTopic(int $group_id, string $title, string $text = "", bool $from_group = true, string $attachments = "")
|
||||
public function addTopic(int $group_id, string $title, string $text = "", bool $from_group = true)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
@ -23,15 +22,14 @@ final class Board extends VKAPIRequestHandler
|
|||
$club = (new ClubsRepo())->get($group_id);
|
||||
|
||||
if (!$club) {
|
||||
$this->fail(403, "Invalid club");
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
if (!$club->canBeModifiedBy($this->getUser()) && !$club->isEveryoneCanCreateTopics()) {
|
||||
$this->fail(403, "Access to club denied");
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
$flags = 0;
|
||||
|
||||
if ($from_group == true && $club->canBeModifiedBy($this->getUser())) {
|
||||
$flags |= 0b10000000;
|
||||
}
|
||||
|
@ -53,59 +51,6 @@ final class Board extends VKAPIRequestHandler
|
|||
$comment->setCreated(time());
|
||||
$comment->setFlags($flags);
|
||||
$comment->save();
|
||||
|
||||
if (!empty($attachments)) {
|
||||
$attachmentsArr = explode(",", $attachments);
|
||||
# блин а мне это везде копировать типа
|
||||
|
||||
if (sizeof($attachmentsArr) > 10) {
|
||||
$this->fail(50, "Error: too many attachments");
|
||||
}
|
||||
|
||||
foreach ($attachmentsArr as $attac) {
|
||||
$attachmentType = null;
|
||||
|
||||
if (str_contains($attac, "photo")) {
|
||||
$attachmentType = "photo";
|
||||
} elseif (str_contains($attac, "video")) {
|
||||
$attachmentType = "video";
|
||||
} else {
|
||||
$this->fail(205, "Unknown attachment type");
|
||||
}
|
||||
|
||||
$attachment = str_replace($attachmentType, "", $attac);
|
||||
|
||||
$attachmentOwner = (int) explode("_", $attachment)[0];
|
||||
$attachmentId = (int) end(explode("_", $attachment));
|
||||
|
||||
$attacc = null;
|
||||
|
||||
if ($attachmentType == "photo") {
|
||||
$attacc = (new PhotosRepo())->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if (!$attacc || $attacc->isDeleted()) {
|
||||
$this->fail(100, "Photo does not exists");
|
||||
}
|
||||
if ($attacc->getOwner()->getId() != $this->getUser()->getId()) {
|
||||
$this->fail(43, "You do not have access to this photo");
|
||||
}
|
||||
|
||||
$comment->attach($attacc);
|
||||
} elseif ($attachmentType == "video") {
|
||||
$attacc = (new VideosRepo())->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if (!$attacc || $attacc->isDeleted()) {
|
||||
$this->fail(100, "Video does not exists");
|
||||
}
|
||||
if ($attacc->getOwner()->getId() != $this->getUser()->getId()) {
|
||||
$this->fail(43, "You do not have access to this video");
|
||||
}
|
||||
|
||||
$comment->attach($attacc);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $topic->getId();
|
||||
|
@ -118,7 +63,7 @@ final class Board extends VKAPIRequestHandler
|
|||
|
||||
$topic = (new TopicsRepo())->getTopicById($group_id, $topic_id);
|
||||
|
||||
if (!$topic || !$topic->getClub() || !$topic->getClub()->canBeModifiedBy($this->getUser())) {
|
||||
if (!$topic || !$topic->getClub()->canBeModifiedBy($this->getUser())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -140,21 +85,15 @@ final class Board extends VKAPIRequestHandler
|
|||
}
|
||||
|
||||
$topic = (new TopicsRepo())->getTopicById($group_id, $topic_id);
|
||||
|
||||
if (!$topic || $topic->isDeleted() || $topic->isClosed()) {
|
||||
$this->fail(100, "Topic is deleted, closed or invalid.");
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
$flags = 0;
|
||||
|
||||
if ($from_group != 0 && !is_null($topic->getClub()) && $topic->getClub()->canBeModifiedBy($this->user)) {
|
||||
$flags |= 0b10000000;
|
||||
}
|
||||
|
||||
if (strlen($message) > 300) {
|
||||
$this->fail(20, "Comment is too long.");
|
||||
}
|
||||
|
||||
$comment = new Comment();
|
||||
$comment->setOwner($this->getUser()->getId());
|
||||
$comment->setModel(get_class($topic));
|
||||
|
@ -164,74 +103,9 @@ final class Board extends VKAPIRequestHandler
|
|||
$comment->setFlags($flags);
|
||||
$comment->save();
|
||||
|
||||
if (!empty($attachments)) {
|
||||
$attachmentsArr = explode(",", $attachments);
|
||||
|
||||
if (sizeof($attachmentsArr) > 10) {
|
||||
$this->fail(50, "Error: too many attachments");
|
||||
}
|
||||
|
||||
foreach ($attachmentsArr as $attac) {
|
||||
$attachmentType = null;
|
||||
|
||||
if (str_contains($attac, "photo")) {
|
||||
$attachmentType = "photo";
|
||||
} elseif (str_contains($attac, "video")) {
|
||||
$attachmentType = "video";
|
||||
} else {
|
||||
$this->fail(205, "Unknown attachment type");
|
||||
}
|
||||
|
||||
$attachment = str_replace($attachmentType, "", $attac);
|
||||
|
||||
$attachmentOwner = (int) explode("_", $attachment)[0];
|
||||
$attachmentId = (int) end(explode("_", $attachment));
|
||||
|
||||
$attacc = null;
|
||||
|
||||
if ($attachmentType == "photo") {
|
||||
$attacc = (new PhotosRepo())->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if (!$attacc || $attacc->isDeleted()) {
|
||||
$this->fail(100, "Photo does not exists");
|
||||
}
|
||||
if ($attacc->getOwner()->getId() != $this->getUser()->getId()) {
|
||||
$this->fail(43, "You do not have access to this photo");
|
||||
}
|
||||
|
||||
$comment->attach($attacc);
|
||||
} elseif ($attachmentType == "video") {
|
||||
$attacc = (new VideosRepo())->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if (!$attacc || $attacc->isDeleted()) {
|
||||
$this->fail(100, "Video does not exists");
|
||||
}
|
||||
if ($attacc->getOwner()->getId() != $this->getUser()->getId()) {
|
||||
$this->fail(43, "You do not have access to this video");
|
||||
}
|
||||
|
||||
$comment->attach($attacc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $comment->getId();
|
||||
}
|
||||
|
||||
public function deleteComment(int $comment_id, int $group_id = 0, int $topic_id = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$comment = (new CommentsRepo())->get($comment_id);
|
||||
|
||||
if ($comment->isDeleted() || !$comment || !$comment->canBeDeletedBy($this->getUser())) {
|
||||
$this->fail(403, "Access to comment denied");
|
||||
}
|
||||
|
||||
$comment->delete();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function deleteTopic(int $group_id, int $topic_id)
|
||||
{
|
||||
$this->requireUser();
|
||||
|
@ -248,24 +122,6 @@ 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)
|
||||
{
|
||||
/*
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$comment = (new CommentsRepo)->get($comment_id);
|
||||
|
||||
if($comment->getOwner() != $this->getUser()->getId())
|
||||
$this->fail(15, "Access to comment denied");
|
||||
|
||||
$comment->setContent($message);
|
||||
$comment->setEdited(time());
|
||||
$comment->save();
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function editTopic(int $group_id, int $topic_id, string $title)
|
||||
{
|
||||
$this->requireUser();
|
||||
|
|
|
@ -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;
|
||||
|
@ -247,7 +248,7 @@ final class Photos extends VKAPIRequestHandler
|
|||
];
|
||||
}
|
||||
|
||||
public function createAlbum(string $title, int $group_id = 0, string $description = "", int $privacy = 0)
|
||||
public function createAlbum(string $title, int $group_id = 0, string $description = "")
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
@ -256,7 +257,7 @@ final class Photos extends VKAPIRequestHandler
|
|||
$club = (new Clubs())->get((int) $group_id);
|
||||
|
||||
if (!$club || !$club->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(20, "Invalid club");
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,162 +271,133 @@ final class Photos extends VKAPIRequestHandler
|
|||
return $album->toVkApiStruct($this->getUser());
|
||||
}
|
||||
|
||||
public function editAlbum(int $album_id, int $owner_id, string $title, string $description = "", int $privacy = 0)
|
||||
public function editAlbum(int $album_id, int $owner_id, string $title = null, string $description = null, int $privacy = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$album = (new Albums())->getAlbumByOwnerAndId($owner_id, $album_id);
|
||||
|
||||
if (!$album || $album->isDeleted()) {
|
||||
$this->fail(2, "Invalid album");
|
||||
if (!$album || $album->isDeleted() || $album->isCreatedBySystem()) {
|
||||
$this->fail(114, "Invalid album id");
|
||||
}
|
||||
|
||||
if (empty($title)) {
|
||||
$this->fail(25, "Title is empty");
|
||||
}
|
||||
|
||||
if ($album->isCreatedBySystem()) {
|
||||
$this->fail(40, "You can't change system album");
|
||||
}
|
||||
|
||||
if (!$album->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(2, "Access to album denied");
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
$album->setName($title);
|
||||
$album->setDescription($description);
|
||||
if (!is_null($title) && !empty($title) && !ctype_space($title)) {
|
||||
$album->setName($title);
|
||||
}
|
||||
if (!is_null($description)) {
|
||||
$album->setDescription($description);
|
||||
}
|
||||
|
||||
$album->save();
|
||||
try {
|
||||
$album->save();
|
||||
} catch (\Throwable $e) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return $album->toVkApiStruct($this->getUser());
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function getAlbums(int $owner_id, string $album_ids = "", int $offset = 0, int $count = 100, bool $need_system = true, bool $need_covers = true, bool $photo_sizes = false)
|
||||
public function getAlbums(int $owner_id = null, string $album_ids = "", int $offset = 0, int $count = 100, bool $need_system = true, bool $need_covers = true, bool $photo_sizes = false)
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$res = [];
|
||||
$res = [
|
||||
"count" => 0,
|
||||
"items" => [],
|
||||
];
|
||||
$albums_list = [];
|
||||
if ($owner_id == null && empty($album_ids)) {
|
||||
$owner_id = $this->getUser()->getId();
|
||||
}
|
||||
|
||||
if (empty($album_ids)) {
|
||||
$owner = get_entity_by_id($owner_id);
|
||||
if (!$owner || !$owner->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
if ($owner_id > 0 && !$owner->getPrivacyPermission('photos.read', $this->getUser())) {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
$albums_list = null;
|
||||
if ($owner_id > 0) {
|
||||
$user = (new UsersRepo())->get($owner_id);
|
||||
|
||||
$res = [
|
||||
"count" => (new Albums())->getUserAlbumsCount($user),
|
||||
"items" => [],
|
||||
];
|
||||
|
||||
if (!$user || $user->isDeleted()) {
|
||||
$this->fail(2, "Invalid user");
|
||||
}
|
||||
|
||||
if (!$user->getPrivacyPermission('photos.read', $this->getUser())) {
|
||||
$this->fail(21, "This user chose to hide his albums.");
|
||||
}
|
||||
|
||||
$albums = array_slice(iterator_to_array((new Albums())->getUserAlbums($user, 1, $count + $offset)), $offset);
|
||||
|
||||
foreach ($albums as $album) {
|
||||
if (!$need_system && $album->isCreatedBySystem()) {
|
||||
continue;
|
||||
}
|
||||
$res["items"][] = $album->toVkApiStruct($this->getUser(), $need_covers, $photo_sizes);
|
||||
}
|
||||
# TODO rewrite to offset
|
||||
$albums_list = array_slice(iterator_to_array((new Albums())->getUserAlbums($owner, 1, $count + $offset)), $offset);
|
||||
$res["count"] = (new Albums())->getUserAlbumsCount($owner);
|
||||
} else {
|
||||
$club = (new Clubs())->get($owner_id * -1);
|
||||
|
||||
$res = [
|
||||
"count" => (new Albums())->getClubAlbumsCount($club),
|
||||
"items" => [],
|
||||
];
|
||||
|
||||
if (!$club) {
|
||||
$this->fail(2, "Invalid club");
|
||||
}
|
||||
|
||||
$albums = array_slice(iterator_to_array((new Albums())->getClubAlbums($club, 1, $count + $offset)), $offset);
|
||||
|
||||
foreach ($albums as $album) {
|
||||
if (!$need_system && $album->isCreatedBySystem()) {
|
||||
continue;
|
||||
}
|
||||
$res["items"][] = $album->toVkApiStruct($this->getUser(), $need_covers, $photo_sizes);
|
||||
}
|
||||
$albums_list = array_slice(iterator_to_array((new Albums())->getClubAlbums($owner, 1, $count + $offset)), $offset);
|
||||
$res["count"] = (new Albums())->getClubAlbumsCount($owner);
|
||||
}
|
||||
|
||||
} else {
|
||||
$albums = explode(',', $album_ids);
|
||||
|
||||
$res = [
|
||||
"count" => sizeof($albums),
|
||||
"items" => [],
|
||||
];
|
||||
|
||||
foreach ($albums as $album) {
|
||||
$id = explode("_", $album);
|
||||
|
||||
$album = (new Albums())->getAlbumByOwnerAndId((int) $id[0], (int) $id[1]);
|
||||
if ($album && !$album->isDeleted()) {
|
||||
if (!$need_system && $album->isCreatedBySystem()) {
|
||||
continue;
|
||||
}
|
||||
$res["items"][] = $album->toVkApiStruct($this->getUser(), $need_covers, $photo_sizes);
|
||||
$album_ids = explode(',', $album_ids);
|
||||
foreach ($album_ids as $album_id) {
|
||||
$album = (new Albums())->getAlbumByOwnerAndId((int) $owner_id, (int) $album_id);
|
||||
if (!$album || $album->isDeleted() || !$album->canBeViewedBy($this->getUser())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$albums_list[] = $album;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($albums_list as $album) {
|
||||
if (!$need_system && $album->isCreatedBySystem()) { # TODO use queries
|
||||
continue;
|
||||
}
|
||||
|
||||
$res["items"][] = $album->toVkApiStruct($this->getUser(), $need_covers, $photo_sizes);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function getAlbumsCount(int $user_id = 0, int $group_id = 0)
|
||||
public function getAlbumsCount(int $user_id = null, int $group_id = null)
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
if ($user_id == 0 && $group_id == 0 || $user_id > 0 && $group_id > 0) {
|
||||
$this->fail(21, "Select user_id or group_id");
|
||||
if (is_null($user_id) && is_null($group_id)) {
|
||||
$user_id = $this->getUser()->getId();
|
||||
}
|
||||
|
||||
if ($user_id > 0) {
|
||||
$us = (new UsersRepo())->get($user_id);
|
||||
if (!$us || $us->isDeleted()) {
|
||||
$this->fail(21, "Invalid user");
|
||||
if (!is_null($user_id)) {
|
||||
$__user = (new UsersRepo())->get($user_id);
|
||||
if (!$__user || $__user->isDeleted() || !$__user->getPrivacyPermission('photos.read', $this->getUser())) {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
if (!$us->getPrivacyPermission('photos.read', $this->getUser())) {
|
||||
$this->fail(21, "This user chose to hide his albums.");
|
||||
return (new Albums())->getUserAlbumsCount($__user);
|
||||
}
|
||||
if (!is_null($group_id)) {
|
||||
$__club = (new Clubs())->get($group_id);
|
||||
if (!$__club || !$__club->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
return (new Albums())->getUserAlbumsCount($us);
|
||||
return (new Albums())->getClubAlbumsCount($__club);
|
||||
}
|
||||
|
||||
if ($group_id > 0) {
|
||||
$cl = (new Clubs())->get($group_id);
|
||||
if (!$cl) {
|
||||
$this->fail(21, "Invalid club");
|
||||
}
|
||||
|
||||
return (new Albums())->getClubAlbumsCount($cl);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getById(string $photos, bool $extended = false, bool $photo_sizes = false)
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$phts = explode(",", $photos);
|
||||
$photos_splitted_list = explode(",", $photos);
|
||||
$res = [];
|
||||
if (sizeof($photos_splitted_list) > 78) {
|
||||
$this->fail(-78, "Photos count must not exceed limit");
|
||||
}
|
||||
|
||||
foreach ($phts as $phota) {
|
||||
$ph = explode("_", $phota);
|
||||
$photo = (new PhotosRepo())->getByOwnerAndVID((int) $ph[0], (int) $ph[1]);
|
||||
|
||||
if (!$photo || $photo->isDeleted()) {
|
||||
$this->fail(21, "Invalid photo");
|
||||
}
|
||||
|
||||
if (!$photo->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(15, "Access denied");
|
||||
foreach ($photos_splitted_list as $photo_id) {
|
||||
$photo_s_id = explode("_", $photo_id);
|
||||
$photo = (new PhotosRepo())->getByOwnerAndVID((int) $photo_s_id[0], (int) $photo_s_id[1]);
|
||||
if (!$photo || $photo->isDeleted() || !$photo->canBeViewedBy($this->getUser())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$res[] = $photo->toVkApiStruct($photo_sizes, $extended);
|
||||
|
@ -442,12 +414,7 @@ final class Photos extends VKAPIRequestHandler
|
|||
|
||||
if (empty($photo_ids)) {
|
||||
$album = (new Albums())->getAlbumByOwnerAndId($owner_id, $album_id);
|
||||
|
||||
if (!$album || $album->isDeleted()) {
|
||||
$this->fail(21, "Invalid album");
|
||||
}
|
||||
|
||||
if (!$album->canBeViewedBy($this->getUser())) {
|
||||
if (!$album || $album->isDeleted() || !$album->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
|
@ -458,11 +425,15 @@ final class Photos extends VKAPIRequestHandler
|
|||
if (!$photo || $photo->isDeleted()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$res["items"][] = $photo->toVkApiStruct($photo_sizes, $extended);
|
||||
}
|
||||
|
||||
} else {
|
||||
$photos = explode(',', $photo_ids);
|
||||
$photos = array_unique(explode(',', $photo_ids));
|
||||
if (sizeof($photos) > 78) {
|
||||
$this->fail(-78, "Photos count must not exceed limit");
|
||||
}
|
||||
|
||||
$res = [
|
||||
"count" => sizeof($photos),
|
||||
|
@ -472,10 +443,12 @@ final class Photos extends VKAPIRequestHandler
|
|||
foreach ($photos as $photo) {
|
||||
$id = explode("_", $photo);
|
||||
|
||||
$phot = (new PhotosRepo())->getByOwnerAndVID((int) $id[0], (int) $id[1]);
|
||||
if ($phot && !$phot->isDeleted() && $phot->canBeViewedBy($this->getUser())) {
|
||||
$res["items"][] = $phot->toVkApiStruct($photo_sizes, $extended);
|
||||
$photo_entity = (new PhotosRepo())->getByOwnerAndVID((int) $id[0], (int) $id[1]);
|
||||
if (!$photo_entity || $photo_entity->isDeleted() || !$photo_entity->canBeViewedBy($this->getUser())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$res["items"][] = $photo_entity->toVkApiStruct($photo_sizes, $extended);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -489,12 +462,8 @@ final class Photos extends VKAPIRequestHandler
|
|||
|
||||
$album = (new Albums())->get($album_id);
|
||||
|
||||
if (!$album || $album->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(21, "Invalid album");
|
||||
}
|
||||
|
||||
if ($album->isDeleted()) {
|
||||
$this->fail(22, "Album already deleted");
|
||||
if (!$album || $album->isDeleted() || $album->isCreatedBySystem() || !$album->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
$album->delete();
|
||||
|
@ -509,12 +478,8 @@ final class Photos extends VKAPIRequestHandler
|
|||
|
||||
$photo = (new PhotosRepo())->getByOwnerAndVID($owner_id, $photo_id);
|
||||
|
||||
if (!$photo) {
|
||||
$this->fail(21, "Invalid photo");
|
||||
}
|
||||
|
||||
if ($photo->isDeleted()) {
|
||||
$this->fail(21, "Photo is deleted");
|
||||
if (!$photo || $photo->isDeleted() || !$photo->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(21, "Access denied");
|
||||
}
|
||||
|
||||
if (!empty($caption)) {
|
||||
|
@ -525,60 +490,48 @@ final class Photos extends VKAPIRequestHandler
|
|||
return 1;
|
||||
}
|
||||
|
||||
public function delete(int $owner_id, int $photo_id, string $photos = "")
|
||||
public function delete(int $owner_id = null, int $photo_id = null, string $photos = null)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if (empty($photos)) {
|
||||
if (!$owner_id) {
|
||||
$owner_id = $this->getUser()->getId();
|
||||
}
|
||||
|
||||
if (is_null($photos)) {
|
||||
if (is_null($photo_id)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$photo = (new PhotosRepo())->getByOwnerAndVID($owner_id, $photo_id);
|
||||
|
||||
if ($this->getUser()->getId() !== $photo->getOwner()->getId()) {
|
||||
$this->fail(21, "You can't delete another's photo");
|
||||
}
|
||||
|
||||
if (!$photo) {
|
||||
$this->fail(21, "Invalid photo");
|
||||
}
|
||||
|
||||
if ($photo->isDeleted()) {
|
||||
$this->fail(21, "Photo is already deleted");
|
||||
if (!$photo || $photo->isDeleted() || !$photo->canBeModifiedBy($this->getUser())) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
$photo->delete();
|
||||
} else {
|
||||
$photozs = explode(',', $photos);
|
||||
$photos_list = array_unique(explode(',', $photos));
|
||||
if (sizeof($photos_list) > 10) {
|
||||
$this->fail(-78, "Photos count must not exceed limit");
|
||||
}
|
||||
|
||||
foreach ($photozs as $photo) {
|
||||
$id = explode("_", $photo);
|
||||
|
||||
$phot = (new PhotosRepo())->getByOwnerAndVID((int) $id[0], (int) $id[1]);
|
||||
|
||||
if ($this->getUser()->getId() !== $phot->getOwner()->getId()) {
|
||||
$this->fail(21, "You can't delete another's photo");
|
||||
foreach ($photos_list as $photo_id) {
|
||||
$id = explode("_", $photo_id);
|
||||
$photo = (new PhotosRepo())->getByOwnerAndVID((int) $id[0], (int) $id[1]);
|
||||
if (!$photo || $photo->isDeleted() || !$photo->canBeModifiedBy($this->getUser())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$phot) {
|
||||
$this->fail(21, "Invalid photo");
|
||||
}
|
||||
|
||||
if ($phot->isDeleted()) {
|
||||
$this->fail(21, "Photo already deleted");
|
||||
}
|
||||
|
||||
$phot->delete();
|
||||
$photo->delete();
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function getAllComments(int $owner_id, int $album_id, bool $need_likes = false, int $offset = 0, int $count = 100)
|
||||
{
|
||||
$this->fail(501, "Not implemented");
|
||||
}
|
||||
|
||||
public function deleteComment(int $comment_id, int $owner_id = 0)
|
||||
# Поскольку комментарии едины, можно использовать метод "wall.deleteComment".
|
||||
/*public function deleteComment(int $comment_id, int $owner_id = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
@ -595,9 +548,9 @@ final class Photos extends VKAPIRequestHandler
|
|||
$comment->delete();
|
||||
|
||||
return 1;
|
||||
}
|
||||
}*/
|
||||
|
||||
public function createComment(int $owner_id, int $photo_id, string $message = "", string $attachments = "", bool $from_group = false)
|
||||
public function createComment(int $owner_id, int $photo_id, string $message = "", bool $from_group = false)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
@ -608,12 +561,8 @@ final class Photos extends VKAPIRequestHandler
|
|||
|
||||
$photo = (new PhotosRepo())->getByOwnerAndVID($owner_id, $photo_id);
|
||||
|
||||
if (!$photo || $photo->isDeleted()) {
|
||||
$this->fail(180, "Invalid photo");
|
||||
}
|
||||
|
||||
if (!$photo->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(15, "Access to photo denied");
|
||||
if (!$photo || $photo->isDeleted() || !$photo->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
$comment = new Comment();
|
||||
|
@ -624,55 +573,6 @@ final class Photos extends VKAPIRequestHandler
|
|||
$comment->setCreated(time());
|
||||
$comment->save();
|
||||
|
||||
if (!empty($attachments)) {
|
||||
$attachmentsArr = explode(",", $attachments);
|
||||
|
||||
if (sizeof($attachmentsArr) > 10) {
|
||||
$this->fail(50, "Error: too many attachments");
|
||||
}
|
||||
|
||||
foreach ($attachmentsArr as $attac) {
|
||||
$attachmentType = null;
|
||||
|
||||
if (str_contains($attac, "photo")) {
|
||||
$attachmentType = "photo";
|
||||
} elseif (str_contains($attac, "video")) {
|
||||
$attachmentType = "video";
|
||||
} else {
|
||||
$this->fail(205, "Unknown attachment type");
|
||||
}
|
||||
|
||||
$attachment = str_replace($attachmentType, "", $attac);
|
||||
|
||||
$attachmentOwner = (int) explode("_", $attachment)[0];
|
||||
$attachmentId = (int) end(explode("_", $attachment));
|
||||
|
||||
$attacc = null;
|
||||
|
||||
if ($attachmentType == "photo") {
|
||||
$attacc = (new PhotosRepo())->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if (!$attacc || $attacc->isDeleted()) {
|
||||
$this->fail(100, "Photo does not exists");
|
||||
}
|
||||
if ($attacc->getOwner()->getId() != $this->getUser()->getId()) {
|
||||
$this->fail(43, "You do not have access to this photo");
|
||||
}
|
||||
|
||||
$comment->attach($attacc);
|
||||
} elseif ($attachmentType == "video") {
|
||||
$attacc = (new VideosRepo())->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if (!$attacc || $attacc->isDeleted()) {
|
||||
$this->fail(100, "Video does not exists");
|
||||
}
|
||||
if ($attacc->getOwner()->getId() != $this->getUser()->getId()) {
|
||||
$this->fail(43, "You do not have access to this video");
|
||||
}
|
||||
|
||||
$comment->attach($attacc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $comment->getId();
|
||||
}
|
||||
|
||||
|
@ -681,16 +581,12 @@ final class Photos extends VKAPIRequestHandler
|
|||
$this->requireUser();
|
||||
|
||||
if ($owner_id < 0) {
|
||||
$this->fail(4, "This method doesn't works with clubs");
|
||||
$this->fail(-413, "Clubs are not supported");
|
||||
}
|
||||
|
||||
$user = (new UsersRepo())->get($owner_id);
|
||||
if (!$user) {
|
||||
$this->fail(4, "Invalid user");
|
||||
}
|
||||
|
||||
if (!$user->getPrivacyPermission('photos.read', $this->getUser())) {
|
||||
$this->fail(21, "This user chose to hide his albums.");
|
||||
if (!$user || !$user->getPrivacyPermission('photos.read', $this->getUser())) {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
$photos = (new PhotosRepo())->getEveryUserPhoto($user, $offset, $count);
|
||||
|
@ -716,12 +612,8 @@ final class Photos extends VKAPIRequestHandler
|
|||
$photo = (new PhotosRepo())->getByOwnerAndVID($owner_id, $photo_id);
|
||||
$comms = array_slice(iterator_to_array($photo->getComments(1, $offset + $count)), $offset);
|
||||
|
||||
if (!$photo || $photo->isDeleted()) {
|
||||
$this->fail(4, "Invalid photo");
|
||||
}
|
||||
|
||||
if (!$photo->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(21, "Access denied");
|
||||
if (!$photo || $photo->isDeleted() || !$photo->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
$res = [
|
||||
|
|
|
@ -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->getUser()->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");
|
||||
}
|
||||
|
@ -1176,8 +1176,9 @@ final class Wall extends VKAPIRequestHandler
|
|||
if ($from_group == 1 && $wallOwner instanceof Club && $wallOwner->canBeModifiedBy($this->getUser())) {
|
||||
$flags |= 0b10000000;
|
||||
}
|
||||
/*if($signed == 1)
|
||||
$flags |= 0b01000000;*/
|
||||
if ($post->isSigned() && $from_group == 1) {
|
||||
$flags |= 0b01000000;
|
||||
}
|
||||
|
||||
$post->setFlags($flags);
|
||||
$post->save(true);
|
||||
|
|
|
@ -26,7 +26,9 @@ class Album extends MediaCollection
|
|||
{
|
||||
$coverPhoto = $this->getCoverPhoto();
|
||||
if (!$coverPhoto) {
|
||||
return "/assets/packages/static/openvk/img/camera_200.png";
|
||||
$server_url = ovk_scheme(true) . $_SERVER["HTTP_HOST"];
|
||||
|
||||
return $server_url . "/assets/packages/static/openvk/img/camera_200.png";
|
||||
}
|
||||
|
||||
return $coverPhoto->getURL();
|
||||
|
@ -92,14 +94,13 @@ class Album extends MediaCollection
|
|||
{
|
||||
$res = (object) [];
|
||||
|
||||
$res->id = $this->getPrettyId();
|
||||
$res->vid = $this->getId();
|
||||
$res->id = $this->getId();
|
||||
$res->thumb_id = !is_null($this->getCoverPhoto()) ? $this->getCoverPhoto()->getPrettyId() : 0;
|
||||
$res->owner_id = $this->getOwner()->getId();
|
||||
$res->owner_id = $this->getOwner()->getRealId();
|
||||
$res->title = $this->getName();
|
||||
$res->description = $this->getDescription();
|
||||
$res->created = $this->getCreationTime()->timestamp();
|
||||
$res->updated = $this->getEditTime() ? $this->getEditTime()->timestamp() : null;
|
||||
$res->updated = $this->getEditTime() ? $this->getEditTime()->timestamp() : $res->created;
|
||||
$res->size = $this->size();
|
||||
$res->privacy_comment = 1;
|
||||
$res->upload_by_admins_only = 1;
|
||||
|
|
|
@ -435,6 +435,10 @@ class Audio extends Media
|
|||
$obj->keys = $this->getKeys();
|
||||
}
|
||||
|
||||
if ($obj->editable) {
|
||||
$obj->listens = $this->getListens();
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
|
|
|
@ -323,7 +323,7 @@ class Club extends RowModel
|
|||
return sizeof($this->getFollowersQuery());
|
||||
}
|
||||
|
||||
public function getFollowers(int $page = 1, int $perPage = 6, string $sort = "follower ASC"): \Traversable
|
||||
public function getFollowers(int $page = 1, int $perPage = 6, string $sort = "target DESC"): \Traversable
|
||||
{
|
||||
$rels = $this->getFollowersQuery($sort)->page($page, $perPage);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -166,14 +168,13 @@ class Notification
|
|||
case 19:
|
||||
$info["type"] = "comment_video";
|
||||
$info["parent"] = $this->getModel(0)->toNotifApiStruct();
|
||||
$info["feedback"] = null; # айди коммента не сохраняется в бд( ну пиздец блять
|
||||
$info["feedback"] = null; # comment id is not saving at db
|
||||
break;
|
||||
case 13:
|
||||
$info["type"] = "comment_photo";
|
||||
$info["parent"] = $this->getModel(0)->toNotifApiStruct();
|
||||
$info["feedback"] = null;
|
||||
break;
|
||||
# unstandart (vk forgor about notes)
|
||||
case 10:
|
||||
$info["type"] = "comment_note";
|
||||
$info["parent"] = $this->getModel(0)->toVkApiStruct();
|
||||
|
|
|
@ -349,7 +349,6 @@ class Photo extends Media
|
|||
$res->width = $this->getDimensions()[0];
|
||||
$res->height = $this->getDimensions()[1];
|
||||
$res->date = $res->created = $this->getPublicationTime()->timestamp();
|
||||
|
||||
if ($photo_sizes) {
|
||||
$res->sizes = array_values($this->getVkApiSizes());
|
||||
$res->src_small = $res->photo_75 = $this->getURLBySizeId("miniscule");
|
||||
|
@ -359,14 +358,19 @@ class Photo extends Media
|
|||
$res->src_xxbig = $res->photo_1280 = $this->getURLBySizeId("larger");
|
||||
$res->src_xxxbig = $res->photo_2560 = $this->getURLBySizeId("original");
|
||||
$res->src_original = $res->url = $this->getURLBySizeId("UPLOADED_MAXRES");
|
||||
$res->orig_photo = [
|
||||
"height" => $res->height,
|
||||
"width" => $res->width,
|
||||
"type" => "base",
|
||||
"url" => $this->getURL(),
|
||||
];
|
||||
}
|
||||
|
||||
if ($extended) {
|
||||
$res->likes = $this->getLikesCount(); # их нету но пусть будут
|
||||
$res->likes = $this->getLikesCount();
|
||||
$res->comments = $this->getCommentsCount();
|
||||
$res->tags = 0;
|
||||
$res->can_comment = 1;
|
||||
$res->can_repost = 0;
|
||||
$res->can_repost = 1;
|
||||
}
|
||||
|
||||
return $res;
|
||||
|
@ -385,9 +389,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
|
||||
|
|
|
@ -41,11 +41,11 @@ trait TRichText
|
|||
return preg_replace_callback(
|
||||
"%(([A-z]++):\/\/(\S*?\.\S*?))([\s)\[\]{},\"\'<]|\.\s|$)%",
|
||||
(function (array $matches): string {
|
||||
$href = str_replace("#", "#", $matches[1]);
|
||||
$href = rawurlencode(str_replace(";", ";", $href));
|
||||
$link = str_replace("#", "#", $matches[3]);
|
||||
$href = rawurlencode($matches[1]);
|
||||
$href = str_replace("%26amp%3B", "%26", $href);
|
||||
$link = $matches[3];
|
||||
# this string breaks ampersands
|
||||
$link = str_replace(";", ";", $link);
|
||||
# $link = str_replace(";", ";", $link);
|
||||
$rel = $this->isAd() ? "sponsored" : "ugc";
|
||||
|
||||
/*$server_domain = str_replace(':' . $_SERVER['SERVER_PORT'], '', $_SERVER['HTTP_HOST']);
|
||||
|
|
|
@ -306,10 +306,10 @@ class User extends RowModel
|
|||
$content_type = $matches[1];
|
||||
$content_id = (int) $matches[2];
|
||||
if (in_array($content_type, ["noSpamTemplate", "user"])) {
|
||||
$reason = "Подозрительная активность";
|
||||
$reason = $this->getRawBanReason();
|
||||
} else {
|
||||
if ($for !== "banned") {
|
||||
$reason = "Подозрительная активность";
|
||||
$reason = $this->getRawBanReason();
|
||||
} else {
|
||||
$reason = [$this->getTextForContentBan($content_type), $content_type];
|
||||
switch ($content_type) {
|
||||
|
@ -524,7 +524,10 @@ class User extends RowModel
|
|||
|
||||
public function getAge(): ?int
|
||||
{
|
||||
return (int) floor((time() - $this->getBirthday()->timestamp()) / YEAR);
|
||||
$birthday = new \DateTime();
|
||||
$birthday->setTimestamp($this->getBirthday()->timestamp());
|
||||
$today = new \DateTime();
|
||||
return (int) $today->diff($birthday)->y;
|
||||
}
|
||||
|
||||
public function get2faSecret(): ?string
|
||||
|
@ -558,6 +561,7 @@ class User extends RowModel
|
|||
"poster",
|
||||
"apps",
|
||||
"docs",
|
||||
"fave",
|
||||
],
|
||||
])->get($id);
|
||||
}
|
||||
|
@ -932,6 +936,7 @@ class User extends RowModel
|
|||
case 1:
|
||||
return tr('female');
|
||||
case 2:
|
||||
default:
|
||||
return tr('neutral');
|
||||
}
|
||||
}
|
||||
|
@ -1195,6 +1200,7 @@ class User extends RowModel
|
|||
"poster",
|
||||
"apps",
|
||||
"docs",
|
||||
"fave",
|
||||
],
|
||||
])->set($id, (int) $status)->toInteger();
|
||||
|
||||
|
@ -1559,14 +1565,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();
|
||||
}
|
||||
}
|
|
@ -62,6 +62,7 @@ class Photos
|
|||
"deleted" => 0,
|
||||
"system" => 0,
|
||||
"private" => 0,
|
||||
"anonymous" => 0,
|
||||
])->order("id DESC");
|
||||
|
||||
foreach ($photos->limit($limit, $offset) as $photo) {
|
||||
|
@ -76,6 +77,7 @@ class Photos
|
|||
"deleted" => 0,
|
||||
"system" => 0,
|
||||
"private" => 0,
|
||||
"anonymous" => 0,
|
||||
]);
|
||||
|
||||
return sizeof($photos);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -157,7 +157,7 @@ class Users
|
|||
{
|
||||
return (object) [
|
||||
"all" => (clone $this->users)->count('*'),
|
||||
"active" => (clone $this->users)->where("online > 0")->count('*'),
|
||||
"active" => (clone $this->users)->where("online >= ?", time() - MONTH)->count('*'),
|
||||
"online" => (clone $this->users)->where("online >= ?", time() - 900)->count('*'),
|
||||
];
|
||||
}
|
||||
|
|
|
@ -255,7 +255,7 @@ final class AdminPresenter extends OpenVKPresenter
|
|||
{
|
||||
$this->warnIfNoCommerce();
|
||||
|
||||
$cat;
|
||||
$cat = null;
|
||||
$gen = false;
|
||||
if ($id !== 0) {
|
||||
$cat = $this->gifts->getCat($id);
|
||||
|
|
|
@ -78,6 +78,10 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
} elseif ($mode === "new") {
|
||||
$audios = $this->audios->getNew();
|
||||
$audiosCount = $audios->size();
|
||||
} elseif ($mode === "uploaded") {
|
||||
$stream = $this->audios->getByUploader($this->user->identity);
|
||||
$audios = $stream->page($page, 10);
|
||||
$audiosCount = $stream->size();
|
||||
} elseif ($mode === "playlists") {
|
||||
if ($owner < 0) {
|
||||
$entity = (new Clubs())->get(abs($owner));
|
||||
|
@ -130,6 +134,11 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
}
|
||||
}
|
||||
|
||||
public function renderUploaded()
|
||||
{
|
||||
$this->renderList(null, "uploaded");
|
||||
}
|
||||
|
||||
public function renderEmbed(int $owner, int $id): void
|
||||
{
|
||||
$audio = $this->audios->getByOwnerAndVID($owner, $id);
|
||||
|
@ -499,7 +508,7 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
$title = $this->postParam("title");
|
||||
$description = $this->postParam("description");
|
||||
$is_unlisted = (int) $this->postParam('is_unlisted');
|
||||
$new_audios = !empty($this->postParam("audios")) ? explode(",", rtrim($this->postParam("audios"), ",")) : [];
|
||||
$new_audios = !empty($this->postParam("audios")) ? explode(",", rtrim($this->postParam("audios"), ",")) : null;
|
||||
|
||||
if (empty($title) || iconv_strlen($title) < 1) {
|
||||
$this->flashFail("err", tr("error"), tr("set_playlist_name"));
|
||||
|
@ -529,13 +538,15 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
"collection" => $playlist->getId(),
|
||||
])->delete();
|
||||
|
||||
foreach ($new_audios as $new_audio) {
|
||||
$audio = (new Audios())->get((int) $new_audio);
|
||||
if (!$audio || $audio->isDeleted()) {
|
||||
continue;
|
||||
}
|
||||
if (!is_null($new_audios)) {
|
||||
foreach ($new_audios as $new_audio) {
|
||||
$audio = (new Audios())->get((int) $new_audio);
|
||||
if (!$audio || $audio->isDeleted()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$playlist->add($audio);
|
||||
$playlist->add($audio);
|
||||
}
|
||||
}
|
||||
|
||||
if ($is_ajax) {
|
||||
|
@ -841,6 +852,10 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
$audios = [$found_audio];
|
||||
$audiosCount = 1;
|
||||
break;
|
||||
case "uploaded":
|
||||
$stream = $this->audios->getByUploader($this->user->identity);
|
||||
$audios = $stream->page($page, $perPage);
|
||||
$audiosCount = $stream->size();
|
||||
}
|
||||
|
||||
$pagesCount = ceil($audiosCount / $perPage);
|
||||
|
|
|
@ -20,7 +20,7 @@ final class AwayPresenter extends OpenVKPresenter
|
|||
|
||||
header("HTTP/1.0 302 Found");
|
||||
header("X-Robots-Tag: noindex, nofollow, noarchive");
|
||||
header("Location: " . $this->queryParam("to"));
|
||||
header("Location: " . rawurldecode($this->queryParam("to")));
|
||||
exit;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -165,7 +165,7 @@ final class InternalAPIPresenter extends OpenVKPresenter
|
|||
if ($type == 'post') {
|
||||
$this->template->_template = 'components/post.xml';
|
||||
$this->template->post = $post;
|
||||
$this->template->commentSection = false;
|
||||
$this->template->commentSection = true;
|
||||
} elseif ($type == 'comment') {
|
||||
$this->template->_template = 'components/comment.xml';
|
||||
$this->template->comment = $post;
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
|
@ -371,7 +371,11 @@ abstract class OpenVKPresenter extends SimplePresenter
|
|||
$whichbrowser->isEngine('NetFront') || // PSP and other japanese portable systems
|
||||
$whichbrowser->isOs('Android') ||
|
||||
$whichbrowser->isOs('iOS') ||
|
||||
$whichbrowser->isBrowser('Internet Explorer', '<=', '8')) {
|
||||
$whichbrowser->isBrowser('BlackBerry Browser') ||
|
||||
$whichbrowser->isBrowser('Internet Explorer', '<=', '8') ||
|
||||
$whichbrowser->isBrowser('Firefox', '<=', '47') ||
|
||||
$whichbrowser->isBrowser('Safari', '<=', '7') ||
|
||||
$whichbrowser->isBrowser('Google Chrome', '<=', '35')) {
|
||||
// yeah, it's old, but ios and android are?
|
||||
if ($whichbrowser->isOs('iOS') && $whichbrowser->isOs('iOS', '<=', '9')) {
|
||||
return true;
|
||||
|
|
|
@ -321,7 +321,7 @@ final class PhotosPresenter extends OpenVKPresenter
|
|||
|
||||
$photos = [];
|
||||
if ((int) $this->postParam("count") > 10) {
|
||||
$this->flashFail("err", tr("no_photo"), "ты еблан", 500, true);
|
||||
$this->flashFail("err", tr("no_photo"), "Too many photos (max is 7-8)", 500, true);
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $this->postParam("count"); $i++) {
|
||||
|
|
|
@ -42,7 +42,6 @@ final class SearchPresenter extends OpenVKPresenter
|
|||
$page = (int) ($this->queryParam("p") ?? 1);
|
||||
|
||||
# https://youtu.be/pSAWM5YuXx8
|
||||
# https://youtu.be/FfNZRhIn2Vk
|
||||
|
||||
$repos = [
|
||||
"groups" => "clubs",
|
||||
|
@ -70,7 +69,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 +95,7 @@ final class SearchPresenter extends OpenVKPresenter
|
|||
# дай бог работал этот case
|
||||
case 'from_me':
|
||||
if ((int) $param_value != 1) {
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
$parameters['from_me'] = $this->user->id;
|
||||
|
||||
|
|
|
@ -169,6 +169,13 @@ final class SupportPresenter extends OpenVKPresenter
|
|||
$_redirect = "/support?act=list";
|
||||
}
|
||||
|
||||
$helpdeskChat = OPENVK_ROOT_CONF["openvk"]["credentials"]["telegram"]["helpdeskChat"];
|
||||
if ($helpdeskChat) {
|
||||
$serverUrl = ovk_scheme(true) . $_SERVER["SERVER_NAME"];
|
||||
$telegramText = "❌ <b>Тикет под названием</b> "{$ticket->getName()}" от <a href='$serverUrl{$ticket->getUser()->getURL()}'>{$ticket->getUser()->getCanonicalName()}</a> ({$ticket->getUser()->getRegistrationIP()}) <b>был удалён.</b>\n";
|
||||
Telegram::send($helpdeskChat, $telegramText);
|
||||
}
|
||||
|
||||
$ticket->delete();
|
||||
$this->redirect($_redirect);
|
||||
}
|
||||
|
@ -200,6 +207,16 @@ final class SupportPresenter extends OpenVKPresenter
|
|||
$comment->setCreated(time());
|
||||
$comment->save();
|
||||
|
||||
$helpdeskChat = OPENVK_ROOT_CONF["openvk"]["credentials"]["telegram"]["helpdeskChat"];
|
||||
if ($helpdeskChat) {
|
||||
$serverUrl = ovk_scheme(true) . $_SERVER["SERVER_NAME"];
|
||||
$commentText = ovk_proc_strtr($this->postParam("text"), 1500);
|
||||
$telegramText = "💬 <b>Новый комментарий от автора тикета</b> <a href='$serverUrl/support/reply/$id'>"{$ticket->getName()}"</a>\n";
|
||||
$telegramText .= "$commentText\n\n";
|
||||
$telegramText .= "Автор: <a href='$serverUrl{$ticket->getUser()->getURL()}'>{$ticket->getUser()->getCanonicalName()}</a> ({$ticket->getUser()->getRegistrationIP()})\n";
|
||||
Telegram::send($helpdeskChat, $telegramText);
|
||||
}
|
||||
|
||||
$this->redirect("/support/view/" . $id);
|
||||
} else {
|
||||
$this->flashFail("err", tr("error"), tr("you_have_not_entered_text"));
|
||||
|
@ -227,15 +244,33 @@ final class SupportPresenter extends OpenVKPresenter
|
|||
{
|
||||
$this->assertPermission('openvk\Web\Models\Entities\TicketReply', 'write', 0);
|
||||
|
||||
$support_names = new SupportAgents();
|
||||
$agent = $support_names->get($this->user->id);
|
||||
$ticket = $this->tickets->get($id);
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$helpdeskChat = OPENVK_ROOT_CONF["openvk"]["credentials"]["telegram"]["helpdeskChat"];
|
||||
|
||||
if (!empty($this->postParam("text")) && !empty($this->postParam("status"))) {
|
||||
$ticket->setType($this->postParam("status"));
|
||||
$status = $this->postParam("status");
|
||||
$ticket->setType($status);
|
||||
$ticket->save();
|
||||
|
||||
switch ($status) {
|
||||
default:
|
||||
# NOTICE falling through
|
||||
case 0:
|
||||
$state = "Вопрос на рассмотрении";
|
||||
break;
|
||||
case 1:
|
||||
$state = "Есть ответ";
|
||||
break;
|
||||
case 2:
|
||||
$state = "Закрыто";
|
||||
}
|
||||
|
||||
$comment = new TicketComment();
|
||||
$comment->setUser_id($this->user->id);
|
||||
$comment->setUser_type(1);
|
||||
|
@ -243,9 +278,42 @@ final class SupportPresenter extends OpenVKPresenter
|
|||
$comment->setTicket_Id($id);
|
||||
$comment->setCreated(time());
|
||||
$comment->save();
|
||||
|
||||
if ($helpdeskChat) {
|
||||
$serverUrl = ovk_scheme(true) . $_SERVER["SERVER_NAME"] . "/support/agent" . $this->user->id;
|
||||
$ticketUrl = ovk_scheme(true) . $_SERVER["SERVER_NAME"] . "/support/reply/" . $id;
|
||||
$commentText = ovk_proc_strtr($this->postParam("text"), 1500);
|
||||
$telegramText = "💬 <b>Новый комментарий от агента к тикету</b> <a href='$ticketUrl'>"{$ticket->getName()}"</a>\n";
|
||||
$telegramText .= "Статус: {$state}\n\n";
|
||||
$telegramText .= "$commentText\n\n";
|
||||
$telegramText .= "Агент: <a href='$serverUrl'>{$this->user->identity->getFullName()}</a>\n";
|
||||
Telegram::send($helpdeskChat, $telegramText);
|
||||
}
|
||||
} elseif (empty($this->postParam("text"))) {
|
||||
$ticket->setType($this->postParam("status"));
|
||||
$status = $this->postParam("status");
|
||||
$ticket->setType($status);
|
||||
$ticket->save();
|
||||
|
||||
switch ($status) {
|
||||
default:
|
||||
# NOTICE falling through
|
||||
case 0:
|
||||
$state = "Вопрос на рассмотрении";
|
||||
break;
|
||||
case 1:
|
||||
$state = "Есть ответ";
|
||||
break;
|
||||
case 2:
|
||||
$state = "Закрыто";
|
||||
}
|
||||
|
||||
if ($helpdeskChat) {
|
||||
$serverUrl = ovk_scheme(true) . $_SERVER["SERVER_NAME"] . "/support/agent" . $this->user->id;
|
||||
$ticketUrl = ovk_scheme(true) . $_SERVER["SERVER_NAME"] . "/support/reply/" . $id;
|
||||
$telegramText = "🔔 <b>Изменён статус тикета</b> <a href='$ticketUrl'>"{$ticket->getName()}"</a>: <b>{$state}</b>\n\n";
|
||||
$telegramText .= "Агент: <a href='$serverUrl'>{$this->user->identity->getFullName()}</a>\n";
|
||||
Telegram::send($helpdeskChat, $telegramText);
|
||||
}
|
||||
}
|
||||
|
||||
$this->flashFail("succ", tr("ticket_changed"), tr("ticket_changed_comment"));
|
||||
|
@ -314,17 +382,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
|
||||
|
@ -439,6 +510,13 @@ final class SupportPresenter extends OpenVKPresenter
|
|||
$ticket->setType(2);
|
||||
$ticket->save();
|
||||
|
||||
$helpdeskChat = OPENVK_ROOT_CONF["openvk"]["credentials"]["telegram"]["helpdeskChat"];
|
||||
if ($helpdeskChat) {
|
||||
$serverUrl = ovk_scheme(true) . $_SERVER["SERVER_NAME"];
|
||||
$telegramText = "🔒 <b>Тикет под названием</b> <a href='$serverUrl/support/reply/{$ticket->getId()}'>"{$ticket->getName()}"</a> от <a href='$serverUrl{$ticket->getUser()->getURL()}'>{$ticket->getUser()->getCanonicalName()}</a> ({$ticket->getUser()->getRegistrationIP()}) <b>был закрыт автором.</b>\n";
|
||||
Telegram::send($helpdeskChat, $telegramText);
|
||||
}
|
||||
|
||||
$this->flashFail("succ", tr("ticket_changed"), tr("ticket_changed_comment"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"));
|
||||
|
@ -406,7 +409,12 @@ final class WallPresenter extends OpenVKPresenter
|
|||
}
|
||||
|
||||
if ($wall > 0 && $wall !== $this->user->identity->getId()) {
|
||||
(new WallPostNotification($wallOwner, $post, $this->user->identity))->emit();
|
||||
$disturber = $this->user->identity;
|
||||
if ($anon) {
|
||||
$disturber = $post->getOwner();
|
||||
}
|
||||
|
||||
(new WallPostNotification($wallOwner, $post, $disturber))->emit();
|
||||
}
|
||||
|
||||
$excludeMentions = [$this->user->identity->getId()];
|
||||
|
@ -568,8 +576,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"));
|
||||
|
|
|
@ -202,6 +202,7 @@
|
|||
<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)}
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
{/if}
|
||||
{elseif $mode == 'new'}
|
||||
{_audio_new}
|
||||
{elseif $mode == 'uploaded'}
|
||||
{_my_audios_small_uploaded}
|
||||
{elseif $mode == 'popular'}
|
||||
{_audio_popular}
|
||||
{elseif $mode == 'alone_audio'}
|
||||
|
@ -32,6 +34,12 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div n:if="$mode == 'uploaded'">
|
||||
{_my_audios_small}
|
||||
»
|
||||
{_my_audios_small_uploaded}
|
||||
</div>
|
||||
|
||||
<div n:if="$mode == 'new'">
|
||||
{_audios}
|
||||
»
|
||||
|
@ -58,7 +66,7 @@
|
|||
{block content}
|
||||
{* ref: https://archive.li/P32em *}
|
||||
|
||||
{include "bigplayer.xml"}
|
||||
{include "bigplayer.xml", buttonsShow_summary => $audiosCount > 10}
|
||||
|
||||
<script>
|
||||
window.__current_page_audio_context = null
|
||||
|
@ -68,6 +76,12 @@
|
|||
entity_id: {$ownerId},
|
||||
page: {$page}
|
||||
}
|
||||
{elseif $mode == 'uploaded'}
|
||||
window.__current_page_audio_context = {
|
||||
name: 'uploaded',
|
||||
entity_id: 0,
|
||||
page: {$page}
|
||||
}
|
||||
{elseif $mode == 'alone_audio'}
|
||||
window.__current_page_audio_context = {
|
||||
name: 'alone_audio',
|
||||
|
@ -77,6 +91,22 @@
|
|||
{/if}
|
||||
</script>
|
||||
|
||||
<div n:if="isset($audios)" class='summaryBarHideable summaryBar summaryBarFlex padding' style="margin: 0px -10px;width: 99.5%;display: none;">
|
||||
<div class='summary'>
|
||||
<b>{tr("is_x_audio", $audiosCount)}</b>
|
||||
</div>
|
||||
|
||||
{include "../components/paginator.xml", conf => (object) [
|
||||
"page" => $page,
|
||||
"count" => $audiosCount,
|
||||
"amount" => sizeof($audios),
|
||||
"perPage" => $perPage ?? OPENVK_DEFAULT_PER_PAGE,
|
||||
"atTop" => true,
|
||||
"space" => 6,
|
||||
"tidy" => true,
|
||||
]}
|
||||
</div>
|
||||
|
||||
<div class="audiosDiv">
|
||||
<div class="audiosContainer audiosSideContainer audiosPaddingContainer" n:if="$mode != 'playlists'">
|
||||
<div n:if="$audiosCount <= 0" style='height: 100%;'>
|
||||
|
|
|
@ -52,5 +52,9 @@
|
|||
<div class="shuffleButton musicIcon" data-tip='simple' data-title="{_shuffle_tip}"></div>
|
||||
<div class="deviceButton musicIcon" data-tip='simple' data-title="{_mute_tip} [M]"></div>
|
||||
</div>
|
||||
|
||||
<div class="absoluteButtons">
|
||||
<div n:if="$buttonsShow_summary" id="summarySwitchButton">-</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<div class="verticalGrayTabs">
|
||||
<div class='with_padding'>
|
||||
<a n:if="isset($thisUser)" n:attr="id => $mode === 'list' && $isMy ? 'used' : 'ki'" href="/audios{$thisUser->getId()}">{_my_music}</a>
|
||||
<a n:attr="id => $mode === 'uploaded' ? 'used' : 'ki'" href="/audios/uploaded">{_my_audios_small_uploaded}</a>
|
||||
{* TODO: show upload link as and plusick (little plus) in button up*}
|
||||
<a n:if="isset($thisUser)" href="/player/upload{if $isMyClub}?gid={abs($ownerId)}{/if}">{_upload_audio}</a>
|
||||
<a n:if="isset($thisUser)" n:attr="id => $mode === 'new' ? 'used' : 'ki'" href="/search?section=audios">{_audio_new}</a>
|
||||
|
@ -13,7 +14,7 @@
|
|||
|
||||
<a n:if="isset($thisUser)" href="/audios/newPlaylist">{_new_playlist}</a>
|
||||
|
||||
{if !$isMy && $mode !== 'popular' && $mode !== 'new' && $mode != 'alone_audio'}
|
||||
{if !$isMy && $mode !== 'popular' && $mode !== 'new' && $mode != 'alone_audio' && $mode != 'uploaded'}
|
||||
<hr>
|
||||
|
||||
<a n:if="!$isMy" n:attr="id => $mode === 'list' ? 'used' : 'ki'" href="/audios{$ownerId}">{if $ownerId > 0}{_music_user}{else}{_music_club}{/if}</a>
|
||||
|
|
86
Web/Presenters/templates/User/Fave.xml
Normal file
86
Web/Presenters/templates/User/Fave.xml
Normal file
|
@ -0,0 +1,86 @@
|
|||
{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 $dat->isDeleted()}
|
||||
<div n:class="deleted_mark, $section == 'photos' ? album-photo : deleted_mark_average">
|
||||
<span>[deleted]</span>
|
||||
</div>
|
||||
{else}
|
||||
{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}
|
||||
{/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}
|
|
@ -120,6 +120,10 @@
|
|||
|
||||
<br/>
|
||||
<div class="settings_delete">
|
||||
<a href="/fave">{_bookmarks_tab}</a>
|
||||
•
|
||||
<a href="/search?section=posts&from_me=1">{_s_posts}</a>
|
||||
<br><br>
|
||||
{_you_can_also} <a onClick="showProfileDeactivateDialog({$csrfToken})">{_delete_your_page}</a>.
|
||||
</div>
|
||||
|
||||
|
@ -596,6 +600,17 @@
|
|||
</table>
|
||||
</form>
|
||||
|
||||
<table cellspacing="7" cellpadding="0" width="60%" border="0" align="center" id="_js_settings">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="120" valign="top" align="right"></td>
|
||||
<td>
|
||||
<a href="javascript:openJsSettings()">{_ui_settings_window}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h4>{_ui_settings_sidebar}</h4>
|
||||
<form action="/settings?act=lMenu" method="POST" enctype="multipart/form-data">
|
||||
<table cellspacing="7" cellpadding="0" width="60%" border="0" align="center">
|
||||
|
@ -696,6 +711,17 @@
|
|||
<span class="nobold">{_my_documents}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="display:none;">
|
||||
<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
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
{if !$attachment->isDeleted()}
|
||||
{var $link = "/photo" . ($attachment->isAnonymous() ? ("s/" . base_convert((string) $attachment->getId(), 10, 32)) : $attachment->getPrettyId())}
|
||||
<a href="{$link}" onclick="OpenMiniature(event, {$attachment->getURLBySizeId('larger')}, {$parent->getPrettyId()}, {$attachment->getPrettyId()}, {$parentType})">
|
||||
<img class="media media_makima" src="{$attachment->getURLBySizeId('normal')}" alt="{$attachment->getDescription()}" loading=lazy />
|
||||
<img n:class="media, $tilesCount > 1 ? media_makima" src="{$attachment->getURLBySizeId('normal')}" alt="{$attachment->getDescription()}" loading=lazy />
|
||||
</a>
|
||||
{else}
|
||||
<a href="javascript:alert('{_attach_no_longer_available}');">
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -203,6 +203,8 @@ routes:
|
|||
handler: "Audio->upload"
|
||||
- url: "/audios{num}"
|
||||
handler: "Audio->list"
|
||||
- url: "/audios/uploaded"
|
||||
handler: "Audio->uploaded"
|
||||
- url: "/audio{num}/listen"
|
||||
handler: "Audio->listen"
|
||||
- url: "/audio{num}_{num}"
|
||||
|
@ -415,6 +417,8 @@ routes:
|
|||
handler: "InternalAPI->getPostTemplate"
|
||||
- url: "/tour"
|
||||
handler: "About->tour"
|
||||
- url: "/fave"
|
||||
handler: "User->fave"
|
||||
- url: "/{?shortCode}"
|
||||
handler: "UnknownTextRouteStrategy->delegate"
|
||||
placeholders:
|
||||
|
|
|
@ -52,6 +52,34 @@
|
|||
height: 46px;
|
||||
}
|
||||
|
||||
.bigPlayer .bigPlayerWrapper .absoluteButtons {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.bigPlayer .bigPlayerWrapper .absoluteButtons > div {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
font-size: 9px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #ebebeb;
|
||||
border: 1px solid #c3c3c3;
|
||||
border-bottom: unset;
|
||||
border-right: unset;
|
||||
color: #c3c3c3;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.bigPlayer .bigPlayerWrapper .absoluteButtons > div:active {
|
||||
background: #c3c3c3;
|
||||
color: #ebebeb;
|
||||
}
|
||||
|
||||
/* Play button and arrows */
|
||||
.bigPlayer .playButtons {
|
||||
display: flex;
|
||||
|
@ -313,7 +341,7 @@
|
|||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.audioEmbed.processed {
|
||||
.audioEmbed.processed .playerButton {
|
||||
filter: opacity(0.6);
|
||||
}
|
||||
|
||||
|
|
|
@ -99,6 +99,7 @@ button.bsdn_playButton {
|
|||
padding-left: 0;
|
||||
font-size: 22px;
|
||||
cursor: pointer;
|
||||
width: 22px;
|
||||
}
|
||||
|
||||
.bsdn_fullScreenButton, .bsdn_repeatButton {
|
||||
|
|
|
@ -11,6 +11,7 @@ body {
|
|||
font-size: 11px;
|
||||
word-break: break-word;
|
||||
word-wrap: break-word;
|
||||
line-height: 1.19;
|
||||
}
|
||||
|
||||
body, .ovk-fullscreen-dimmer, .ovk-photo-view-dimmer {
|
||||
|
@ -2919,7 +2920,6 @@ a.poll-retract-vote {
|
|||
position: relative;
|
||||
}
|
||||
|
||||
/* не говновёрстка, а пиксель-пёрфект) */
|
||||
.page_header.search_expanded.search_expanded_at_all #search_and_one_more_wrapper {
|
||||
width: 547px;
|
||||
}
|
||||
|
@ -3039,6 +3039,10 @@ a.poll-retract-vote {
|
|||
gap: 1px;
|
||||
}
|
||||
|
||||
.verticalGrayTabsPad {
|
||||
padding: 0px 0px 0px 8px;
|
||||
}
|
||||
|
||||
.searchList hr, .verticalGrayTabs hr {
|
||||
width: 153px;
|
||||
margin-left: 0px;
|
||||
|
@ -4278,3 +4282,7 @@ hr {
|
|||
height: 30px;
|
||||
background-position-y: 9px;
|
||||
}
|
||||
|
||||
.deleted_mark_average {
|
||||
padding: 5px 61px;
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ u(document).on('click', '#__feed_settings_link', (e) => {
|
|||
`
|
||||
|
||||
MessageBox(tr("feed_settings"), body, [tr("close")], [Function.noop])
|
||||
u('.ovk-diag-body').attr('style', 'padding:0px;height: 255px;')
|
||||
u('.ovk-diag-body').attr('style', 'padding:0px;height: 255px;overflow: hidden;')
|
||||
|
||||
async function __switchTab(tab)
|
||||
{
|
||||
|
@ -84,8 +84,6 @@ u(document).on('click', '#__feed_settings_link', (e) => {
|
|||
const CURRENT_PERPAGE = Number(__temp_url.searchParams.get('posts') ?? 10)
|
||||
const CURRENT_PAGE = Number(__temp_url.searchParams.get('p') ?? 1)
|
||||
const CURRENT_RETURN_BANNED = Number(__temp_url.searchParams.get('return_banned') ?? 0)
|
||||
const CURRENT_AUTO_SCROLL = Number(localStorage.getItem('ux.auto_scroll') ?? 1)
|
||||
const CURRENT_DISABLE_AJAX = Number(localStorage.getItem('ux.disable_ajax_routing') ?? 0)
|
||||
const COUNT = [1, 5, 10, 20, 30, 40, 50]
|
||||
u('#_feed_settings_container #__content').html(`
|
||||
<table cellspacing="7" cellpadding="0" border="0" align="center">
|
||||
|
@ -116,26 +114,6 @@ u(document).on('click', '#__feed_settings_link', (e) => {
|
|||
<label for='showIgnored'>${tr('show_ignored_sources')}</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="120" valign="top">
|
||||
<span class="nobold">
|
||||
<input type='checkbox' data-act='localstorage_item' data-inverse="1" name='ux.disable_ajax_routing' id="ux.disable_ajax_routing" ${CURRENT_DISABLE_AJAX == 0 ? 'checked' : ''}>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<label for='ux.disable_ajax_routing'>${tr('ajax_routing')}</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="120" valign="top">
|
||||
<span class="nobold">
|
||||
<input type='checkbox' data-act='localstorage_item' name='ux.auto_scroll' id="ux.auto_scroll" ${CURRENT_AUTO_SCROLL == 1 ? 'checked' : ''}>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<label for='ux.auto_scroll'>${tr('auto_scroll')}</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="120" valign="top">
|
||||
</td>
|
||||
|
@ -299,3 +277,32 @@ u(document).on('change', `input[data-act='localstorage_item']`, (e) => {
|
|||
|
||||
localStorage.setItem(e.target.name, Number(e.target.checked))
|
||||
})
|
||||
|
||||
function openJsSettings() {
|
||||
const CURRENT_AUTO_SCROLL = Number(localStorage.getItem('ux.auto_scroll') ?? 1)
|
||||
const CURRENT_DISABLE_AJAX = Number(localStorage.getItem('ux.disable_ajax_routing') ?? 0)
|
||||
|
||||
u("#_js_settings td").remove()
|
||||
u("#_js_settings").append(`
|
||||
<tr>
|
||||
<td width="120" valign="top">
|
||||
<span class="nobold">
|
||||
<input type='checkbox' data-act='localstorage_item' data-inverse="1" name='ux.disable_ajax_routing' id="ux.disable_ajax_routing" ${CURRENT_DISABLE_AJAX == 0 ? 'checked' : ''}>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<label for='ux.disable_ajax_routing'>${tr('ajax_routing')}</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="120" valign="top">
|
||||
<span class="nobold">
|
||||
<input type='checkbox' data-act='localstorage_item' name='ux.auto_scroll' id="ux.auto_scroll" ${CURRENT_AUTO_SCROLL == 1 ? 'checked' : ''}>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<label for='ux.auto_scroll'>${tr('auto_scroll')}</label>
|
||||
</td>
|
||||
</tr>
|
||||
`)
|
||||
}
|
||||
|
|
|
@ -54,6 +54,9 @@ window.player = new class {
|
|||
current_track_id = 0
|
||||
tracks = []
|
||||
|
||||
// time type:
|
||||
// 0 - shows remaining time before end
|
||||
// 1 - shows full track time
|
||||
get timeType() {
|
||||
return localStorage.getItem('audio.timeType') ?? 0
|
||||
}
|
||||
|
@ -62,6 +65,7 @@ window.player = new class {
|
|||
localStorage.setItem('audio.timeType', value)
|
||||
}
|
||||
|
||||
// <audio> tag
|
||||
get audioPlayer() {
|
||||
return this.__realAudioPlayer
|
||||
}
|
||||
|
@ -231,6 +235,9 @@ window.player = new class {
|
|||
'query': this.context.object.query,
|
||||
}))
|
||||
break
|
||||
case "uploaded":
|
||||
form_data.append('context', this.context.object.name)
|
||||
break
|
||||
case 'alone_audio':
|
||||
form_data.append('context', this.context.object.name)
|
||||
form_data.append('context_entity', this.context.object.entity_id)
|
||||
|
@ -322,6 +329,10 @@ window.player = new class {
|
|||
|
||||
this.__updateFace()
|
||||
u(this.audioPlayer).trigger('volumechange')
|
||||
|
||||
if(this.isAtAudiosPage()) {
|
||||
document.title = ovk_proc_strtr(escapeHtml(`${window.player.currentTrack.performer} — ${window.player.currentTrack.name}`), 255)
|
||||
}
|
||||
}
|
||||
|
||||
hasContext() {
|
||||
|
@ -377,7 +388,7 @@ window.player = new class {
|
|||
}
|
||||
|
||||
await this.setTrack(this.previousTrack.id)
|
||||
if(!this.currentTrack.available || this.currentTrack.withdrawn) {
|
||||
if(/*!this.currentTrack.available || */this.currentTrack.withdrawn) {
|
||||
if(!this.previousTrack) {
|
||||
return
|
||||
}
|
||||
|
@ -394,7 +405,7 @@ window.player = new class {
|
|||
}
|
||||
|
||||
await this.setTrack(this.nextTrack.id)
|
||||
if(!this.currentTrack.available || this.currentTrack.withdrawn) {
|
||||
if(/*!this.currentTrack.available || */this.currentTrack.withdrawn) {
|
||||
if(!this.nextTrack) {
|
||||
return
|
||||
}
|
||||
|
@ -664,6 +675,8 @@ window.player = new class {
|
|||
})
|
||||
}
|
||||
|
||||
// the listen counts if you reach half of song
|
||||
// but it doesnt checks on server normally so you can "накрутить" listens
|
||||
async __countListen() {
|
||||
let playlist = 0
|
||||
if(!this.listen_coef) {
|
||||
|
@ -787,6 +800,10 @@ window.player = new class {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
toggleSummary() {
|
||||
$(".summaryBarHideable").slideToggle(300, "linear")
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", async () => {
|
||||
|
@ -1163,7 +1180,25 @@ u(document).on("drop", '.audiosContainer', function(e) {
|
|||
}
|
||||
})
|
||||
|
||||
u(document).on("click", "#summarySwitchButton", (e) => {
|
||||
if(u(".summaryBarHideable").nodes[0].style.overflow == "hidden") {
|
||||
return
|
||||
}
|
||||
|
||||
if(u(e.target).html() == "-") {
|
||||
u(e.target).html("+")
|
||||
} else {
|
||||
u(e.target).html("-")
|
||||
}
|
||||
|
||||
window.player.toggleSummary()
|
||||
})
|
||||
|
||||
u(document).on('contextmenu', '.bigPlayer, .audioEmbed, #ajax_audio_player', (e) => {
|
||||
if(e.shiftKey) {
|
||||
return
|
||||
}
|
||||
|
||||
e.preventDefault()
|
||||
|
||||
u('#ctx_menu').remove()
|
||||
|
@ -1179,6 +1214,10 @@ u(document).on('contextmenu', '.bigPlayer, .audioEmbed, #ajax_audio_player', (e)
|
|||
x = e.pageX - rx
|
||||
y = e.pageY - ry
|
||||
|
||||
if((rect.height + rect.top) + 100 > window.innerHeight) {
|
||||
y = ((rect.height + 120) * -1)
|
||||
}
|
||||
|
||||
const ctx_u = u(`
|
||||
<div id='ctx_menu' style='top:${y}px;left:${x}px;' data-type='ctx_type'>
|
||||
<a id='audio_ctx_copy'>${tr('copy_link_to_audio')}</a>
|
||||
|
@ -1194,7 +1233,7 @@ u(document).on('contextmenu', '.bigPlayer, .audioEmbed, #ajax_audio_player', (e)
|
|||
<a id='audio_ctx_add_to_playlist'>${tr('audio_ctx_add_to_playlist')}</a>
|
||||
${ctx_type == 'main_player' ? `
|
||||
<a id='audio_ctx_clear_context'>${tr('audio_ctx_clear_context')}</a>` : ''}
|
||||
${ctx_type == 'main_player' ? `<a href='https://github.com/mrilyew' target='_blank'>BigPlayer v1.1 by MrIlyew</a>` : ''}
|
||||
${ctx_type == 'main_player' ? `<a href='https://github.com/mrilyew' target='_blank'>BigPlayer v1.2 by MrIlyew</a>` : ''}
|
||||
</div>
|
||||
`)
|
||||
u(parent).append(ctx_u)
|
||||
|
@ -1948,8 +1987,12 @@ $(document).on("click", ".audioEmbed.processed .playerButton", (e) => {
|
|||
title: tr('error'),
|
||||
body: tr('audio_embed_processing'),
|
||||
unique_name: 'processing_notify',
|
||||
buttons: [tr('ok')],
|
||||
callbacks: [Function.noop]
|
||||
buttons: [tr("audio_embed_processing_bait"), tr('ok')],
|
||||
callbacks: [() => {
|
||||
const pl = u(e.target).closest(".audioEmbed")
|
||||
pl.removeClass("processed")
|
||||
pl.find(".playIcon").trigger("click")
|
||||
}, Function.noop]
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
@ -2471,7 +2471,6 @@ u(document).on('click', '#__sourceAttacher', (e) => {
|
|||
const __checkCopyrightLinkRes = await fetch(`/method/wall.checkCopyrightLink?auth_mechanism=roaming&link=${encodeURIComponent(source_value)}`)
|
||||
const checkCopyrightLink = await __checkCopyrightLinkRes.json()
|
||||
|
||||
// todo переписать блять мессенджбоксы чтоб они классами были
|
||||
if(checkCopyrightLink.error_code) {
|
||||
__removeDialog()
|
||||
switch(checkCopyrightLink.error_code) {
|
||||
|
|
|
@ -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",
|
||||
|
|
3
install/sqls/00055-agent-card-fix.sql
Normal file
3
install/sqls/00055-agent-card-fix.sql
Normal file
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE `support_names`
|
||||
DROP PRIMARY KEY,
|
||||
ADD PRIMARY KEY(`id`);
|
|
@ -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";
|
||||
|
@ -701,6 +703,7 @@
|
|||
"round_avatars" = "Round";
|
||||
|
||||
"apply_style_for_this_device" = "Apply style only for this device";
|
||||
"ui_settings_window" = "Advanced settings";
|
||||
|
||||
"search_for_groups" = "Search for groups";
|
||||
"search_for_users" = "Search for users";
|
||||
|
@ -926,7 +929,8 @@
|
|||
"audio_embed_deleted" = "Audio has been deleted";
|
||||
"audio_embed_withdrawn" = "The audio has been withdrawn at the request of the copyright holder";
|
||||
"audio_embed_forbidden" = "The user's privacy settings do not allow this audio to be embedded";
|
||||
"audio_embed_processing" = "Audio is still being processed or has not been processed correctly.";
|
||||
"audio_embed_processing" = "Audio is processing.";
|
||||
"audio_embed_processing_bait" = "Play anyway";
|
||||
|
||||
"audios_count_zero" = "No audios";
|
||||
"audios_count_one" = "One audio";
|
||||
|
@ -945,6 +949,7 @@
|
|||
"audio_search" = "Search";
|
||||
|
||||
"my_audios_small" = "My audios";
|
||||
"my_audios_small_uploaded" = "Uploaded";
|
||||
"my_playlists" = "My playlists";
|
||||
"playlists" = "Playlists";
|
||||
"audios_explicit" = "Contains obscene language";
|
||||
|
@ -1036,6 +1041,12 @@
|
|||
"audio_ctx_play_next" = "Play next";
|
||||
"audio_ctx_clear_context" = "Clear tracks list";
|
||||
|
||||
"is_x_audio_zero" = "No audios";
|
||||
"is_x_audio_one" = "Just one audio.";
|
||||
"is_x_audio_few" = "Just $1 audios.";
|
||||
"is_x_audio_many" = "Just $1 audios.";
|
||||
"is_x_audio_other" = "Just $1 audios.";
|
||||
|
||||
/* Notifications */
|
||||
|
||||
"feedback" = "Feedback";
|
||||
|
@ -2113,6 +2124,7 @@
|
|||
"s_apps" = "Applications";
|
||||
"s_posts" = "Posts";
|
||||
"s_comments" = "Comments";
|
||||
"s_photos" = "Photos";
|
||||
"s_videos" = "Videos";
|
||||
"s_audios" = "Music";
|
||||
"s_audios_playlists" = "Playlists";
|
||||
|
@ -2223,6 +2235,7 @@
|
|||
"mobile_like" = "Like";
|
||||
"mobile_user_info_hide" = "Hide";
|
||||
"mobile_user_info_show_details" = "Show details";
|
||||
"mobile_attachment_only_for_pc" = "This attachments is not implemented for PDA version. Please, view it on PC.";
|
||||
|
||||
/* Fullscreen player */
|
||||
|
||||
|
@ -2385,3 +2398,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";
|
||||
|
|
|
@ -45,8 +45,8 @@
|
|||
"register_meta_desc" = "$1 желісіне тіркеліңіз!";
|
||||
"register_referer_meta_title" = "$1 сізді $2 желіне шақырады!";
|
||||
"register_referer_meta_desc" = "$1 және одан көп пайдаланушылармен $2 желісінде қосылыңыз!";
|
||||
"registration_welcome_1" = "is a universal colleague search tool based on the VKontakte structure. дегеніміз — VK құрылымына негізделген әмбебап әріптестерді іздеу құралы";
|
||||
"registration_welcome_2" = "Достар, сыныптастар, көршілер мен әріптестер үнемі байланыста болғанын қалаймыз.";
|
||||
"registration_welcome_1" = "дегеніміз — VK құрылымына негізделген әмбебап әріптестерді іздеу құралы";
|
||||
"registration_welcome_2" = "Біз достар, сыныптастар, көршілер мен әріптестер үнемі байланыста болғанын қалаймыз.";
|
||||
"users" = "Пайдаланушылар";
|
||||
"other_fields" = "Қалғаны";
|
||||
|
||||
|
|
|
@ -624,6 +624,8 @@
|
|||
"my_feed" = "Мои Новости";
|
||||
"my_feedback" = "Мои Ответы";
|
||||
"my_settings" = "Мои Настройки";
|
||||
"bookmarks" = "Закладки";
|
||||
"bookmarks_tab" = "Избранное";
|
||||
"bug_tracker" = "Баг-трекер";
|
||||
|
||||
"menu_settings" = "Настройки";
|
||||
|
@ -674,6 +676,7 @@
|
|||
"cut" = "Квадратные";
|
||||
"round_avatars" = "Круглые";
|
||||
"apply_style_for_this_device" = "Применить стиль только для этого устройства";
|
||||
"ui_settings_window" = "Дополнительные настройки";
|
||||
"search_for_groups" = "Поиск групп";
|
||||
"search_for_users" = "Поиск людей";
|
||||
"search_for_posts" = "Поиск записей";
|
||||
|
@ -881,7 +884,8 @@
|
|||
"audio_embed_deleted" = "Аудиозапись была удалена";
|
||||
"audio_embed_withdrawn" = "Аудиозапись была изъята по обращению правообладателя.";
|
||||
"audio_embed_forbidden" = "Настройки приватности пользователя не позволяют встраивать эту композицию";
|
||||
"audio_embed_processing" = "Аудио ещё обрабатывается, либо обработалось неправильно.";
|
||||
"audio_embed_processing" = "Аудио находится в обработке.";
|
||||
"audio_embed_processing_bait" = "Всё равно хочу воспроизвести";
|
||||
|
||||
"audios_count_zero" = "Нет аудиозаписей";
|
||||
"audios_count_one" = "Одна аудиозапись"; /* сингл */
|
||||
|
@ -900,6 +904,7 @@
|
|||
"audio_search" = "Поиск";
|
||||
|
||||
"my_audios_small" = "Мои аудиозаписи";
|
||||
"my_audios_small_uploaded" = "Загруженное";
|
||||
"my_playlists" = "Мои плейлисты";
|
||||
"playlists" = "Плейлисты";
|
||||
"audios_explicit" = "Содержит нецензурную лексику";
|
||||
|
@ -992,6 +997,12 @@
|
|||
"audio_ctx_play_next" = "Воспроизвести следующим";
|
||||
"audio_ctx_clear_context" = "Очистить список треков";
|
||||
|
||||
"is_x_audio_zero" = "Нету аудиозаписей";
|
||||
"is_x_audio_one" = "Всего одна аудиозапись.";
|
||||
"is_x_audio_few" = "Всего $1 аудиозаписи.";
|
||||
"is_x_audio_many" = "Всего $1 аудиозаписей.";
|
||||
"is_x_audio_other" = "Всего $1 аудиозаписей.";
|
||||
|
||||
/* Notifications */
|
||||
|
||||
"feedback" = "Ответы";
|
||||
|
@ -2008,6 +2019,7 @@
|
|||
"s_apps" = "Приложения";
|
||||
"s_posts" = "Записи";
|
||||
"s_comments" = "Комментарии";
|
||||
"s_photos" = "Фотографии";
|
||||
"s_videos" = "Видео";
|
||||
"s_audios" = "Аудио";
|
||||
"s_audios_playlists" = "Плейлисты";
|
||||
|
@ -2118,6 +2130,7 @@
|
|||
"mobile_like" = "Нравится";
|
||||
"mobile_user_info_hide" = "Скрыть";
|
||||
"mobile_user_info_show_details" = "Показать подробнее";
|
||||
"mobile_attachment_only_for_pc" = "Вложение недоступно в PDA версии, его просмотр возможен только с другого устройства";
|
||||
|
||||
/* Fullscreen player */
|
||||
|
||||
|
@ -2280,3 +2293,18 @@
|
|||
"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 закладок";
|
||||
|
||||
|
|
|
@ -597,6 +597,8 @@
|
|||
"my_feedback" = "Мої Відповіді";
|
||||
"my_apps" = "Застосунки";
|
||||
"my_settings" = "Мої Налаштування";
|
||||
"bookmarks" = "Вподобані";
|
||||
"bookmarks_tab" = "Вподобане";
|
||||
"bug_tracker" = "Баг-трекер";
|
||||
|
||||
"menu_settings" = "Налаштування";
|
||||
|
@ -647,6 +649,7 @@
|
|||
"cut" = "Квадратні";
|
||||
"round avatars" = "Круглі";
|
||||
"apply_style_for_this_device" = "Застосувати стиль лише для цього пристрою";
|
||||
"ui_settings_window" = "Додаткові налаштування";
|
||||
"search_for_groups" = "Пошук спільнот";
|
||||
"search_for_users" = "Пошук користувачів";
|
||||
"search_for_posts" = "Пошук дописів";
|
||||
|
@ -853,7 +856,8 @@
|
|||
"audio_embed_deleted" = "Аудіозапис видалено";
|
||||
"audio_embed_withdrawn" = "Аудіозапис було вилучено на вимогу правовласника";
|
||||
"audio_embed_forbidden" = "Налаштування конфіденційності користувача не дозволяють вбудовувати цей аудіозапис";
|
||||
"audio_embed_processing" = "Аудіозапис ще обробляється або було оброблено неправильно.";
|
||||
"audio_embed_processing" = "Аудіозапис ще обробляється або був неправильно оброблений.";
|
||||
"audio_embed_processing_bait" = "Все одно відтворити";
|
||||
|
||||
"audios_count_zero" = "Немає аудіозаписів";
|
||||
"audios_count_one" = "Один аудіозапис";
|
||||
|
@ -872,6 +876,7 @@
|
|||
"audio_search" = "Пошук";
|
||||
|
||||
"my_audios_small" = "Мої аудіозаписи";
|
||||
"my_audios_small_uploaded" = "Завантажене";
|
||||
"my_playlists" = "Мій список відтворення";
|
||||
"playlists" = "Списки відтворення";
|
||||
"audios_explicit" = "Має нецензурну лексику";
|
||||
|
@ -962,6 +967,12 @@
|
|||
"audio_ctx_play_next" = "Відтворити наступним";
|
||||
"audio_ctx_clear_context" = "Очистити список аудіозаписів";
|
||||
|
||||
"is_x_audio_zero" = "Немає аудіозаписів";
|
||||
"is_x_audio_one" = "Один аудіозапис.";
|
||||
"is_x_audio_few" = "Всього $1 аудіозаписа.";
|
||||
"is_x_audio_many" = "Всього $1 аудіозаписів.";
|
||||
"is_x_audio_other" = "Всього $1 аудіозаписів.";
|
||||
|
||||
/* Notifications */
|
||||
|
||||
"feedback" = "Відповіді";
|
||||
|
@ -1977,6 +1988,7 @@
|
|||
"s_apps" = "Застосунки";
|
||||
"s_posts" = "Дописи";
|
||||
"s_comments" = "Коментарі";
|
||||
"s_photos" = "Фотографії";
|
||||
"s_videos" = "Відео";
|
||||
"s_audios" = "Музика";
|
||||
"s_audios_playlists" = "Списки відтворення";
|
||||
|
@ -2087,7 +2099,8 @@
|
|||
"mobile_menu" = "Меню";
|
||||
"mobile_like" = "Подобається";
|
||||
"mobile_user_info_hide" = "Приховувати";
|
||||
"mobile_user_info_show_details" = "Показати докладніше";
|
||||
"mobile_user_info_show_details" = "Відобразити докладніше";
|
||||
"mobile_attachment_only_for_pc" = "Вкладення недоступне в PDA версії, його перегляд можливий тільки з іншого пристрою";
|
||||
"my" = "Мої";
|
||||
"enter_a_name_or_artist" = "Введіть назву або виконавця...";
|
||||
|
||||
|
@ -2237,4 +2250,18 @@
|
|||
"documents_sort_size" = "За розміром";
|
||||
"select_doc" = "Вибір документа";
|
||||
"no_documents" = "Документів немає";
|
||||
"go_to_my_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
|
|
@ -660,3 +660,26 @@ ul {
|
|||
.doc_icon.no_image span::before {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAKCAYAAABmBXS+AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsAAAA7AAWrWiQkAAABXSURBVChTY2RAAoFe9ZuEBOR93314uHn9tkY/qDADE5QGA5ACZBoGUBThAkQpYkyOmvcfysYJiDMJROAzbe6yJEZ4EGBTCFIAolHCCVkhTAFWgGkiAwMAzxkZ3qVQ7YEAAAAASUVORK5CYII=");
|
||||
}
|
||||
|
||||
.bigPlayer .bigPlayerWrapper .absoluteButtons > div {
|
||||
background: #1e1a2b;
|
||||
border: 1px solid #2c2640;
|
||||
}
|
||||
|
||||
.insertedPhoto {
|
||||
background: #1e1a2b;
|
||||
border: 1px solid #403a56;
|
||||
}
|
||||
|
||||
.ovk-modal-player-window #ovk-player-info {
|
||||
background: #0e0b1a;
|
||||
}
|
||||
|
||||
.header_navigation #search_box #searchBoxFastTips {
|
||||
background: #181826;
|
||||
border-color: #2c2640;
|
||||
}
|
||||
|
||||
.header_navigation #search_box #searchBoxFastTips a:hover, .header_navigation #search_box #searchBoxFastTips a:focus {
|
||||
background: #111322;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue