Compare commits

..

No commits in common. "85c7703e267217e2695fd639cc75b95151abe6a6" and "a4d5bb8088e74ce3a9ffa411a2d4447c4ed84124" have entirely different histories.

100 changed files with 3994 additions and 5109 deletions

View file

@ -1,6 +1,14 @@
name: Build images
on: [push, pull_request]
on:
push:
# Publish `master` as Docker `latest` image.
branches:
- master
# Publish `v1.2.3` tags as releases.
tags:
- v*
env:
BASE_IMAGE_NAME: openvk
@ -9,21 +17,24 @@ env:
DB_VERSION: "10.9"
jobs:
buildbase:
name: Build base images
build:
runs-on: ubuntu-latest
strategy:
matrix:
platform: [amd64, arm64]
runs-on: ubuntu-latest
arch: ['x86_64']
if: github.event_name == 'push'
steps:
- uses: actions/checkout@v3
with:
lfs: false
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v2
- name: Change repository string to lowercase
id: repositorystring
@ -31,114 +42,29 @@ jobs:
with:
string: ${{ github.repository }}
- name: Base image meta
id: basemeta
uses: docker/metadata-action@v5
with:
images: |
ghcr.io/${{ steps.repositorystring.outputs.lowercase }}/${{env.BASE_IMAGE_NAME}}
labels: |
org.opencontainers.image.documentation=https://github.com/OpenVK/openvk/blob/master/install/automated/docker/Readme.md
tags: |
type=sha
type=ref,event=branch
type=ref,event=pr
type=ref,event=tag
type=raw,value=latest,enable={{is_default_branch}}
- name: Log into registry
if: github.event_name != 'pull_request'
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Build base image
uses: docker/build-push-action@v6
with:
platforms: linux/${{matrix.platform}}
file: install/automated/docker/openvk.Dockerfile
tags: ${{ steps.basemeta.outputs.tags }}
labels: ${{ steps.basemeta.outputs.labels }}
push: ${{ github.event_name != 'pull_request' }}
build-args: |
GITREPO=${{ steps.repositorystring.outputs.lowercase }}
run: |
IMAGE_ID=ghcr.io/${{ steps.repositorystring.outputs.lowercase }}/$BASE_IMAGE_NAME
IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
[[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')
[ "$VERSION" == "master" ] && VERSION=latest
echo IMAGE_ID=$IMAGE_ID
echo VERSION=$VERSION
builddb:
name: Build DB images
strategy:
matrix:
platform: [amd64, arm64]
runs-on: ubuntu-latest
steps:
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3
- name: Change repository string to lowercase
id: repositorystring
uses: Entepotenz/change-string-case-action-min-dependencies@v1.1.0
with:
string: ${{ github.repository }}
- name: MariaDB primary meta
id: db-primarymeta
uses: docker/metadata-action@v5
with:
images: |
ghcr.io/${{ steps.repositorystring.outputs.lowercase }}/${{env.DB_IMAGE_NAME}}
labels: |
org.opencontainers.image.title=OpenVK MariaDB (Primary)
org.opencontainers.image.description=OpenVK's image for MariaDB for primary database.
org.opencontainers.image.documentation=https://github.com/OpenVK/openvk/blob/master/install/automated/docker/Readme.md
tags: |
type=sha,prefix=${{env.DB_VERSION}}-primary-sha-
type=ref,event=branch,prefix=${{env.DB_VERSION}}-primary-
type=ref,event=pr,prefix=${{env.DB_VERSION}}-primary-pr-
type=ref,event=tag,prefix=${{env.DB_VERSION}}-primary-
type=raw,value=${{env.DB_VERSION}}-primary,enable={{is_default_branch}}
- name: MariaDB event meta
id: db-eventmeta
uses: docker/metadata-action@v5
with:
images: |
ghcr.io/${{ steps.repositorystring.outputs.lowercase }}/${{env.DB_IMAGE_NAME}}
labels: |
org.opencontainers.image.title=OpenVK MariaDB (EventDB)
org.opencontainers.image.description=OpenVK's image for MariaDB for event database.
org.opencontainers.image.documentation=https://github.com/OpenVK/openvk/blob/master/install/automated/docker/Readme.md
tags: |
type=sha,prefix=${{env.DB_VERSION}}-eventdb-sha-
type=ref,event=branch,prefix=${{env.DB_VERSION}}-eventdb-
type=ref,event=pr,prefix=${{env.DB_VERSION}}-eventdb-pr-
type=ref,event=tag,prefix=${{env.DB_VERSION}}-eventdb-
type=raw,value=${{env.DB_VERSION}}-eventdb,enable={{is_default_branch}}
- name: Log into registry
if: github.event_name != 'pull_request'
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
docker buildx build --platform linux/amd64,linux/arm64 -t $IMAGE_ID:$VERSION . --push -f install/automated/docker/openvk.Dockerfile --build-arg GITREPO=${{ steps.repositorystring.outputs.lowercase }}
- name: Build MariaDB primary image
uses: docker/build-push-action@v6
with:
push: ${{ github.event_name != 'pull_request' }}
platforms: linux/${{matrix.platform}}
file: install/automated/docker/mariadb-primary.Dockerfile
tags: ${{ steps.db-primarymeta.outputs.tags }}
labels: ${{ steps.db-primarymeta.outputs.labels }}
build-args: |
VERSION=${{env.DB_VERSION}}
run: |
IMAGE_NAME=ghcr.io/${{ steps.repositorystring.outputs.lowercase }}/$DB_IMAGE_NAME:$DB_VERSION-primary
docker buildx build --platform linux/amd64,linux/arm64 -t $IMAGE_NAME . --push -f install/automated/docker/mariadb-primary.Dockerfile --build-arg VERSION=$DB_VERSION
- name: Build MariaDB event image
uses: docker/build-push-action@v6
with:
push: ${{ github.event_name != 'pull_request' }}
platforms: linux/${{matrix.platform}}
file: install/automated/docker/mariadb-eventdb.Dockerfile
tags: ${{ steps.db-eventmeta.outputs.tags }}
labels: ${{ steps.db-eventmeta.outputs.labels }}
build-args: |
VERSION=${{env.DB_VERSION}}
run: |
IMAGE_NAME=ghcr.io/${{ steps.repositorystring.outputs.lowercase }}/$EVENT_IMAGE_NAME:$DB_VERSION-eventdb
docker buildx build --platform linux/amd64,linux/arm64 -t $IMAGE_NAME . --push -f install/automated/docker/mariadb-eventdb.Dockerfile --build-arg VERSION=$DB_VERSION

View file

@ -4,7 +4,7 @@ _[Русский](README_RU.md)_
**OpenVK** is an attempt to create a simple CMS that ~~cosplays~~ imitates old VKontakte. Code provided here is not stable yet.
VKontakte belongs to VK (formerly Mail.ru Group).
VKontakte belongs to Pavel Durov and VK Group.
To be honest, we don't know whether if it even works. However, this version is maintained and we will be happy to accept your bugreports [in our bug tracker](https://github.com/openvk/openvk/projects/1). You should also be able to submit them using [ticketing system](https://ovk.to/support?act=new) (you will need an OpenVK account for this).
@ -36,7 +36,7 @@ Here is our minimum hardware recommendation:
### Installation procedure
1. Install PHP 7.4, web-server, Composer, Node.js, NPM and [Chandler](https://github.com/openvk/chandler)
1. Install PHP 7.4, web-server, Composer, Node.js, Yarn and [Chandler](https://github.com/openvk/chandler)
* PHP 8 is still being tested; the functionality of the engine on this version of PHP is not yet guaranteed.
@ -65,7 +65,7 @@ ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions
7. Copy `openvk-example.yml` to `openvk.yml` and change options to your liking
8. Run `composer install` in OpenVK directory
9. Run `composer install` in commitcaptcha directory
10. Move to `Web/static/js` and execute `npm install`
10. Move to `Web/static/js` and execute `yarn install`
11. Set `openvk` as your root app in `chandler.yml`
Once you are done, you can login as a system administrator on the network itself (no registration required):

View file

@ -4,7 +4,7 @@ _[English](README.md)_
**OpenVK** — это попытка создать простую CMS, которая ~~косплеит~~ имитирует старый ВКонтакте. На данный момент, представленный здесь исходный код проекта пока не является стабильным.
ВКонтакте принадлежит VK (в прошлом Mail.ru Group).
ВКонтакте принадлежит Павлу Дурову и VK Group.
Честно говоря, мы даже не знаем, работает ли она вообще. Однако, эта версия поддерживается, и мы будем рады принять ваши сообщения об ошибках [в нашем баг-трекере](https://github.com/openvk/openvk/projects/1). Вы также можете отправлять их через [вкладку "Помощь"](https://ovk.to/support?act=new) (для этого вам понадобится учетная запись OpenVK).
@ -28,7 +28,7 @@ _[English](README.md)_
### Процедура установки
1. Установите PHP 7.4, веб-сервер, Composer, Node.js, NPM и [Chandler](https://github.com/openvk/chandler)
1. Установите PHP 7.4, веб-сервер, Composer, Node.js, Yarn и [Chandler](https://github.com/openvk/chandler)
* PHP 8 пока ещё тестируется, работоспособность движка на этой версии PHP пока не гарантируется.
@ -57,7 +57,7 @@ ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions
7. Скопируйте `openvk-example.yml` в `openvk.yml` и измените параметры под свои нужды
8. Запустите `composer install` в директории OpenVK
9. Запустите `composer install` в директории commitcaptcha
10. Перейдите в `Web/static/js` и выполните `npm install`
10. Перейдите в `Web/static/js` и выполните `yarn install`
11. Установите `openvk` в качестве корневого приложения в файле `chandler.yml`
После этого вы можете войти как системный администратор в саму сеть (регистрация не требуется):

92
ServiceAPI/Photos.php Normal file
View file

@ -0,0 +1,92 @@
<?php declare(strict_types=1);
namespace openvk\ServiceAPI;
use openvk\Web\Models\Entities\User;
use openvk\Web\Models\Repositories\{Photos as PhotosRepo, Albums, Clubs};
class Photos implements Handler
{
protected $user;
protected $photos;
function __construct(?User $user)
{
$this->user = $user;
$this->photos = new PhotosRepo;
}
function getPhotos(int $page = 1, int $album = 0, callable $resolve, callable $reject)
{
if($album == 0) {
$photos = $this->photos->getEveryUserPhoto($this->user, $page, 24);
$count = $this->photos->getUserPhotosCount($this->user);
} else {
$album = (new Albums)->get($album);
if(!$album || $album->isDeleted())
$reject(55, "Invalid .");
if($album->getOwner() instanceof User) {
if($album->getOwner()->getId() != $this->user->getId())
$reject(555, "Access to album denied");
} else {
if(!$album->getOwner()->canBeModifiedBy($this->user))
$reject(555, "Access to album denied");
}
$photos = $album->getPhotos($page, 24);
$count = $album->size();
}
$arr = [
"count" => $count,
"items" => [],
];
foreach($photos as $photo) {
$res = json_decode(json_encode($photo->toVkApiStruct()), true);
$arr["items"][] = $res;
}
$resolve($arr);
}
function getAlbums(int $club, callable $resolve, callable $reject)
{
$albumsRepo = (new Albums);
$count = $albumsRepo->getUserAlbumsCount($this->user);
$albums = $albumsRepo->getUserAlbums($this->user, 1, $count);
$arr = [
"count" => $count,
"items" => [],
];
foreach($albums as $album) {
$res = ["id" => $album->getId(), "name" => $album->getName()];
$arr["items"][] = $res;
}
if($club > 0) {
$cluber = (new Clubs)->get($club);
if(!$cluber || !$cluber->canBeModifiedBy($this->user))
$reject(1337, "Invalid (club), or you can't modify him");
$clubCount = (new Albums)->getClubAlbumsCount($cluber);
$clubAlbums = (new Albums)->getClubAlbums($cluber, 1, $clubCount);
foreach($clubAlbums as $albumr) {
$res = ["id" => $albumr->getId(), "name" => $albumr->getName()];
$arr["items"][] = $res;
}
$arr["count"] = $arr["count"] + $clubCount;
}
$resolve($arr);
}
}

156
ServiceAPI/Video.php Normal file
View file

@ -0,0 +1,156 @@
<?php declare(strict_types=1);
namespace openvk\ServiceAPI;
use openvk\Web\Models\Entities\{User, Post};
use openvk\Web\Models\Repositories\{Videos, Comments, Clubs};
use Chandler\MVC\Routing\Router;
class Video implements Handler
{
protected $user;
protected $videos;
protected $comments;
protected $groups;
function __construct(?User $user)
{
$this->user = $user;
$this->videos = new Videos;
$this->comments = new Comments;
$this->groups = new Clubs;
}
function getVideo(int $id, callable $resolve, callable $reject)
{
$video = $this->videos->get($id);
if(!$video || $video->isDeleted()) {
$reject(2, "Video does not exists");
}
if(method_exists($video, "canBeViewedBy") && !$video->canBeViewedBy($this->user)) {
$reject(4, "Access to video denied");
}
if(!$video->getOwner()->getPrivacyPermission('videos.read', $this->user)) {
$reject(8, "Access to video denied: this user chose to hide his videos");
}
$prevVideo = NULL;
$nextVideo = NULL;
$lastVideo = $this->videos->getLastVideo($video->getOwner());
if($video->getVirtualId() - 1 != 0) {
for($i = $video->getVirtualId(); $i != 0; $i--) {
$maybeVideo = (new Videos)->getByOwnerAndVID($video->getOwner()->getId(), $i);
if(!is_null($maybeVideo) && !$maybeVideo->isDeleted() && $maybeVideo->getId() != $video->getId()) {
if(method_exists($maybeVideo, "canBeViewedBy") && !$maybeVideo->canBeViewedBy($this->user)) {
continue;
}
$prevVideo = $maybeVideo;
break;
}
}
}
if(is_null($lastVideo) || $lastVideo->getId() == $video->getId()) {
$nextVideo = NULL;
} else {
for($i = $video->getVirtualId(); $i <= $lastVideo->getVirtualId(); $i++) {
$maybeVideo = (new Videos)->getByOwnerAndVID($video->getOwner()->getId(), $i);
if(!is_null($maybeVideo) && !$maybeVideo->isDeleted() && $maybeVideo->getId() != $video->getId()) {
if(method_exists($maybeVideo, "canBeViewedBy") && !$maybeVideo->canBeViewedBy($this->user)) {
continue;
}
$nextVideo = $maybeVideo;
break;
}
}
}
$res = [
"id" => $video->getId(),
"title" => $video->getName(),
"owner" => $video->getOwner()->getId(),
"commentsCount" => $video->getCommentsCount(),
"description" => $video->getDescription(),
"type" => $video->getType(),
"name" => $video->getOwner()->getCanonicalName(),
"pretty_id" => $video->getPrettyId(),
"virtual_id" => $video->getVirtualId(),
"published" => (string)$video->getPublicationTime(),
"likes" => $video->getLikesCount(),
"has_like" => $video->hasLikeFrom($this->user),
"author" => $video->getOwner()->getCanonicalName(),
"canBeEdited" => $video->getOwner()->getId() == $this->user->getId(),
"isProcessing" => $video->getType() == 0 && $video->getURL() == "/assets/packages/static/openvk/video/rendering.mp4",
"prevVideo" => !is_null($prevVideo) ? $prevVideo->getId() : null,
"nextVideo" => !is_null($nextVideo) ? $nextVideo->getId() : null,
];
if($video->getType() == 1) {
$res["embed"] = $video->getVideoDriver()->getEmbed();
} else {
$res["url"] = $video->getURL();
}
$resolve($res);
}
function shareVideo(int $owner, int $vid, int $type, string $message, int $club, bool $signed, bool $asGroup, callable $resolve, callable $reject)
{
$video = $this->videos->getByOwnerAndVID($owner, $vid);
if(!$video || $video->isDeleted()) {
$reject(16, "Video does not exists");
}
if(method_exists($video, "canBeViewedBy") && !$video->canBeViewedBy($this->user)) {
$reject(32, "Access to video denied");
}
if(!$video->getOwner()->getPrivacyPermission('videos.read', $this->user)) {
$reject(8, "Access to video denied: this user chose to hide his videos");
}
$flags = 0;
$nPost = new Post;
$nPost->setOwner($this->user->getId());
if($type == 0) {
$nPost->setWall($this->user->getId());
} else {
$club = $this->groups->get($club);
if(!$club || $club->isDeleted() || !$club->canBeModifiedBy($this->user)) {
$reject(64, "Can't do repost to this club");
}
if($asGroup)
$flags |= 0b10000000;
if($signed)
$flags |= 0b01000000;
$nPost->setWall($club->getId() * -1);
}
$nPost->setContent($message);
$nPost->setFlags($flags);
$nPost->save();
$nPost->attach($video);
$res = [
"id" => $nPost->getId(),
"pretty_id" => $nPost->getPrettyId(),
];
$resolve($res);
}
}

View file

@ -80,4 +80,67 @@ class Wall implements Handler
$resolve($post->getId());
}
function getMyNotes(callable $resolve, callable $reject)
{
$count = $this->notes->getUserNotesCount($this->user);
$myNotes = $this->notes->getUserNotes($this->user, 1, $count);
$arr = [
"count" => $count,
"closed" => $this->user->getPrivacySetting("notes.read"),
"items" => [],
];
foreach($myNotes as $note) {
$arr["items"][] = [
"id" => $note->getId(),
"name" => ovk_proc_strtr($note->getName(), 30),
#"preview" => $note->getPreview()
];
}
$resolve($arr);
}
function getVideos(int $page = 1, callable $resolve, callable $reject)
{
$videos = $this->videos->getByUser($this->user, $page, 8);
$count = $this->videos->getUserVideosCount($this->user);
$arr = [
"count" => $count,
"items" => [],
];
foreach($videos as $video) {
$res = json_decode(json_encode($video->toVkApiStruct($this->user)), true);
$res["video"]["author_name"] = $video->getOwner()->getCanonicalName();
$arr["items"][] = $res;
}
$resolve($arr);
}
function searchVideos(int $page = 1, string $query, callable $resolve, callable $reject)
{
$dbc = $this->videos->find($query);
$videos = $dbc->page($page, 8);
$count = $dbc->size();
$arr = [
"count" => $count,
"items" => [],
];
foreach($videos as $video) {
$res = json_decode(json_encode($video->toVkApiStruct($this->user)), true);
$res["video"]["author_name"] = $video->getOwner()->getCanonicalName();
$arr["items"][] = $res;
}
$resolve($arr);
}
}

View file

@ -11,12 +11,6 @@ final class Groups extends VKAPIRequestHandler
{
$this->requireUser();
# InfoApp fix
if($filter == "admin" && ($user_id != 0 && $user_id != $this->getUser()->getId())) {
$this->fail(15, 'Access denied: filter admin is available only for current user');
}
$clbs = [];
if($user_id == 0) {
foreach($this->getUser()->getClubs($offset, $filter == "admin", $count, true) as $club)
$clbs[] = $club;

View file

@ -32,7 +32,6 @@ final class Newsfeed extends VKAPIRequestHandler
->select("id")
->where("wall IN (?)", $ids)
->where("deleted", 0)
->where("suggested", 0)
->where("id < (?)", empty($start_from) ? PHP_INT_MAX : $start_from)
->where("? <= created", empty($start_time) ? 0 : $start_time)
->where("? >= created", empty($end_time) ? PHP_INT_MAX : $end_time)
@ -57,15 +56,6 @@ final class Newsfeed extends VKAPIRequestHandler
if($this->getUser()->getNsfwTolerance() === User::NSFW_INTOLERANT)
$queryBase .= " AND `nsfw` = 0";
if($return_banned == 0) {
$ignored_sources_ids = $this->getUser()->getIgnoredSources(0, OPENVK_ROOT_CONF['openvk']['preferences']['newsfeed']['ignoredSourcesLimit'] ?? 50, true);
if(sizeof($ignored_sources_ids) > 0) {
$imploded_ids = implode("', '", $ignored_sources_ids);
$queryBase .= " AND `posts`.`wall` NOT IN ('$imploded_ids')";
}
}
$start_from = empty($start_from) ? PHP_INT_MAX : $start_from;
$start_time = empty($start_time) ? 0 : $start_time;
@ -84,152 +74,4 @@ final class Newsfeed extends VKAPIRequestHandler
return $response;
}
function getByType(string $feed_type = 'top', string $fields = "", int $start_from = 0, int $start_time = 0, int $end_time = 0, int $offset = 0, int $count = 30, int $extended = 0, int $return_banned = 0)
{
$this->requireUser();
switch($feed_type) {
case 'top':
return $this->getGlobal($fields, $start_from, $start_time, $end_time, $offset, $count, $extended, $return_banned);
break;
default:
return $this->get($fields, $start_from, $start_time, $end_time, $offset, $count, $extended);
break;
}
}
function getBanned(int $extended = 0, string $fields = "", string $name_case = "nom", int $merge = 0): object
{
$this->requireUser();
$offset = 0;
$count = OPENVK_ROOT_CONF['openvk']['preferences']['newsfeed']['ignoredSourcesLimit'] ?? 50;
$banned = $this->getUser()->getIgnoredSources($offset, $count, ($extended != 1));
$return_object = (object) [
'groups' => [],
'members' => [],
];
if($extended == 0) {
foreach($banned as $ban) {
if($ban > 0)
$return_object->members[] = $ban;
else
$return_object->groups[] = $ban;
}
} else {
if($merge == 1) {
$return_object = (object) [
'count' => sizeof($banned),
'items' => [],
];
foreach($banned as $ban) {
$return_object->items[] = $ban->toVkApiStruct($this->getUser(), $fields);
}
} else {
$return_object = (object) [
'groups' => [],
'profiles' => [],
];
foreach($banned as $ban) {
if($ban->getRealId() > 0)
$return_object->profiles[] = $ban->toVkApiStruct($this->getUser(), $fields);
else
$return_object->groups[] = $ban->toVkApiStruct($this->getUser(), $fields);
}
}
}
return $return_object;
}
function addBan(string $user_ids = "", string $group_ids = "")
{
$this->requireUser();
$this->willExecuteWriteAction();
# Formatting input ids
if(!empty($user_ids)) {
$user_ids = array_map(function($el) {
return (int)$el;
}, explode(',', $user_ids));
$user_ids = array_unique($user_ids);
} else
$user_ids = [];
if(!empty($group_ids)) {
$group_ids = array_map(function($el) {
return abs((int)$el) * -1;
}, explode(',', $group_ids));
$group_ids = array_unique($group_ids);
} else
$group_ids = [];
$ids = array_merge($user_ids, $group_ids);
if(sizeof($ids) < 1)
return 0;
if(sizeof($ids) > 10)
$this->fail(-10, "Limit of 'ids' is 10");
$config_limit = OPENVK_ROOT_CONF['openvk']['preferences']['newsfeed']['ignoredSourcesLimit'] ?? 50;
$user_ignores = $this->getUser()->getIgnoredSourcesCount();
if(($user_ignores + sizeof($ids)) > $config_limit) {
$this->fail(-50, "Ignoring limit exceeded");
}
$entities = get_entities($ids);
$successes = 0;
foreach($entities as $entity) {
if(!$entity || $entity->getRealId() === $this->getUser()->getRealId() || $entity->isHideFromGlobalFeedEnabled() || $entity->isIgnoredBy($this->getUser())) continue;
$entity->addIgnore($this->getUser());
$successes += 1;
}
return 1;
}
function deleteBan(string $user_ids = "", string $group_ids = "")
{
$this->requireUser();
$this->willExecuteWriteAction();
if(!empty($user_ids)) {
$user_ids = array_map(function($el) {
return (int)$el;
}, explode(',', $user_ids));
$user_ids = array_unique($user_ids);
} else
$user_ids = [];
if(!empty($group_ids)) {
$group_ids = array_map(function($el) {
return abs((int)$el) * -1;
}, explode(',', $group_ids));
$group_ids = array_unique($group_ids);
} else
$group_ids = [];
$ids = array_merge($user_ids, $group_ids);
if(sizeof($ids) < 1)
return 0;
if(sizeof($ids) > 10)
$this->fail(-10, "Limit of ids is 10");
$entities = get_entities($ids);
$successes = 0;
foreach($entities as $entity) {
if(!$entity || $entity->getRealId() === $this->getUser()->getRealId() || !$entity->isIgnoredBy($this->getUser())) continue;
$entity->removeIgnore($this->getUser());
$successes += 1;
}
return 1;
}
}

View file

@ -427,7 +427,7 @@ final class Photos extends VKAPIRequestHandler
$this->fail(15, "Access denied");
$photos = array_slice(iterator_to_array($album->getPhotos(1, $count + $offset)), $offset);
$res["count"] = $album->size();
$res["count"] = sizeof($photos);
foreach($photos as $photo) {
if(!$photo || $photo->isDeleted()) continue;
@ -638,15 +638,15 @@ final class Photos extends VKAPIRequestHandler
$this->fail(4, "This method doesn't works with clubs");
$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.");
$photos = (new PhotosRepo)->getEveryUserPhoto($user, $offset, $count);
$photos = array_slice(iterator_to_array((new PhotosRepo)->getEveryUserPhoto($user, 1, $count + $offset)), $offset);
$res = [
"count" => (new PhotosRepo)->getUserPhotosCount($user),
"items" => [],
];

View file

@ -11,55 +11,24 @@ use openvk\Web\Models\Repositories\Comments as CommentsRepo;
final class Video extends VKAPIRequestHandler
{
function get(int $owner_id = 0, string $videos = "", string $fields = "", int $offset = 0, int $count = 30, int $extended = 0): object
function get(int $owner_id, string $videos = "", int $offset = 0, int $count = 30, int $extended = 0): object
{
$this->requireUser();
if(!empty($videos)) {
$vids = explode(',', $videos);
$profiles = [];
$groups = [];
foreach($vids as $vid) {
foreach($vids as $vid)
{
$id = explode("_", $vid);
$items = [];
$video = (new VideosRepo)->getByOwnerAndVID(intval($id[0]), intval($id[1]));
if($video && !$video->isDeleted()) {
$out_video = $video->getApiStructure($this->getUser())->video;
$items[] = $out_video;
if($out_video['owner_id']) {
if($out_video['owner_id'] > 0)
$profiles[] = $out_video['owner_id'];
else
$groups[] = abs($out_video['owner_id']);
}
if($video) {
$items[] = $video->getApiStructure($this->getUser());
}
}
if($extended == 1) {
$profiles = array_unique($profiles);
$groups = array_unique($groups);
$profilesFormatted = [];
$groupsFormatted = [];
foreach($profiles as $prof) {
$profile = (new UsersRepo)->get($prof);
$profilesFormatted[] = $profile->toVkApiStruct($this->getUser(), $fields);
}
foreach($groups as $gr) {
$group = (new ClubsRepo)->get($gr);
$groupsFormatted[] = $group->toVkApiStruct($this->getUser(), $fields);
}
return (object) [
"count" => sizeof($items),
"items" => $items,
"profiles" => $profilesFormatted,
"groups" => $groupsFormatted,
];
}
return (object) [
"count" => count($items),
@ -77,46 +46,12 @@ final class Video extends VKAPIRequestHandler
if(!$user->getPrivacyPermission('videos.read', $this->getUser()))
$this->fail(21, "This user chose to hide his videos.");
$videos = (new VideosRepo)->getByUserLimit($user, $offset, $count);
$videos = (new VideosRepo)->getByUser($user, $offset + 1, $count);
$videosCount = (new VideosRepo)->getUserVideosCount($user);
$items = [];
$profiles = [];
$groups = [];
foreach($videos as $video) {
$video = $video->getApiStructure($this->getUser())->video;
$items[] = $video;
if($video['owner_id']) {
if($video['owner_id'] > 0)
$profiles[] = $video['owner_id'];
else
$groups[] = abs($video['owner_id']);
}
}
if($extended == 1) {
$profiles = array_unique($profiles);
$groups = array_unique($groups);
$profilesFormatted = [];
$groupsFormatted = [];
foreach($profiles as $prof) {
$profile = (new UsersRepo)->get($prof);
$profilesFormatted[] = $profile->toVkApiStruct($this->getUser(), $fields);
}
foreach($groups as $gr) {
$group = (new ClubsRepo)->get($gr);
$groupsFormatted[] = $group->toVkApiStruct($this->getUser(), $fields);
}
return (object) [
"count" => $videosCount,
"items" => $items,
"profiles" => $profilesFormatted,
"groups" => $groupsFormatted,
];
foreach ($videos as $video) {
$items[] = $video->getApiStructure($this->getUser());
}
return (object) [

View file

@ -284,16 +284,12 @@ final class Wall extends VKAPIRequestHandler
foreach($psts as $pst) {
$id = explode("_", $pst);
$post = (new PostsRepo)->getPostById(intval($id[0]), intval($id[1]), true);
$post = (new PostsRepo)->getPostById(intval($id[0]), intval($id[1]));
if($post && !$post->isDeleted()) {
if(!$post->canBeViewedBy($this->getUser()))
continue;
if($post->getSuggestionType() != 0 && !$post->canBeEditedBy($this->getUser())) {
continue;
}
$from_id = get_class($post->getOwner()) == "openvk\Web\Models\Entities\Club" ? $post->getOwner()->getId() * (-1) : $post->getOwner()->getId();
$attachments = [];
$repost = []; // чел высрал семь сигарет 😳 помянем 🕯
@ -477,7 +473,7 @@ final class Wall extends VKAPIRequestHandler
];
}
function post(string $owner_id, string $message = "", string $copyright = "", int $from_group = 0, int $signed = 0, string $attachments = "", int $post_id = 0): object
function post(string $owner_id, string $message = "", int $from_group = 0, int $signed = 0, string $attachments = "", int $post_id = 0): object
{
$this->requireUser();
$this->willExecuteWriteAction();
@ -555,17 +551,7 @@ final class Wall extends VKAPIRequestHandler
if($signed == 1)
$flags |= 0b01000000;
$parsed_attachments = parseAttachments($attachments, ['photo', 'video', 'note', 'poll', 'audio']);
$final_attachments = [];
$should_be_suggested = $owner_id < 0 && !$wallOwner->canBeModifiedBy($this->getUser()) && $wallOwner->getWallType() == 2;
foreach($parsed_attachments as $attachment) {
if($attachment && !$attachment->isDeleted() && $attachment->canBeViewedBy($this->getUser()) &&
!(method_exists($attachment, 'getVoters') && $attachment->getOwner()->getId() != $this->getUser()->getId())) {
$final_attachments[] = $attachment;
}
}
if((empty($message) && (empty($attachments) || sizeof($final_attachments) < 1)))
if(empty($message) && empty($attachments))
$this->fail(100, "Required parameter 'message' missing.");
try {
@ -583,7 +569,7 @@ final class Wall extends VKAPIRequestHandler
} catch(\Throwable) {}
}
if($should_be_suggested)
if($owner_id < 0 && !$wallOwner->canBeModifiedBy($this->getUser()) && $wallOwner->getWallType() == 2)
$post->setSuggested(1);
$post->save();
@ -591,70 +577,134 @@ final class Wall extends VKAPIRequestHandler
$this->fail(100, "One of the parameters specified was missing or invalid");
}
foreach($final_attachments as $attachment) {
$post->attach($attachment);
# TODO use parseAttachments
if(!empty($attachments)) {
$attachmentsArr = explode(",", $attachments);
# Аттачи такого вида: [тип][id владельца]_[id вложения]
# Пример: photo1_1
if(sizeof($attachmentsArr) > 10)
$this->fail(50, "Too many attachments");
preg_match_all("/poll/m", $attachments, $matches, PREG_SET_ORDER, 0);
if(sizeof($matches) > 1)
$this->fail(85, "Too many polls");
foreach($attachmentsArr as $attac) {
$attachmentType = NULL;
if(str_contains($attac, "photo"))
$attachmentType = "photo";
elseif(str_contains($attac, "video"))
$attachmentType = "video";
elseif(str_contains($attac, "note"))
$attachmentType = "note";
elseif(str_contains($attac, "poll"))
$attachmentType = "poll";
elseif(str_contains($attac, "audio"))
$attachmentType = "audio";
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, "Invalid photo");
if(!$attacc->getOwner()->getPrivacyPermission('photos.read', $this->getUser()))
$this->fail(43, "Access to photo denied");
$post->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()->getPrivacyPermission('videos.read', $this->getUser()))
$this->fail(43, "Access to video denied");
$post->attach($attacc);
} elseif($attachmentType == "note") {
$attacc = (new NotesRepo)->getNoteById($attachmentOwner, $attachmentId);
if(!$attacc || $attacc->isDeleted())
$this->fail(100, "Note does not exist");
if(!$attacc->getOwner()->getPrivacyPermission('notes.read', $this->getUser()))
$this->fail(11, "Access to note denied");
$post->attach($attacc);
} elseif($attachmentType == "poll") {
$attacc = (new PollsRepo)->get($attachmentId);
if(!$attacc || $attacc->isDeleted())
$this->fail(100, "Poll does not exist");
if($attacc->getOwner()->getId() != $this->getUser()->getId())
$this->fail(43, "You do not have access to this poll");
$post->attach($attacc);
} elseif($attachmentType == "audio") {
$attacc = (new AudiosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
if(!$attacc || $attacc->isDeleted())
$this->fail(100, "Audio does not exist");
$post->attach($attacc);
}
}
}
if($wall > 0 && $wall !== $this->user->identity->getId())
(new WallPostNotification($wallOwner, $post, $this->user->identity))->emit();
if($owner_id < 0 && !$wallOwner->canBeModifiedBy($this->getUser()) && $wallOwner->getWallType() == 2) {
$suggsCount = (new PostsRepo)->getSuggestedPostsCount($wallOwner->getId());
if($suggsCount % 10 == 0) {
$managers = $wallOwner->getManagers();
$owner = $wallOwner->getOwner();
(new NewSuggestedPostsNotification($owner, $wallOwner))->emit();
foreach($managers as $manager) {
(new NewSuggestedPostsNotification($manager->getUser(), $wallOwner))->emit();
}
}
return (object)["post_id" => "on_view"];
}
return (object)["post_id" => $post->getVirtualId()];
}
function repost(string $object, string $message = "", string $attachments = "", int $group_id = 0, int $as_group = 0, int $signed = 0) {
function repost(string $object, string $message = "", int $group_id = 0) {
$this->requireUser();
$this->willExecuteWriteAction();
$postArray;
if(preg_match('/(wall|video|photo)((?:-?)[0-9]+)_([0-9]+)/', $object, $postArray) == 0)
if(preg_match('/wall((?:-?)[0-9]+)_([0-9]+)/', $object, $postArray) == 0)
$this->fail(100, "One of the parameters specified was missing or invalid: object is incorrect");
$parsed_attachments = parseAttachments($attachments, ['photo', 'video', 'note', 'audio']);
$final_attachments = [];
foreach($parsed_attachments as $attachment) {
if($attachment && !$attachment->isDeleted() && $attachment->canBeViewedBy($this->getUser()) &&
!(method_exists($attachment, 'getVoters') && $attachment->getOwner()->getId() != $this->getUser()->getId())) {
$final_attachments[] = $attachment;
}
}
$repost_entity = NULL;
$repost_type = $postArray[1];
switch($repost_type) {
default:
case 'wall':
$repost_entity = (new PostsRepo)->getPostById((int) $postArray[2], (int) $postArray[3]);
break;
case 'photo':
$repost_entity = (new PhotosRepo)->getByOwnerAndVID((int) $postArray[2], (int) $postArray[3]);
break;
case 'video':
$repost_entity = (new VideosRepo)->getByOwnerAndVID((int) $postArray[2], (int) $postArray[3]);
break;
}
if(!$repost_entity || $repost_entity->isDeleted() || !$repost_entity->canBeViewedBy($this->getUser())) $this->fail(100, "One of the parameters specified was missing or invalid");
$post = (new PostsRepo)->getPostById((int) $postArray[1], (int) $postArray[2]);
if(!$post || $post->isDeleted()) $this->fail(100, "One of the parameters specified was missing or invalid");
if(!$post->canBeViewedBy($this->getUser()))
$this->fail(15, "Access denied");
$nPost = new Post;
$nPost->setOwner($this->user->getId());
if($group_id > 0) {
$club = (new ClubsRepo)->get($group_id);
$club = (new ClubsRepo)->get($group_id);
if(!$club)
$this->fail(42, "Invalid group");
if(!$club->canBeModifiedBy($this->user))
$this->fail(16, "Access to group denied");
$nPost->setWall($club->getRealId());
$flags = 0;
if($as_group === 1 || $signed === 1)
$flags |= 0b10000000;
if($signed === 1)
$flags |= 0b01000000;
$nPost->setFlags($flags);
$nPost->setWall($group_id * -1);
} else {
$nPost->setWall($this->user->getId());
}
@ -662,27 +712,16 @@ final class Wall extends VKAPIRequestHandler
$nPost->setContent($message);
$nPost->setApi_Source_Name($this->getPlatform());
$nPost->save();
$nPost->attach($repost_entity);
foreach($parsed_attachments as $attachment) {
$nPost->attach($attachment);
}
if($repost_type == 'wall' && $repost_entity->getOwner(false)->getId() !== $this->user->getId() && !($repost_entity->getOwner() instanceof Club))
(new RepostNotification($repost_entity->getOwner(false), $repost_entity, $this->user))->emit();
$repost_count = 1;
if($repost_type == 'wall') {
$repost_count = $repost_entity->getRepostCount();
}
$nPost->attach($post);
if($post->getOwner(false)->getId() !== $this->user->getId() && !($post->getOwner() instanceof Club))
(new RepostNotification($post->getOwner(false), $post, $this->user))->emit();
return (object) [
"success" => 1, // 👍
"post_id" => $nPost->getVirtualId(),
"pretty_id" => $nPost->getPrettyId(),
"reposts_count" => $repost_count,
"likes_count" => $repost_entity->getLikesCount()
"reposts_count" => $post->getRepostCount(),
"likes_count" => $post->getLikesCount()
];
}
@ -728,7 +767,7 @@ final class Wall extends VKAPIRequestHandler
"date" => $comment->getPublicationTime()->timestamp(),
"text" => $comment->getText(false),
"post_id" => $post->getVirtualId(),
"owner_id" => method_exists($post, 'isPostedOnBehalfOfGroup') && $post->isPostedOnBehalfOfGroup() ? $post->getOwner()->getId() * -1 : $post->getOwner()->getId(),
"owner_id" => $post->isPostedOnBehalfOfGroup() ? $post->getOwner()->getId() * -1 : $post->getOwner()->getId(),
"parents_stack" => [],
"attachments" => $attachments,
"thread" => [
@ -794,13 +833,6 @@ final class Wall extends VKAPIRequestHandler
foreach($comment->getChildren() as $attachment) {
if($attachment instanceof \openvk\Web\Models\Entities\Photo) {
$attachments[] = $this->getApiPhoto($attachment);
} elseif($attachment instanceof \openvk\Web\Models\Entities\Video) {
$attachments[] = $attachment->getApiStructure();
} elseif($attachment instanceof \openvk\Web\Models\Entities\Note) {
$attachments[] = [
'type' => 'note',
'note' => $attachment->toVkApiStruct()
];
} elseif($attachment instanceof \openvk\Web\Models\Entities\Audio) {
$attachments[] = [
"type" => "audio",
@ -815,7 +847,7 @@ final class Wall extends VKAPIRequestHandler
"date" => $comment->getPublicationTime()->timestamp(),
"text" => $comment->getText(false),
"post_id" => $comment->getTarget()->getVirtualId(),
"owner_id" => method_exists($comment->getTarget(), 'isPostedOnBehalfOfGroup') && $comment->getTarget()->isPostedOnBehalfOfGroup() ? $comment->getTarget()->getOwner()->getId() * -1 : $comment->getTarget()->getOwner()->getId(),
"owner_id" => $comment->getTarget()->isPostedOnBehalfOfGroup() ? $comment->getTarget()->getOwner()->getId() * -1 : $comment->getTarget()->getOwner()->getId(),
"parents_stack" => [],
"attachments" => $attachments,
"likes" => [
@ -867,16 +899,7 @@ final class Wall extends VKAPIRequestHandler
if($post->getTargetWall() < 0)
$club = (new ClubsRepo)->get(abs($post->getTargetWall()));
$parsed_attachments = parseAttachments($attachments, ['photo', 'video', 'note', 'audio']);
$final_attachments = [];
foreach($parsed_attachments as $attachment) {
if($attachment && !$attachment->isDeleted() && $attachment->canBeViewedBy($this->getUser()) &&
!(method_exists($attachment, 'getVoters') && $attachment->getOwner()->getId() != $this->getUser()->getId())) {
$final_attachments[] = $attachment;
}
}
if((empty($message) && (empty($attachments) || sizeof($final_attachments) < 1))) {
if(empty($message) && empty($attachments)) {
$this->fail(100, "Required parameter 'message' missing.");
}
@ -897,8 +920,55 @@ final class Wall extends VKAPIRequestHandler
$this->fail(1, "ошибка про то что коммент большой слишком");
}
foreach($final_attachments as $attachment) {
$comment->attach($attachment);
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";
elseif(str_contains($attac, "audio"))
$attachmentType = "audio";
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()->getPrivacyPermission('photos.read', $this->getUser()))
$this->fail(11, "Access to photo denied");
$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()->getPrivacyPermission('videos.read', $this->getUser()))
$this->fail(11, "Access to video denied");
$comment->attach($attacc);
} elseif($attachmentType == "audio") {
$attacc = (new AudiosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
if(!$attacc || $attacc->isDeleted())
$this->fail(100, "Audio does not exist");
$comment->attach($attacc);
}
}
}
if($post->getOwner()->getId() !== $this->user->getId())
@ -949,24 +1019,11 @@ final class Wall extends VKAPIRequestHandler
}
}
function edit(int $owner_id, int $post_id, string $message = "", string $attachments = "", string $copyright = NULL, int $explicit = -1, int $from_group = 0, int $signed = 0) {
function edit(int $owner_id, int $post_id, string $message = "", string $attachments = "", string $copyright = NULL) {
$this->requireUser();
$this->willExecuteWriteAction();
$parsed_attachments = parseAttachments($attachments, ['photo', 'video', 'note', 'audio', 'poll']);
$final_attachments = [];
foreach($parsed_attachments as $attachment) {
if($attachment && !$attachment->isDeleted() && $attachment->canBeViewedBy($this->getUser()) &&
!(method_exists($attachment, 'getVoters') && $attachment->getOwner()->getId() != $this->getUser()->getId())) {
$final_attachments[] = $attachment;
}
}
if(empty($message) && sizeof($final_attachments) < 1) {
$this->fail(-66, "Post will be empty, don't saving.");
}
$post = (new PostsRepo)->getPostById($owner_id, $post_id, true);
$post = (new PostsRepo)->getPostById($owner_id, $post_id);
if(!$post || $post->isDeleted())
$this->fail(102, "Invalid post");
@ -974,43 +1031,36 @@ final class Wall extends VKAPIRequestHandler
if(!$post->canBeEditedBy($this->getUser()))
$this->fail(7, "Access to editing denied");
if(!empty($message) || (empty($message) && sizeof($final_attachments) > 0))
if(!empty($message))
$post->setContent($message);
$post->setEdited(time());
if(!is_null($copyright) && !empty($copyright)) {
if($copyright == 'remove') {
$post->resetSource();
} else {
try {
$post->setSource($copyright);
} catch(\Throwable) {}
}
try {
$post->setSource($copyright);
} catch(\Throwable) {}
}
if($explicit != -1) {
$post->setNsfw($explicit == 1);
}
$wallOwner = ($owner_id > 0 ? (new UsersRepo)->get($owner_id) : (new ClubsRepo)->get($owner_id * -1));
$flags = 0;
if($from_group == 1 && $wallOwner instanceof Club && $wallOwner->canBeModifiedBy($this->getUser()))
$flags |= 0b10000000;
/*if($signed == 1)
$flags |= 0b01000000;*/
$post->setFlags($flags);
$post->save(true);
if($attachments == 'remove' || sizeof($final_attachments) > 0) {
foreach($post->getChildren() as $att) {
if(!($att instanceof Post)) {
$post->detach($att);
}
}
# todo добавить такое в веб версию
if(!empty($attachments)) {
$attachs = parseAttachments($attachments);
$newAttachmentsCount = sizeof($attachs);
foreach($final_attachments as $attachment) {
$post->attach($attachment);
$postsAttachments = iterator_to_array($post->getChildren());
if(sizeof($postsAttachments) >= 10)
$this->fail(15, "Post have too many attachments");
if(($newAttachmentsCount + sizeof($postsAttachments)) > 10)
$this->fail(158, "Post will have too many attachments");
foreach($attachs as $attach) {
if($attach && !$attach->isDeleted())
$post->attach($attach);
else
$this->fail(52, "One of the attachments is invalid");
}
}
@ -1022,16 +1072,8 @@ final class Wall extends VKAPIRequestHandler
$this->willExecuteWriteAction();
$comment = (new CommentsRepo)->get($comment_id);
$parsed_attachments = parseAttachments($attachments, ['photo', 'video', 'note', 'audio']);
$final_attachments = [];
foreach($parsed_attachments as $attachment) {
if($attachment && !$attachment->isDeleted() && $attachment->canBeViewedBy($this->getUser()) &&
!(method_exists($attachment, 'getVoters') && $attachment->getOwner()->getId() != $this->getUser()->getId())) {
$final_attachments[] = $attachment;
}
}
if(empty($message) && sizeof($final_attachments) < 1)
if(empty($message) && empty($attachments))
$this->fail(100, "Required parameter 'message' missing.");
if(!$comment || $comment->isDeleted())
@ -1040,16 +1082,29 @@ final class Wall extends VKAPIRequestHandler
if(!$comment->canBeEditedBy($this->getUser()))
$this->fail(15, "Access to editing comment denied");
if(!empty($message) || (empty($message) && sizeof($final_attachments) > 0))
if(!empty($message))
$comment->setContent($message);
$comment->setEdited(time());
$comment->save(true);
if(!empty($attachments)) {
$attachs = parseAttachments($attachments);
$newAttachmentsCount = sizeof($attachs);
if(sizeof($final_attachments) > 0) {
$comment->unwire();
foreach($final_attachments as $attachment) {
$comment->attach($attachment);
$postsAttachments = iterator_to_array($comment->getChildren());
if(sizeof($postsAttachments) >= 10)
$this->fail(15, "Post have too many attachments");
if(($newAttachmentsCount + sizeof($postsAttachments)) > 10)
$this->fail(158, "Post will have too many attachments");
foreach($attachs as $attach) {
if($attach && !$attach->isDeleted())
$comment->attach($attach);
else
$this->fail(52, "One of the attachments is invalid");
}
}

View file

@ -87,7 +87,6 @@ class Album extends MediaCollection
$res = (object) [];
$res->id = $this->getPrettyId();
$res->vid = $this->getId();
$res->thumb_id = !is_null($this->getCoverPhoto()) ? $this->getCoverPhoto()->getPrettyId() : 0;
$res->owner_id = $this->getOwner()->getId();
$res->title = $this->getName();

View file

@ -42,11 +42,10 @@ class Club extends RowModel
return iterator_to_array($avPhotos)[0] ?? NULL;
}
function getAvatarUrl(string $size = "miniscule", $avPhoto = NULL): string
function getAvatarUrl(string $size = "miniscule"): string
{
$serverUrl = ovk_scheme(true) . $_SERVER["HTTP_HOST"];
if(!$avPhoto)
$avPhoto = $this->getAvatarPhoto();
$avPhoto = $this->getAvatarPhoto();
return is_null($avPhoto) ? "$serverUrl/assets/packages/static/openvk/img/camera_200.png" : $avPhoto->getURLBySizeId($size);
}
@ -444,57 +443,30 @@ class Club extends RowModel
$res->id = $this->getId();
$res->name = $this->getName();
$res->screen_name = $this->getShortCode() ?? "club".$this->getId();
$res->is_closed = false;
$res->type = 'group';
$res->is_member = $user ? (int)$this->getSubscriptionStatus($user) : 0;
$res->screen_name = $this->getShortCode();
$res->is_closed = 0;
$res->deactivated = NULL;
$res->can_access_closed = true;
$res->is_admin = $user && $this->canBeModifiedBy($user);
if(!is_array($fields))
$fields = explode(',', $fields);
$avatar_photo = $this->getAvatarPhoto();
foreach($fields as $field) {
switch($field) {
case 'verified':
$res->verified = (int)$this->isVerified();
break;
case 'site':
$res->site = $this->getWebsite();
break;
case 'description':
$res->description = $this->getDescription();
break;
case 'background':
$res->background = $this->getBackDropPictureURLs();
break;
case 'photo_50':
$res->photo_50 = $this->getAvatarUrl('miniscule', $avatar_photo);
break;
case 'photo_100':
$res->photo_100 = $this->getAvatarUrl('tiny', $avatar_photo);
break;
case 'photo_200':
$res->photo_200 = $this->getAvatarUrl('normal', $avatar_photo);
break;
case 'photo_max':
$res->photo_max = $this->getAvatarUrl('original', $avatar_photo);
break;
case 'members_count':
$res->members_count = $this->getFollowersCount();
break;
case 'real_id':
$res->real_id = $this->getRealId();
break;
}
if($user && $this->canBeModifiedBy($user)) {
$res->admin_level = 3;
}
$res->is_member = $user && $this->getSubscriptionStatus($user) ? 1 : 0;
$res->type = "group";
$res->photo_50 = $this->getAvatarUrl("miniscule");
$res->photo_100 = $this->getAvatarUrl("tiny");
$res->photo_200 = $this->getAvatarUrl("normal");
$res->can_create_topic = $user && $this->canBeModifiedBy($user) ? 1 : ($this->isEveryoneCanCreateTopics() ? 1 : 0);
$res->can_post = $user && $this->canBeModifiedBy($user) ? 1 : ($this->canPost() ? 1 : 0);
return $res;
}
use Traits\TBackDrops;
use Traits\TSubscribable;
use Traits\TAudioStatuses;
use Traits\TIgnorable;
}

View file

@ -46,11 +46,8 @@ class Comment extends Post
return parent::getOwner($honourFlags, $real);
}
function canBeDeletedBy(User $user = NULL): bool
function canBeDeletedBy(User $user): bool
{
if(!$user)
return false;
return $this->getOwner()->getId() == $user->getId() ||
$this->getTarget()->getOwner()->getId() == $user->getId() ||
$this->getTarget() instanceof Post && $this->getTarget()->getTargetWall() < 0 && (new Clubs)->get(abs($this->getTarget()->getTargetWall()))->canBeModifiedBy($user) ||

View file

@ -308,7 +308,7 @@ class Photo extends Media
$res->date = $res->created = $this->getPublicationTime()->timestamp();
if($photo_sizes) {
$res->sizes = array_values($this->getVkApiSizes());
$res->sizes = $this->getVkApiSizes();
$res->src_small = $res->photo_75 = $this->getURLBySizeId("miniscule");
$res->src = $res->photo_130 = $this->getURLBySizeId("tiny");
$res->src_big = $res->photo_604 = $this->getURLBySizeId("normal");

View file

@ -103,11 +103,6 @@ class Post extends Postable
$this->stateChanges("source", $source);
}
function resetSource()
{
$this->stateChanges("source", NULL);
}
function getVkApiCopyright(): object
{
return (object)[
@ -265,22 +260,16 @@ class Post extends Postable
$this->save();
}
function canBePinnedBy(User $user = NULL): bool
function canBePinnedBy(User $user): bool
{
if(!$user)
return false;
if($this->getTargetWall() < 0)
return (new Clubs)->get(abs($this->getTargetWall()))->canBeModifiedBy($user);
return $this->getTargetWall() === $user->getId();
}
function canBeDeletedBy(User $user = NULL): bool
function canBeDeletedBy(User $user): bool
{
if(!$user)
return false;
if($this->getTargetWall() < 0 && !$this->getWallOwner()->canBeModifiedBy($user) && $this->getWallOwner()->getWallType() != 1 && $this->getSuggestionType() == 0)
return false;

View file

@ -134,13 +134,8 @@ class Report extends RowModel
function getContentName(): string
{
$content_object = $this->getContentObject();
if(!$content_object) {
return 'unknown';
}
if (method_exists($content_object, "getCanonicalName"))
return $content_object->getCanonicalName();
if (method_exists($this->getContentObject(), "getCanonicalName"))
return $this->getContentObject()->getCanonicalName();
return $this->getContentType() . " #" . $this->getContentId();
}

View file

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace openvk\Web\Models\Entities\Traits;
use openvk\Web\Models\Entities\{Attachable, Photo, Video};
use openvk\Web\Models\Entities\{Attachable, Photo};
use openvk\Web\Util\Makima\Makima;
use Chandler\Database\DatabaseConnection;
@ -36,10 +36,10 @@ trait TAttachmentHost
if($h < 0)
$h = $w;
$children = iterator_to_array($this->getChildren());
$children = $this->getChildren();
$skipped = $photos = $result = [];
foreach($children as $child) {
if($child instanceof Photo || $child instanceof Video && $child->getDimensions()) {
if($child instanceof Photo) {
$photos[] = $child;
continue;
}

View file

@ -1,55 +0,0 @@
<?php declare(strict_types=1);
namespace openvk\Web\Models\Entities\Traits;
use Chandler\Database\DatabaseConnection;
use openvk\Web\Models\Entities\User;
trait TIgnorable
{
function isIgnoredBy(User $user = NULL): bool
{
if(!$user)
return false;
$ctx = DatabaseConnection::i()->getContext();
$data = [
"owner" => $user->getId(),
"source" => $this->getRealId(),
];
$sub = $ctx->table("ignored_sources")->where($data);
return $sub->count() > 0;
}
function addIgnore(User $for_user): bool
{
DatabaseConnection::i()->getContext()->table("ignored_sources")->insert([
"owner" => $for_user->getId(),
"source" => $this->getRealId(),
]);
return true;
}
function removeIgnore(User $for_user): bool
{
DatabaseConnection::i()->getContext()->table("ignored_sources")->where([
"owner" => $for_user->getId(),
"source" => $this->getRealId(),
])->delete();
return true;
}
function toggleIgnore(User $for_user): bool
{
if($this->isIgnoredBy($for_user)) {
$this->removeIgnore($for_user);
return false;
} else {
$this->addIgnore($for_user);
return true;
}
}
}

View file

@ -112,7 +112,7 @@ class User extends RowModel
return "/id" . $this->getId();
}
function getAvatarUrl(string $size = "miniscule", $avPhoto = NULL): string
function getAvatarUrl(string $size = "miniscule"): string
{
$serverUrl = ovk_scheme(true) . $_SERVER["HTTP_HOST"];
@ -121,9 +121,7 @@ class User extends RowModel
else if($this->isBanned())
return "$serverUrl/assets/packages/static/openvk/img/banned.jpg";
if(!$avPhoto)
$avPhoto = $this->getAvatarPhoto();
$avPhoto = $this->getAvatarPhoto();
if(is_null($avPhoto))
return "$serverUrl/assets/packages/static/openvk/img/camera_200.png";
else
@ -1346,6 +1344,11 @@ class User extends RowModel
$res->first_name = $this->getFirstName();
$res->last_name = $this->getLastName();
$res->deactivated = $this->isDeactivated();
$res->photo_50 = $this->getAvatarURL();
$res->photo_100 = $this->getAvatarURL("tiny");
$res->photo_200 = $this->getAvatarURL("normal");
$res->photo_id = !is_null($this->getAvatarPhoto()) ? $this->getAvatarPhoto()->getPrettyId() : NULL;
$res->is_closed = $this->isClosed();
if(!is_null($user))
@ -1354,60 +1357,17 @@ class User extends RowModel
if(!is_array($fields))
$fields = explode(',', $fields);
$avatar_photo = $this->getAvatarPhoto();
foreach($fields as $field) {
switch($field) {
case 'is_dead':
$res->is_dead = $this->isDead();
break;
case 'verified':
$res->verified = (int)$this->isVerified();
break;
case 'sex':
$res->sex = $this->isFemale() ? 1 : ($this->isNeutral() ? 0 : 2);
break;
case 'photo_50':
$res->photo_50 = $this->getAvatarUrl('miniscule', $avatar_photo);
break;
case 'photo_100':
$res->photo_100 = $this->getAvatarUrl('tiny', $avatar_photo);
break;
case 'photo_200':
$res->photo_200 = $this->getAvatarUrl('normal', $avatar_photo);
break;
case 'photo_max':
$res->photo_max = $this->getAvatarUrl('original', $avatar_photo);
break;
case 'photo_id':
$res->photo_id = $avatar_photo ? $avatar_photo->getPrettyId() : NULL;
break;
case 'background':
$res->background = $this->getBackDropPictureURLs();
break;
case 'reg_date':
$res->reg_date = $this->getRegistrationTime()->timestamp();
break;
case 'nickname':
$res->nickname = $this->getPseudo();
break;
case 'rating':
$res->rating = $this->getRating();
break;
case 'status':
$res->status = $this->getStatus();
break;
case 'screen_name':
$res->screen_name = $this->getShortCode() ?? "id".$this->getId();
break;
case 'real_id':
$res->real_id = $this->getRealId();
$res->is_dead = $user->isDead();
break;
}
}
return $res;
}
function getAudiosCollectionSize()
{
return (new \openvk\Web\Models\Repositories\Audios)->getUserCollectionSize($this);
@ -1447,40 +1407,7 @@ class User extends RowModel
return $returnArr;
}
function getIgnoredSources(int $offset = 0, int $limit = 10, bool $onlyIds = false)
{
$sources = DatabaseConnection::i()->getContext()->table("ignored_sources")->where("owner", $this->getId())->limit($limit, $offset)->order('id DESC');
$output_array = [];
foreach($sources as $source) {
if($onlyIds) {
$output_array[] = (int)$source->source;
} else {
$ignored_source_model = NULL;
$ignored_source_id = (int)$source->source;
if($ignored_source_id > 0)
$ignored_source_model = (new Users)->get($ignored_source_id);
else
$ignored_source_model = (new Clubs)->get(abs($ignored_source_id));
if(!$ignored_source_model)
continue;
$output_array[] = $ignored_source_model;
}
}
return $output_array;
}
function getIgnoredSourcesCount()
{
return DatabaseConnection::i()->getContext()->table("ignored_sources")->where("owner", $this->getId())->count();
}
use Traits\TBackDrops;
use Traits\TSubscribable;
use Traits\TAudioStatuses;
use Traits\TIgnorable;
}

View file

@ -34,23 +34,9 @@ class Video extends Media
if(sizeof($durations[1]) === 0)
throw new \DomainException("$filename does not contain any meaningful video streams");
$length = 0;
foreach($durations[1] as $duration) {
$duration = floatval($duration);
if($duration < 1.0)
foreach($durations[1] as $duration)
if(floatval($duration) < 1.0)
throw new \DomainException("$filename does not contain any meaningful video streams");
else
$length = max($length, $duration);
}
$this->stateChanges("length", (int) round($length, 0, PHP_ROUND_HALF_EVEN));
preg_match('%width=([0-9\.]++)%', $streams, $width);
preg_match('%height=([0-9\.]++)%', $streams, $height);
if(!empty($width) && !empty($height)) {
$this->stateChanges("width", $width[1]);
$this->stateChanges("height", $height[1]);
}
try {
if(!is_dir($dirId = dirname($this->pathFromHash($hash))))
@ -132,7 +118,6 @@ class Video extends Media
function getApiStructure(?User $user = NULL): object
{
$fromYoutube = $this->getType() == Video::TYPE_EMBED;
$dimensions = $this->getDimensions();
$res = (object)[
"type" => "video",
"video" => [
@ -145,7 +130,7 @@ class Video extends Media
"comments" => $this->getCommentsCount(),
"date" => $this->getPublicationTime()->timestamp(),
"description" => $this->getDescription(),
"duration" => $this->getLength(),
"duration" => 0, // я хуй знает как получить длину видео
"image" => [
[
"url" => $this->getThumbnailURL(),
@ -154,8 +139,8 @@ class Video extends Media
"with_padding" => 1
]
],
"width" => $dimensions ? $dimensions[0] : 640,
"height" => $dimensions ? $dimensions[1] : 480,
"width" => 640,
"height" => 480,
"id" => $this->getVirtualId(),
"owner_id" => $this->getOwner()->getId(),
"user_id" => $this->getOwner()->getId(),
@ -170,7 +155,6 @@ class Video extends Media
"repeat" => 0,
"type" => "video",
"views" => 0,
"is_processed" => $this->isProcessed(),
"reposts" => [
"count" => 0,
"user_reposted" => 0
@ -240,74 +224,6 @@ class Video extends Media
return $video;
}
function fillDimensions()
{
$hash = $this->getRecord()->hash;
$path = $this->pathFromHash($hash);
if(!file_exists($path)) {
$this->stateChanges("width", 0);
$this->stateChanges("height", 0);
$this->stateChanges("length", 0);
$this->save();
return false;
}
$streams = Shell::ffprobe("-i", $path, "-show_streams", "-select_streams v", "-loglevel error")->execute($error);
$durations = [];
preg_match_all('%duration=([0-9\.]++)%', $streams, $durations);
$length = 0;
foreach($durations[1] as $duration) {
$duration = floatval($duration);
if($duration < 1.0)
continue;
else
$length = max($length, $duration);
}
$this->stateChanges("length", (int) round($length, 0, PHP_ROUND_HALF_EVEN));
preg_match('%width=([0-9\.]++)%', $streams, $width);
preg_match('%height=([0-9\.]++)%', $streams, $height);
if(!empty($width) && !empty($height)) {
$this->stateChanges("width", $width[1]);
$this->stateChanges("height", $height[1]);
}
$this->save();
return true;
}
function getDimensions()
{
if($this->getType() == Video::TYPE_EMBED) return [320, 180];
$width = $this->getRecord()->width;
$height = $this->getRecord()->height;
if(!$width) return NULL;
return $width != 0 ? [$width, $height] : NULL;
}
function getLength()
{
return $this->getRecord()->length;
}
function getFormattedLength(): string
{
$len = $this->getLength();
if(!$len) return "00:00";
$mins = floor($len / 60);
$secs = $len - ($mins * 60);
return (
str_pad((string) $mins, 2, "0", STR_PAD_LEFT)
. ":" .
str_pad((string) $secs, 2, "0", STR_PAD_LEFT)
);
}
function canBeViewedBy(?User $user = NULL): bool
{
@ -332,7 +248,7 @@ class Video extends Media
$res->owner_id = $this->getOwner()->getId();
$res->title = $this->getName();
$res->description = $this->getDescription();
$res->duration = $this->getLength();
$res->duration = "22";
$res->link = "/video".$this->getOwner()->getId()."_".$this->getVirtualId();
$res->image = $this->getThumbnailURL();
$res->date = $this->getPublicationTime()->timestamp();

View file

@ -43,18 +43,6 @@ class Clubs
return $this->toClub($this->clubs->get($id));
}
function getByIds(array $ids = []): array
{
$clubs = $this->clubs->select('*')->where('id IN (?)', $ids);
$clubs_array = [];
foreach($clubs as $club) {
$clubs_array[] = $this->toClub($club);
}
return $clubs_array;
}
function find(string $query, array $params = [], array $order = ['type' => 'id', 'invert' => false], int $page = 1, ?int $perPage = NULL): \Traversable
{
$query = "%$query%";

View file

@ -33,7 +33,7 @@ class Photos
return new Photo($photo);
}
function getEveryUserPhoto(User $user, int $offset = 0, int $limit = 10): \Traversable
function getEveryUserPhoto(User $user, int $page = 1, ?int $perPage = NULL): \Traversable
{
$perPage = $perPage ?? OPENVK_DEFAULT_PER_PAGE;
$photos = $this->photos->where([
@ -41,7 +41,7 @@ class Photos
"deleted" => 0
])->order("id DESC");
foreach($photos->limit($limit, $offset) as $photo) {
foreach($photos->page($page, $perPage) as $photo) {
yield new Photo($photo);
}
}

View file

@ -53,9 +53,9 @@ class Posts
$offset--;
}
}
} /*else if(!is_null($offset)) {
} else if(!is_null($offset)) {
$offset--;
}*/
}
$sel = $this->posts->where([
"wall" => $user,

View file

@ -28,18 +28,6 @@ class Users
{
return $this->toUser($this->users->get($id));
}
function getByIds(array $ids = []): array
{
$users = $this->users->select('*')->where('id IN (?)', $ids);
$users_array = [];
foreach($users as $user) {
$users_array[] = $this->toUser($user);
}
return $users_array;
}
function getByShortURL(string $url): ?User
{

View file

@ -39,13 +39,6 @@ class Videos
$perPage = $perPage ?? OPENVK_DEFAULT_PER_PAGE;
foreach($this->videos->where("owner", $user->getId())->where(["deleted" => 0, "unlisted" => 0])->page($page, $perPage)->order("created DESC") as $video)
yield new Video($video);
}
function getByUserLimit(User $user, int $offset = 0, int $limit = 10): \Traversable
{
$perPage = $perPage ?? OPENVK_DEFAULT_PER_PAGE;
foreach($this->videos->where("owner", $user->getId())->where(["deleted" => 0, "unlisted" => 0])->limit($limit, $offset)->order("created DESC") as $video)
yield new Video($video);
}
function getUserVideosCount(User $user): int
@ -56,7 +49,7 @@ class Videos
function find(string $query = "", array $params = [], array $order = ['type' => 'id', 'invert' => false]): Util\EntityStream
{
$query = "%$query%";
$result = $this->videos->where("CONCAT_WS(' ', name, description) LIKE ?", $query)->where("deleted", 0)->where("unlisted", 0);
$result = $this->videos->where("CONCAT_WS(' ', name, description) LIKE ?", $query)->where("deleted", 0);
$order_str = 'id';
switch($order['type']) {

View file

@ -33,7 +33,6 @@ final class AudioPresenter extends OpenVKPresenter
function renderList(?int $owner = NULL, ?string $mode = "list"): void
{
$this->assertUserLoggedIn();
$this->template->_template = "Audio/List.xml";
$page = (int)($this->queryParam("p") ?? 1);
$audios = [];
@ -502,7 +501,6 @@ final class AudioPresenter extends OpenVKPresenter
function renderPlaylist(int $owner_id, int $virtual_id): void
{
$this->assertUserLoggedIn();
$playlist = $this->audios->getPlaylistByOwnerAndVID($owner_id, $virtual_id);
$page = (int)($this->queryParam("p") ?? 1);
if (!$playlist || $playlist->isDeleted())

View file

@ -27,12 +27,7 @@ final class CommentPresenter extends OpenVKPresenter
$this->flashFail("err", tr("error"), tr("forbidden"));
if(!is_null($this->user)) $comment->toggleLike($this->user->identity);
if($_SERVER["REQUEST_METHOD"] === "POST") {
$this->returnJson([
'success' => true,
]);
}
$this->redirect($_SERVER["HTTP_REFERER"]);
}
@ -75,24 +70,64 @@ final class CommentPresenter extends OpenVKPresenter
$this->flashFail("err", tr("error_when_publishing_comment"), tr("error_when_publishing_comment_description"));
}
}
$photos = [];
if(!empty($this->postParam("photos"))) {
$un = rtrim($this->postParam("photos"), ",");
$arr = explode(",", $un);
$horizontal_attachments = [];
$vertical_attachments = [];
if(!empty($this->postParam("horizontal_attachments"))) {
$horizontal_attachments_array = array_slice(explode(",", $this->postParam("horizontal_attachments")), 0, OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["postSizes"]["maxAttachments"]);
if(sizeof($horizontal_attachments_array) > 0) {
$horizontal_attachments = parseAttachments($horizontal_attachments_array, ['photo', 'video']);
if(sizeof($arr) < 11) {
foreach($arr as $dat) {
$ids = explode("_", $dat);
$photo = (new Photos)->getByOwnerAndVID((int)$ids[0], (int)$ids[1]);
if(!$photo || $photo->isDeleted())
continue;
$photos[] = $photo;
}
}
}
if(!empty($this->postParam("vertical_attachments"))) {
$vertical_attachments_array = array_slice(explode(",", $this->postParam("vertical_attachments")), 0, OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["postSizes"]["maxAttachments"]);
if(sizeof($vertical_attachments_array) > 0) {
$vertical_attachments = parseAttachments($vertical_attachments_array, ['audio', 'note']);
$videos = [];
if(!empty($this->postParam("videos"))) {
$un = rtrim($this->postParam("videos"), ",");
$arr = explode(",", $un);
if(sizeof($arr) < 11) {
foreach($arr as $dat) {
$ids = explode("_", $dat);
$video = (new Videos)->getByOwnerAndVID((int)$ids[0], (int)$ids[1]);
if(!$video || $video->isDeleted())
continue;
$videos[] = $video;
}
}
}
$audios = [];
if(!empty($this->postParam("audios"))) {
$un = rtrim($this->postParam("audios"), ",");
$arr = explode(",", $un);
if(sizeof($arr) < 11) {
foreach($arr as $dat) {
$ids = explode("_", $dat);
$audio = (new Audios)->getByOwnerAndVID((int)$ids[0], (int)$ids[1]);
if(!$audio || $audio->isDeleted())
continue;
$audios[] = $audio;
}
}
}
if(empty($this->postParam("text")) && sizeof($horizontal_attachments) < 1 && sizeof($vertical_attachments) < 1)
if(empty($this->postParam("text")) && sizeof($photos) < 1 && sizeof($videos) < 1 && sizeof($audios) < 1)
$this->flashFail("err", tr("error_when_publishing_comment"), tr("error_comment_empty"));
try {
@ -108,21 +143,15 @@ final class CommentPresenter extends OpenVKPresenter
$this->flashFail("err", tr("error_when_publishing_comment"), tr("error_comment_too_big"));
}
foreach($horizontal_attachments as $horizontal_attachment) {
if(!$horizontal_attachment || $horizontal_attachment->isDeleted() || !$horizontal_attachment->canBeViewedBy($this->user->identity)) {
continue;
}
foreach($photos as $photo)
$comment->attach($photo);
if(sizeof($videos) > 0)
foreach($videos as $vid)
$comment->attach($vid);
$comment->attach($horizontal_attachment);
}
foreach($vertical_attachments as $vertical_attachment) {
if(!$vertical_attachment || $vertical_attachment->isDeleted() || !$vertical_attachment->canBeViewedBy($this->user->identity)) {
continue;
}
$comment->attach($vertical_attachment);
}
foreach($audios as $audio)
$comment->attach($audio);
if($entity->getOwner()->getId() !== $this->user->identity->getId())
if(($owner = $entity->getOwner()) instanceof User)

View file

@ -43,7 +43,6 @@ final class GroupPresenter extends OpenVKPresenter
}
$this->template->club = $club;
$this->template->ignore_status = $club->isIgnoredBy($this->user->identity);
}
}

View file

@ -121,9 +121,9 @@ final class InternalAPIPresenter extends OpenVKPresenter
{
if($attachment instanceof \openvk\Web\Models\Entities\Photo)
{
$response[$attachment->getPrettyId()] = [
"url" => $attachment->getURLBySizeId('larger'),
"id" => $attachment->getPrettyId(),
$response[] = [
"url" => $attachment->getURLBySizeId('normal'),
"id" => $attachment->getPrettyId()
];
}
}
@ -133,35 +133,4 @@ final class InternalAPIPresenter extends OpenVKPresenter
]);
}
}
function renderGetPostTemplate(int $owner_id, int $post_id) {
if($_SERVER["REQUEST_METHOD"] !== "POST") {
header("HTTP/1.1 405 Method Not Allowed");
exit("ты‍ не по адресу");
}
$type = $this->queryParam("type", false);
if($type == "post") {
$post = (new Posts)->getPostById($owner_id, $post_id, true);
} else {
$post = (new Comments)->get($post_id);
}
if(!$post || !$post->canBeEditedBy($this->user->identity)) {
exit('');
}
header("Content-Type: text/plain");
if($type == 'post') {
$this->template->_template = 'components/post.xml';
$this->template->post = $post;
$this->template->commentSection = false;
} elseif($type == 'comment') {
$this->template->_template = 'components/comment.xml';
$this->template->comment = $post;
} else {
exit('');
}
}
}

View file

@ -283,11 +283,6 @@ abstract class OpenVKPresenter extends SimplePresenter
}
}
/*if($this->queryParam('al') == '1') {
$this->assertNoCSRF();
header('Content-Type: text/plain; charset=UTF-8');
}*/
parent::onStartup();
}

View file

@ -176,7 +176,6 @@ final class PhotosPresenter extends OpenVKPresenter
$this->template->cCount = $photo->getCommentsCount();
$this->template->cPage = (int) ($this->queryParam("p") ?? 1);
$this->template->comments = iterator_to_array($photo->getComments($this->template->cPage));
$this->template->owner = $photo->getOwner();
}
function renderAbsolutePhoto($id): void
@ -288,8 +287,7 @@ final class PhotosPresenter extends OpenVKPresenter
"id" => $photo->getId(),
"vid" => $photo->getVirtualId(),
"owner" => $photo->getOwner()->getId(),
"link" => $photo->getURL(),
"pretty_id" => $photo->getPrettyId(),
"link" => $photo->getURL()
];
} catch(ISE $ex) {
$name = $album->getName();
@ -356,26 +354,4 @@ final class PhotosPresenter extends OpenVKPresenter
$this->flash("succ", tr("photo_is_deleted"), tr("photo_is_deleted_desc"));
$this->redirect($redirect);
}
function renderLike(int $wall, int $post_id): void
{
$this->assertUserLoggedIn();
$this->willExecuteWriteAction();
$this->assertNoCSRF();
$photo = $this->photos->getByOwnerAndVID($wall, $post_id);
if(!$photo || $photo->isDeleted() || !$photo->canBeViewedBy($this->user->identity)) $this->notFound();
if(!is_null($this->user)) {
$photo->toggleLike($this->user->identity);
}
if($_SERVER["REQUEST_METHOD"] === "POST") {
$this->returnJson([
'success' => true,
]);
}
$this->redirect("$_SERVER[HTTP_REFERER]");
}
}

View file

@ -54,10 +54,6 @@ final class UserPresenter extends OpenVKPresenter
$this->template->audioStatus = $user->getCurrentAudioStatus();
$this->template->user = $user;
if($id !== $this->user->id) {
$this->template->ignore_status = $user->isIgnoredBy($this->user->identity);
}
}
}

View file

@ -62,7 +62,6 @@ final class VideosPresenter extends OpenVKPresenter
$this->flashFail("err", tr("error"), tr("video_uploads_disabled"));
if($_SERVER["REQUEST_METHOD"] === "POST") {
$is_ajax = (int)($this->postParam('ajax') ?? '0') == 1;
if(!empty($this->postParam("name"))) {
$video = new Video;
$video->setOwner($this->user->id);
@ -76,29 +75,18 @@ final class VideosPresenter extends OpenVKPresenter
else if(!empty($this->postParam("link")))
$video->setLink($this->postParam("link"));
else
$this->flashFail("err", tr("no_video_error"), tr("no_video_description"), 10, $is_ajax);
$this->flashFail("err", tr("no_video_error"), tr("no_video_description"));
} catch(\DomainException $ex) {
$this->flashFail("err", tr("error_video"), tr("file_corrupted"), 10, $is_ajax);
$this->flashFail("err", tr("error_video"), tr("file_corrupted"));
} catch(ISE $ex) {
$this->flashFail("err", tr("error_video"), tr("link_incorrect"), 10, $is_ajax);
$this->flashFail("err", tr("error_video"), tr("link_incorrect"));
}
if((int)($this->postParam("unlisted") ?? '0') == 1) {
$video->setUnlisted(true);
}
$video->save();
if($is_ajax) {
$object = $video->getApiStructure();
$this->returnJson([
'payload' => $object->video,
]);
}
$this->redirect("/video" . $video->getPrettyId());
} else {
$this->flashFail("err", tr("error_video"), tr("no_name_error"), 10, $is_ajax);
$this->flashFail("err", tr("error_video"), tr("no_name_error"));
}
}
}
@ -163,13 +151,7 @@ final class VideosPresenter extends OpenVKPresenter
if(!is_null($this->user)) {
$video->toggleLike($this->user->identity);
}
if($_SERVER["REQUEST_METHOD"] === "POST") {
$this->returnJson([
'success' => true,
]);
}
$this->redirect("$_SERVER[HTTP_REFERER]");
$this->returnJson(["success" => true]);
}
}

View file

@ -197,16 +197,6 @@ final class WallPresenter extends OpenVKPresenter
if($this->user->identity->getNsfwTolerance() === User::NSFW_INTOLERANT)
$queryBase .= " AND `nsfw` = 0";
if(((int)$this->queryParam('return_banned')) == 0) {
$ignored_sources_ids = $this->user->identity->getIgnoredSources(0, OPENVK_ROOT_CONF['openvk']['preferences']['newsfeed']['ignoredSourcesLimit'] ?? 50, true);
if(sizeof($ignored_sources_ids) > 0) {
$imploded_ids = implode("', '", $ignored_sources_ids);
$queryBase .= " AND `posts`.`wall` NOT IN ('$imploded_ids')";
}
}
$posts = DatabaseConnection::i()->getConnection()->query("SELECT `posts`.`id` " . $queryBase . " ORDER BY `created` DESC LIMIT " . $pPage . " OFFSET " . ($page - 1) * $pPage);
$count = DatabaseConnection::i()->getConnection()->query("SELECT COUNT(*) " . $queryBase)->fetch()->{"COUNT(*)"};
@ -282,22 +272,25 @@ final class WallPresenter extends OpenVKPresenter
if($this->postParam("force_sign") === "on")
$flags |= 0b01000000;
$horizontal_attachments = [];
$vertical_attachments = [];
if(!empty($this->postParam("horizontal_attachments"))) {
$horizontal_attachments_array = array_slice(explode(",", $this->postParam("horizontal_attachments")), 0, OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["postSizes"]["maxAttachments"]);
if(sizeof($horizontal_attachments_array) > 0) {
$horizontal_attachments = parseAttachments($horizontal_attachments_array, ['photo', 'video']);
$photos = [];
if(!empty($this->postParam("photos"))) {
$un = rtrim($this->postParam("photos"), ",");
$arr = explode(",", $un);
if(sizeof($arr) < 11) {
foreach($arr as $dat) {
$ids = explode("_", $dat);
$photo = (new Photos)->getByOwnerAndVID((int)$ids[0], (int)$ids[1]);
if(!$photo || $photo->isDeleted())
continue;
$photos[] = $photo;
}
}
}
if(!empty($this->postParam("vertical_attachments"))) {
$vertical_attachments_array = array_slice(explode(",", $this->postParam("vertical_attachments")), 0, OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["postSizes"]["maxAttachments"]);
if(sizeof($vertical_attachments_array) > 0) {
$vertical_attachments = parseAttachments($vertical_attachments_array, ['audio', 'note']);
}
}
try {
$poll = NULL;
$xml = $this->postParam("poll");
@ -309,10 +302,61 @@ final class WallPresenter extends OpenVKPresenter
$this->flashFail("err", tr("failed_to_publish_post"), "Poll format invalid");
}
if(empty($this->postParam("text")) && sizeof($horizontal_attachments) < 1 && sizeof($vertical_attachments) < 1 && !$poll)
$note = NULL;
if(!is_null($this->postParam("note")) && $this->postParam("note") != "none") {
$note = (new Notes)->get((int)$this->postParam("note"));
if(!$note || $note->isDeleted() || $note->getOwner()->getId() != $this->user->id) {
$this->flashFail("err", tr("error"), tr("error_attaching_note"));
}
if($note->getOwner()->getPrivacySetting("notes.read") < 1) {
$this->flashFail("err", " ");
}
}
$videos = [];
if(!empty($this->postParam("videos"))) {
$un = rtrim($this->postParam("videos"), ",");
$arr = explode(",", $un);
if(sizeof($arr) < 11) {
foreach($arr as $dat) {
$ids = explode("_", $dat);
$video = (new Videos)->getByOwnerAndVID((int)$ids[0], (int)$ids[1]);
if(!$video || $video->isDeleted())
continue;
$videos[] = $video;
}
}
}
$audios = [];
if(!empty($this->postParam("audios"))) {
$un = rtrim($this->postParam("audios"), ",");
$arr = explode(",", $un);
if(sizeof($arr) < 11) {
foreach($arr as $dat) {
$ids = explode("_", $dat);
$audio = (new Audios)->getByOwnerAndVID((int)$ids[0], (int)$ids[1]);
if(!$audio || $audio->isDeleted())
continue;
$audios[] = $audio;
}
}
}
if(empty($this->postParam("text")) && sizeof($photos) < 1 && sizeof($videos) < 1 && sizeof($audios) < 1 && !$poll && !$note)
$this->flashFail("err", tr("failed_to_publish_post"), tr("post_is_empty_or_too_big"));
$should_be_suggested = $wall < 0 && !$wallOwner->canBeModifiedBy($this->user->identity) && $wallOwner->getWallType() == 2;
try {
$post = new Post;
$post->setOwner($this->user->id);
@ -329,7 +373,7 @@ final class WallPresenter extends OpenVKPresenter
} catch(\Throwable) {}
}
if($should_be_suggested)
if($wall < 0 && !$wallOwner->canBeModifiedBy($this->user->identity) && $wallOwner->getWallType() == 2)
$post->setSuggested(1);
$post->save();
@ -337,24 +381,21 @@ final class WallPresenter extends OpenVKPresenter
$this->flashFail("err", tr("failed_to_publish_post"), tr("post_is_too_big"));
}
foreach($horizontal_attachments as $horizontal_attachment) {
if(!$horizontal_attachment || $horizontal_attachment->isDeleted() || !$horizontal_attachment->canBeViewedBy($this->user->identity)) {
continue;
}
$post->attach($horizontal_attachment);
}
foreach($vertical_attachments as $vertical_attachment) {
if(!$vertical_attachment || $vertical_attachment->isDeleted() || !$vertical_attachment->canBeViewedBy($this->user->identity)) {
continue;
}
$post->attach($vertical_attachment);
}
foreach($photos as $photo)
$post->attach($photo);
if(sizeof($videos) > 0)
foreach($videos as $vid)
$post->attach($vid);
if(!is_null($poll))
$post->attach($poll);
if(!is_null($note))
$post->attach($note);
foreach($audios as $audio)
$post->attach($audio);
if($wall > 0 && $wall !== $this->user->identity->getId())
(new WallPostNotification($wallOwner, $post, $this->user->identity))->emit();
@ -363,7 +404,9 @@ final class WallPresenter extends OpenVKPresenter
if($wall > 0)
$excludeMentions[] = $wall;
if(!$should_be_suggested) {
if($wall < 0 && !$wallOwner->canBeModifiedBy($this->user->identity) && $wallOwner->getWallType() == 2) {
# Чтобы не было упоминаний из предложки
} else {
$mentions = iterator_to_array($post->resolveMentions($excludeMentions));
foreach($mentions as $mentionee)
@ -371,7 +414,18 @@ final class WallPresenter extends OpenVKPresenter
(new MentionNotification($mentionee, $post, $post->getOwner(), strip_tags($post->getText())))->emit();
}
if($should_be_suggested) {
if($wall < 0 && !$wallOwner->canBeModifiedBy($this->user->identity) && $wallOwner->getWallType() == 2) {
$suggsCount = $this->posts->getSuggestedPostsCount($wallOwner->getId());
if($suggsCount % 10 == 0) {
$managers = $wallOwner->getManagers();
$owner = $wallOwner->getOwner();
(new NewSuggestedPostsNotification($owner, $wallOwner))->emit();
foreach($managers as $manager)
(new NewSuggestedPostsNotification($manager->getUser(), $wallOwner))->emit();
}
$this->redirect("/club".$wallOwner->getId()."/suggested");
} else {
$this->redirect($wallOwner->getURL());
@ -422,12 +476,6 @@ final class WallPresenter extends OpenVKPresenter
if(!is_null($this->user)) {
$post->toggleLike($this->user->identity);
}
if($_SERVER["REQUEST_METHOD"] === "POST") {
$this->returnJson([
'success' => true,
]);
}
$this->redirect("$_SERVER[HTTP_REFERER]#postGarter=" . $post->getId());
}

View file

@ -17,7 +17,6 @@
{script "js/node_modules/umbrellajs/umbrella.min.js"}
{script "js/l10n.js"}
{script "js/openvk.cls.js"}
{script "js/utils.js"}
{script "js/node_modules/dashjs/dist/dash.all.min.js"}
<script src="/assets/packages/static/openvk/js/node_modules/cropperjs/dist/cropper.js" type="module"></script>
{script "js/al_music.js"}
@ -27,7 +26,6 @@
{css "js/node_modules/tippy.js/dist/border.css"}
{css "js/node_modules/tippy.js/dist/svg-arrow.css"}
{css "js/node_modules/tippy.js/themes/light.css"}
{css "js/node_modules/jquery-ui/themes/base/resizable.css"}
{script "js/node_modules/@popperjs/core/dist/umd/popper.min.js"}
{script "js/node_modules/tippy.js/dist/tippy-bundle.umd.min.js"}
{script "js/node_modules/handlebars/dist/handlebars.min.js"}
@ -53,10 +51,7 @@
<div n:if="OPENVK_ROOT_CONF['openvk']['preferences']['bellsAndWhistles']['testLabel']" id="test-label">FOR TESTING PURPOSES ONLY</div>
<div class="notifications_global_wrap"></div>
<div class="dimmer">
<div id='absolute_territory'></div>
</div>
<div class="upLeftErrors"></div>
<div class="dimmer"></div>
<div class="articleView">
<a id="articleCloseButton" class="button" href="javascript:void(u('body').removeClass('article'));">{_close}</a>
@ -250,9 +245,9 @@
<div class="floating_sidebar">
<a id="minilink-friends" class="minilink" href="/friends{$thisUser->getId()}">
<object type="internal/link" n:if="$thisUser->getRequestsCount() > 0">
<object type="internal/link" n:if="$thisUser->getFollowersCount() > 0">
<div class="counter">
+{$thisUser->getRequestsCount()}
+{$thisUser->getFollowersCount()}
</div>
</object>
<img src="/assets/packages/static/openvk/img/friends.svg">
@ -373,7 +368,7 @@
</div>
<div id="ajloader" class="loader">
<img src="/assets/packages/static/openvk/img/loading_mini.gif">
<img src="/assets/packages/static/openvk/img/loading_mini.gif" style="width: 40px;">
</div>
{include "components/cookies.xml"}
@ -391,11 +386,9 @@
{script "js/al_polls.js"}
{script "js/al_suggestions.js"}
{script "js/al_navigation.js"}
{script "js/al_comments.js"}
{ifset $thisUser}
{script "js/al_notifs.js"}
{script "js/al_feed.js"}
{/ifset}
<script>bsdnHydrate();</script>
@ -437,9 +430,6 @@
window.openvk = {
"audio_genres": {\openvk\Web\Models\Entities\Audio::genres},
"at_search": {$atSearch ?? false},
"max_attachments": {\OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["postSizes"]["maxAttachments"] ?? 10},
"max_filesize_mb": 5,
"current_id": {$thisUser ? $thisUser->getId() : 0},
}
</script>

View file

@ -385,8 +385,8 @@
<tr>
<td class="e">
Vladimir Barinov (veselcraft), Celestora, Konstantin Kichulkin (kosfurler),
Daniel Myslivets, Maxim Leshchenko (maksales / maksalees), n1rwana and
Jillian Österreich (Lumaeris)
Nikita Volkov (sup_ban), Daniel Myslivets, Maxim Leshchenko (maksales / maksalees)
and n1rwana
</td>
</tr>
</tbody>
@ -400,7 +400,7 @@
<tr>
<td class="e">
Vladimir Barinov (veselcraft) and Konstantin Kichulkin (kosfurler)<br/>
OpenVK is a free open source software that "cosplays" (or imitates) older versions of a Russian social network called VKontakte. VKontakte belongs to VK (formerly Mail.ru Group).
OpenVK is a free open source software that "cosplays" (or imitates) older versions of a Russian social network called VKontakte. VKontakte belongs to Pavel Durov and VK Group.
</td>
</tr>
</tbody>
@ -447,7 +447,7 @@
</tr>
<tr>
<td class="e">Initial hosting</td>
<td class="v">Jillian Österreich (Lumaeris) and Celestora</td>
<td class="v">Lumaeris and Celestora</td>
</tr>
<tr>
<td class="e">Initial bug-tracker hosting</td>
@ -459,7 +459,7 @@
</tr>
<tr>
<td class="e">Illustrations</td>
<td class="v">Ash Defenders, Polina Katunina (ktp0li)</td>
<td class="v">Ash Defenders, Polina Katunina (RousPhaul)</td>
</tr>
<tr>
<td class="e">Best barmaid</td>
@ -479,9 +479,9 @@
</tr>
<tr class="e">
<td>
kovaltim, Vladimir Lapskiy (0x7d5), Alexander Minkin (WerySkok), Polina Katunina (ktp0li), veth,
kovaltim, Vladimir Lapskiy (0x7d5), Alexander Minkin (WerySkok), Polina Katunina (RousPhaul), veth,
Egor Shevchenko, Vadim Korovin (yuni), Ash Defenders,
Pavel Silaev, Dmitriy Daemon, Jillian Österreich (Lumaeris),
Pavel Silaev, Dmitriy Daemon, Lumaeris,
cmed404 and unknown tester, who disappeared shortly after trying to upload post with cat.
</td>
</tr>

View file

@ -5,17 +5,17 @@
<div id="audioEmbed-{$id}" data-realid="{$audio->getId()}" {if $hideButtons}data-prettyid="{$audio->getPrettyId()}" data-name="{$audio->getName()}"{/if} data-genre="{$audio->getGenre()}" class="audioEmbed {if !$isAvailable}processed{/if} {if $isWithdrawn}withdrawn{/if}" data-length="{$audio->getLength()}" data-keys="{json_encode($audio->getKeys())}" data-url="{$audio->getURL()}">
<audio class="audio" />
<div id="miniplayer" class="audioEntry">
<div class='audioEntryWrapper' style="display: flex;" draggable='true'>
<div id="miniplayer" class="audioEntry" style="min-height: 39px;">
<div style="display: flex;">
<div class="playerButton">
<div class="playIcon"></div>
</div>
<div class="status" draggable='false'>
<div class="status" style="margin-top: 12px;">
<div class="mediaInfo noOverflow">
<div class="info">
<strong class="performer">
<a href="/search?section=audios&order=listens&only_performers=on&q={$audio->getPerformer()}">{$audio->getPerformer()}</a>
<a href="/search?query=&section=audios&order=listens&only_performers=on&q={$audio->getPerformer()}">{$audio->getPerformer()}</a>
</strong>
<span class="title {if !empty($audio->getLyrics())}withLyrics{/if}">{$audio->getTitle()}</span>
@ -27,8 +27,8 @@
</div>
</div>
<div class="volume">
<span class="nobold {if !$hideButtons}hideOnHover{/if}" data-unformatted="{$audio->getLength()}">{$audio->getFormattedLength()}</span>
<div class="volume" style="display: flex; flex-direction: column;width:14%;">
<span class="nobold {if !$hideButtons}hideOnHover{/if}" data-unformatted="{$audio->getLength()}" style="text-align: center;margin-top: 12px;">{$audio->getFormattedLength()}</span>
<div class="buttons">
{php $hasAudio = isset($thisUser) && $audio->isInLibraryOf($thisUser)}
@ -44,7 +44,7 @@
</div>
</div>
</div>
<div class="subTracks" draggable='false'>
<div class="subTracks">
<div class="lengthTrackWrapper">
<div class="track lengthTrack">
<div class="selectableTrack" n:attr="style => $isWithdrawn ? 'display: none;' : ''">

View file

@ -168,10 +168,10 @@
{/if}
{var $canReport = $thisUser->getId() != $club->getOwner()->getId()}
{if $canReport}
<a class="profile_link" style="display:block;" href="javascript:reportClub()">{_report}</a>
<a class="profile_link" style="display:block;" href="javascript:reportVideo()">{_report}</a>
<script>
function reportClub() {
function reportVideo() {
uReportMsgTxt = tr("going_to_report_club");
uReportMsgTxt += "<br/>"+tr("report_question_text");
uReportMsgTxt += "<br/><br/><b>"+tr("report_reason")+"</b>: <input type='text' id='uReportMsgInput' placeholder='" + tr("reason") + "' />"
@ -194,9 +194,6 @@
}
</script>
{/if}
<a n:if="!$club->isHideFromGlobalFeedEnabled()" class="profile_link" style="display:block;" id="__ignoreSomeone" data-val='{!$ignore_status ? 1 : 0}' data-id="{$club->getRealId()}">
{if !$ignore_status}{_ignore_club}{else}{_unignore_club}{/if}
</a>
</div>
<div>
<div class="content_title_expanded" onclick="hidePanel(this);">

View file

@ -4,72 +4,76 @@
{block header}
{ifset $album}
{var $album_owner = $album->getOwner()}
<a href="{$album_owner->getURL()}">
{$album_owner->getCanonicalName()}
<a href="{$album->getOwner()->getURL()}">
{$album->getOwner()->getCanonicalName()}
</a>
{if ($album_owner instanceof openvk\Web\Models\Entities\Club)}
» <a href="/albums{$album_owner->getId() * -1}">{_albums}</a>
{if ($album->getOwner() instanceof openvk\Web\Models\Entities\Club)}
» <a href="/albums{$album->getOwner()->getId() * -1}">{_albums}</a>
{else}
» <a href="/albums{$album_owner->getId()}">{_albums}</a>
» <a href="/albums{$album->getOwner()->getId()}">{_albums}</a>
{/if}
» <a href="/album{$album->getPrettyId()}">{$album->getName()}</a>
{else}
<a href="{$owner->getURL()}">{$owner->getCanonicalName()}</a>
<a href="{$photo->getOwner()->getURL()}">{$photo->getOwner()->getCanonicalName()}</a>
{/ifset}
» {_photo}
{/block}
{block content}
<div class='media-page-wrapper photo-page-wrapper'>
<div class='photo-page-wrapper-photo'>
<img src="{$photo->getURLBySizeId('large')}" />
<center style="margin-bottom: 8pt;">
<img src="{$photo->getURLBySizeId('large')}" style="max-width: 80%; max-height: 60vh;" />
</center>
<hr/>
<div style="width: 100%; min-height: 100px;" class="ovk-photo-details">
<div style="float: left; min-height: 100px; width: 68%;margin-left: 3px;">
{include "../components/comments.xml", comments => $comments, count => $cCount, page => $cPage, model => "photos", parent => $photo, custom_id => 999}
</div>
<div class='ovk-photo-details'>
<div class='media-page-wrapper-description'>
<p n:if='!empty($photo->getDescription())'>{$photo->getDescription()}</p>
<div class='upload_time'>
{_info_upload_date}: {$photo->getPublicationTime()}
{if isset($thisUser)}
|
{var $liked = $photo->hasLikeFrom($thisUser)}
{var $likesCount = $photo->getLikesCount()}
<div class='like_wrap tidy'>
<a href="/photo{$photo->getPrettyId()}/like?hash={rawurlencode($csrfToken)}" class="post-like-button" data-liked="{(int) $liked}" data-likes="{$likesCount}">
<div class="heart" id="{if $liked}liked{/if}"></div>
<span class="likeCnt">{if $likesCount > 0}{$likesCount}{/if}</span>
</a>
</div>
{/if}
</div>
<div style="float:right;min-height: 100px;width: 30%;margin-left: 1px;">
<div>
<h4>{_information}</h4>
<span style="color: grey;">{_info_description}:</span>
{$photo->getDescription() ?? "(" . tr("none") . ")"}<br/>
<span style="color: grey;">{_info_uploaded_by}:</span>
<a href="{$photo->getOwner()->getURL()}">{$photo->getOwner()->getFullName()}</a><br/>
<span style="color: grey;">{_info_upload_date}:</span>
{$photo->getPublicationTime()}
</div>
<hr/>
<div class="media-page-wrapper-details">
<div class='media-page-wrapper-comments'>
{include "../components/comments.xml", comments => $comments, count => $cCount, page => $cPage, model => "photos", parent => $photo, custom_id => 999}
</div>
<div class='media-page-wrapper-actions'>
<a href="{$owner->getURL()}" class='media-page-author-block'>
<img class='cCompactAvatars' src="{$owner->getAvatarURL('miniscule')}">
<div class='media-page-author-block-name'>
<b>{$owner->getCanonicalName()}</b>
</div>
</a>
<div n:if="isset($thisUser) && $thisUser->getId() === $photo->getOwner()->getId()">
<a href="/photo{$photo->getPrettyId()}/edit" class="profile_link" style="display:block;width:96%;">{_edit}</a>
<a id="_photoDelete" href="/photo{$photo->getPrettyId()}/delete" class="profile_link" style="display:block;width:96%;">{_delete}</a>
</div>
<a href="{$photo->getURL()}" class="profile_link" target="_blank" style="display:block;width:96%;">{_"open_original"}</a>
<a n:if="isset($thisUser) && $thisUser->getId() != $photo->getOwner()->getId()" class="profile_link" style="display:block;width:96%;" href="javascript:reportPhoto({$photo->getId()})">{_report}</a>
<a n:if="isset($thisUser)" onclick="javascript:repost({$photo->getPrettyId()}, 'photo')" class="profile_link" style="display:block;width:96%;">
{_share}
</a>
</div>
<br/>
<h4>{_actions}</h4>
{if isset($thisUser) && $thisUser->getId() != $photo->getOwner()->getId()}
{var canReport = true}
{/if}
<div n:if="isset($thisUser) && $thisUser->getId() === $photo->getOwner()->getId()">
<a href="/photo{$photo->getPrettyId()}/edit" class="profile_link" style="display:block;width:96%;">{_edit}</a>
<a id="_photoDelete" href="/photo{$photo->getPrettyId()}/delete" class="profile_link" style="display:block;width:96%;">{_delete}</a>
</div>
<a href="{$photo->getURL()}" class="profile_link" target="_blank" style="display:block;width:96%;">{_"open_original"}</a>
<a n:if="$canReport ?? false" class="profile_link" style="display:block;width:96%;" href="javascript:reportPhoto()">{_report}</a>
<script n:if="$canReport ?? false">
function reportPhoto() {
uReportMsgTxt = tr("going_to_report_photo");
uReportMsgTxt += "<br/>"+tr("report_question_text");
uReportMsgTxt += "<br/><br/><b>"+tr("report_reason")+"</b>: <input type='text' id='uReportMsgInput' placeholder='" + tr("reason") + "' />"
MessageBox(tr("report_question"), uReportMsgTxt, [tr("confirm_m"), tr("cancel")], [
(function() {
res = document.querySelector("#uReportMsgInput").value;
xhr = new XMLHttpRequest();
xhr.open("GET", "/report/" + {$photo->getId()} + "?reason=" + res + "&type=photo", true);
xhr.onload = (function() {
if(xhr.responseText.indexOf("reason") === -1)
MessageBox(tr("error"), tr("error_sending_report"), ["OK"], [Function.noop]);
else
MessageBox(tr("action_successfully"), tr("will_be_watched"), ["OK"], [Function.noop]);
});
xhr.send(null);
}),
Function.noop
]);
}
</script>
</div>
</div>
{/block}

View file

@ -29,7 +29,7 @@
</div>
<div class='page_wrap_content' id='search_page'>
<div n:class='page_wrap_content_main, scroll_container, $section == "audios" && $count > 0 ? audios_padding'>
<div n:class='page_wrap_content_main, $section != "posts" ? scroll_container, $section == "audios" && $count > 0 ? audios_padding'>
{if $count > 0}
{if $section === 'users'}
<div class='scroll_node search_content content def_row_content' n:foreach="$data as $dat">

View file

@ -122,8 +122,8 @@
<h4>{_search_group}</h4>
<span>{_search_group_desc}</span>
<form action="/search">
<input name="section" type="hidden" value="groups">
<input name="q" class="header_search_input" value="" style="background: none; width: 155px; padding-left: 3px;">
<input name="type" type="hidden" value="groups">
<input name="query" class="header_search_input" value="" style="background: none; width: 155px; padding-left: 3px;">
<button class="button">{_search_by_groups}</button>
</form>
</div>

View file

@ -166,9 +166,6 @@
{/if}
<a class="profile_link" style="display:block;width:96%;" href="javascript:reportUser()">{_report}</a>
<a n:if="!$user->isHideFromGlobalFeedEnabled()" class="profile_link" style="display:block;width:96%;" id="__ignoreSomeone" data-val='{!$ignore_status ? 1 : 0}' data-id="{$user->getId()}">
{if !$ignore_status}{_ignore_user}{else}{_unignore_user}{/if}
</a>
<script>
function reportUser() {
uReportMsgTxt = tr("going_to_report_user");
@ -325,13 +322,13 @@
</div>
<div style="padding: 5px;">
<div class="ovk-video" n:foreach="$videos as $video">
<a href="/video{$video->getPrettyId()}" class="preview" align="center" id="videoOpen" data-id="{$video->getPrettyId()}">
<a href="/video{$video->getPrettyId()}" class="preview" align="center" id="videoOpen" data-id="{$video->getId()}">
<img
src="{$video->getThumbnailURL()}"
style="max-width: 170px; max-height: 127px; margin: auto;" />
</a>
<div>
<b><a href="/video{$video->getPrettyId()}" id="videoOpen" data-id="{$video->getPrettyId()}">{ovk_proc_strtr($video->getName(), 30)}</a></b><br>
<b><a href="/video{$video->getPrettyId()}" id="videoOpen" data-id="{$video->getId()}">{ovk_proc_strtr($video->getName(), 30)}</a></b><br>
<span style="font-size: 10px;">{$video->getPublicationTime()} | {_comments} ({$video->getCommentsCount()})</span>
</div>
</div>

View file

@ -11,88 +11,91 @@
{/block}
{block content}
<div class='media-page-wrapper video-page-wrapper'>
<div class='video-page-wrapper-video'>
{if $video->getType() === 0}
<div class="bsdn" data-name="{$video->getName()}" data-author="{$user->getCanonicalName()}">
<video src="{$video->getURL()}"></video>
</div>
<center style="margin-bottom: 8pt;">
{if $video->getType() === 0}
<div class="bsdn" data-name="{$video->getName()}" data-author="{$user->getCanonicalName()}">
<video src="{$video->getURL()}"></video>
</div>
{else}
{var $driver = $video->getVideoDriver()}
{if !$driver}
{_unknown_video}
{else}
{var $driver = $video->getVideoDriver()}
{if !$driver}
{_unknown_video}
{else}
{$driver->getEmbed()|noescape}
{$driver->getEmbed()|noescape}
{/if}
{/if}
</center>
<hr/>
<div style="width: 100%; min-height: 100px;">
<div style="float: left; min-height: 100px; width: 68%; margin-right: 2%;" id="comments">
{include "../components/comments.xml",
comments => $comments,
count => $cCount,
page => $cPage,
model => "videos",
parent => $video}
</div>
<div style="float: left; min-height: 100px; width: 30%; overflow: hidden; overflow-wrap: break-word;">
<div>
<h4>{_information}</h4>
<span style="color: grey;">{_info_name}:</span>
{$video->getName()}<br/>
<span style="color: grey;">{_info_description}:</span>
{$video->getDescription() ?? "(" . tr("none") . ")"}<br/>
<span style="color: grey;">{_info_uploaded_by}:</span>
<a href="{$user->getURL()}">{$user->getFullName()}</a><br/>
<span style="color: grey;">{_info_upload_date}:</span>
{$video->getPublicationTime()}
</div>
<br/>
<div>
<div n:if="isset($thisUser) && $thisUser->getId() === $user->getId()">
<h4>{_actions}</h4>
<a href="/video{$video->getPrettyId()}/edit" class="profile_link" style="display:block;width:96%;">
{_edit}
</a>
<a href="/video{$video->getPrettyId()}/remove" class="profile_link" style="display:block;width:96%;">
{_delete}
</a>
</div>
<a href="/video{$video->getPrettyId()}" class="profile_link" id="videoOpen" data-id="{$video->getId()}" style="display:block;width:96%;">
{_watch_in_window}
</a>
</div>
{if isset($thisUser)}
{if $thisUser->getId() != $video->getOwner()->getId()}
{var canReport = true}
{/if}
{/if}
<a n:if="$canReport ?? false" class="profile_link" style="display:block;width:96%;" href="javascript:reportVideo()">{_report}</a>
<script n:if="$canReport ?? false">
function reportVideo() {
uReportMsgTxt = tr("going_to_report_video");
uReportMsgTxt += "<br/>"+tr("report_question_text");
uReportMsgTxt += "<br/><br/><b>"+tr("report_reason")+"</b>: <input type='text' id='uReportMsgInput' placeholder='" + tr("reason") + "' />"
MessageBox(tr("report_question"), uReportMsgTxt, [tr("confirm_m"), tr("cancel")], [
(function() {
res = document.querySelector("#uReportMsgInput").value;
xhr = new XMLHttpRequest();
xhr.open("GET", "/report/" + {$video->getId()} + "?reason=" + res + "&type=video", true);
xhr.onload = (function() {
if(xhr.responseText.indexOf("reason") === -1)
MessageBox(tr("error"), tr("error_sending_report"), ["OK"], [Function.noop]);
else
MessageBox(tr("action_successfully"), tr("will_be_watched"), ["OK"], [Function.noop]);
});
xhr.send(null);
}),
Function.noop
]);
}
</script>
</div>
<div class='ovk-vid-details'>
<div class='media-page-wrapper-description'>
<p><b>{$video->getName()}</b></p>
<p n:if='!empty($video->getDescription())'>{$video->getDescription()}</p>
<div class='upload_time'>
{_info_upload_date}: {$video->getPublicationTime()}
{if isset($thisUser)}
|
{var $liked = $video->hasLikeFrom($thisUser)}
{var $likesCount = $video->getLikesCount()}
<div class='like_wrap tidy'>
<a href="/video{$video->getPrettyId()}/like?hash={rawurlencode($csrfToken)}" class="post-like-button" data-liked="{(int) $liked}" data-likes="{$likesCount}">
<div class="heart" id="{if $liked}liked{/if}"></div>
<span class="likeCnt">{if $likesCount > 0}{$likesCount}{/if}</span>
</a>
</div>
{/if}
</div>
</div>
<hr/>
<div class="media-page-wrapper-details">
<div class='media-page-wrapper-comments' id="comments">
{include "../components/comments.xml",
comments => $comments,
count => $cCount,
page => $cPage,
model => "videos",
parent => $video}
</div>
<div class='media-page-wrapper-actions'>
<a href="{$user->getURL()}" class='media-page-author-block'>
<img class='cCompactAvatars' src="{$user->getAvatarURL('miniscule')}">
<div class='media-page-author-block-name'>
<b>{$user->getCanonicalName()}</b>
</div>
</a>
<div>
<div n:if="isset($thisUser) && $thisUser->getId() === $user->getId()">
<a href="/video{$video->getPrettyId()}/edit" class="profile_link" style="display:block;width:96%;">
{_edit}
</a>
<a id='_videoDelete' href="/video{$video->getPrettyId()}/remove" class="profile_link" style="display:block;width:96%;">
{_delete}
</a>
</div>
<a n:if="isset($thisUser)" onclick="javascript:repost({$video->getPrettyId()}, 'video')" class="profile_link" style="display:block;width:96%;">
{_share}
</a>
</div>
{if isset($thisUser)}
{if $thisUser->getId() != $video->getOwner()->getId()}
{var canReport = true}
{/if}
{/if}
<a n:if="$canReport ?? false" class="profile_link" style="display:block;width:96%;" href="javascript:reportVideo({$video->getId()})">{_report}</a>
<a n:if="$video->getType() == 0" href="{$video->getURL()}" download="" class="profile_link" style="display:block;width:96%;">{_download_video}</a>
</div>
</div>
</div>
</div>
{/block}

View file

@ -15,20 +15,16 @@
<div n:attr="id => (isset($globalFeed) ? 'activetabs' : 'ki')" class="tab">
<a n:attr="id => (isset($globalFeed) ? 'act_tab_a' : 'ki')" href="/feed/all">{_all_news}</a>
</div>
<a href='#' id="__feed_settings_link" data-pagescount='{ceil($paginatorConf->count / $paginatorConf->perPage)}'>{_feed_settings}</a>
</div>
<div n:class="postFeedWrapper, $thisUser->hasMicroblogEnabled() ? postFeedWrapperMicroblog">
{include "../components/textArea.xml", route => "/wall" . $thisUser->getId() . "/makePost", graffiti => true, polls => true, notes => true, hasSource => true}
</div>
<div class='scroll_container'>
<div class='scroll_node' n:foreach='$posts as $post'>
<a name="postGarter={$post->getId()}"></a>
{include "../components/post.xml", post => $post, onWallOf => true, commentSection => true}
</div>
</div>
{foreach $posts as $post}
<a name="postGarter={$post->getId()}"></a>
{include "../components/post.xml", post => $post, onWallOf => true, commentSection => true}
{/foreach}
<div class="postFeedBottom">
<div class="postFeedPaginator">
@ -57,4 +53,8 @@
window.location.assign(url.replace("__padding", e.target.value));
});
</script>
{if isset($thisUser) && $thisUser->hasMicroblogEnabled()}
{script "js/al_comments.js"}
{/if}
{/block}

View file

@ -31,13 +31,13 @@
{include "../components/textArea.xml", route => "/wall$owner/makePost", hasSource => true}
</div>
<div class="content scroll_container">
<div class="content">
{if sizeof($posts) > 0}
<div class='scroll_node' n:foreach='$posts as $post'>
{foreach $posts as $post}
<a name="postGarter={$post->getId()}"></a>
{include "../components/post.xml", post => $post, commentSection => true}
</div>
{/foreach}
{include "../components/paginator.xml", conf => $paginatorConf}
{else}
{_no_posts_abstract}
@ -45,4 +45,8 @@
</div>
</div>
</div>
{if isset($thisUser) && $thisUser->hasMicroblogEnabled()}
{script "js/al_comments.js"}
{/if}
{/block}

View file

@ -1,7 +1,7 @@
{if $attachment instanceof \openvk\Web\Models\Entities\Photo}
{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})">
<a href="{$link}" onclick="OpenMiniature(event, {$attachment->getURLBySizeId('normal')}, {$parent->getPrettyId()}, {$attachment->getPrettyId()}, {$parentType})">
<img class="media media_makima" src="{$attachment->getURLBySizeId('normal')}" alt="{$attachment->getDescription()}" loading=lazy />
</a>
{else}
@ -10,50 +10,39 @@
</a>
{/if}
{elseif $attachment instanceof \openvk\Web\Models\Entities\Video}
{if $tilesCount <= 1}
{if $attachment->getType() === 0}
<div class="bsdn media" data-name="{$attachment->getName()}" data-author="{$attachment->getOwner()->getCanonicalName()}">
<video class="media" src="{$attachment->getURL()}"></video>
</div>
{else}
{var $driver = $attachment->getVideoDriver()}
{if !$driver}
<span style="color:red;">{_version_incompatibility}</span>
{else}
{$driver->getEmbed("100%")|noescape}
{/if}
{/if}
<div class="video-wowzer">
<div class="small-video-ico"></div>
<a href="/video{$attachment->getPrettyId()}" id="videoOpen" data-id="{$attachment->getPrettyId()}">{$attachment->getName()}</a>
<span class="video-wowzer-length" n:if="$attachment->getLength() != NULL">({$attachment->getFormattedLength()})</span>
{if $attachment->getType() === 0}
<div class="bsdn media" data-name="{$attachment->getName()}" data-author="{$attachment->getOwner()->getCanonicalName()}">
<video class="media" src="{$attachment->getURL()}"></video>
</div>
{else}
<a class='compact_video' id='videoOpen' data-id='{$attachment->getPrettyId()}' href="/video{$attachment->getPrettyId()}">
<div class='play-button'>
<div class='play-button-ico'></div>
</div>
<div class='video-length' n:if="$attachment->getLength() != NULL">
{$attachment->getFormattedLength()}
</div>
<img class="media media_makima" src="{$attachment->getThumbnailURL()}" loading=lazy />
</a>
{var $driver = $attachment->getVideoDriver()}
{if !$driver}
<span style="color:red;">{_version_incompatibility}</span>
{else}
{$driver->getEmbed("100%")|noescape}
{/if}
{/if}
<div class="video-wowzer">
<img src="/assets/packages/static/openvk/img/videoico.png" />
<a href="/video{$attachment->getPrettyId()}" id="videoOpen" data-id="{$attachment->getId()}">{$attachment->getName()}</a>
</div>
{elseif $attachment instanceof \openvk\Web\Models\Entities\Poll}
{presenter "openvk!Poll->view", $attachment->getId()}
{elseif $attachment instanceof \openvk\Web\Models\Entities\Note}
<div data-att_type='note' data-att_id="{$attachment->getPrettyId()}">
{if !$attachment->isDeleted()}
<div class="attachment_note">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 10"><polygon points="0 0 0 10 8 10 8 4 4 4 4 0 0 0"/><polygon points="5 0 5 3 8 3 5 0"/></svg>
<div class='attachment_note_content'>
<span class="attachment_note_text">{_note}</span>
<span class="attachment_note_name"><a href="javascript:void(showArticle({$attachment->getId()}));">{ovk_proc_strtr($attachment->getName(), 66)}</a></span>
</div>
<img class="attachment_note_icon" src="/assets/packages/static/openvk/img/note.svg">
<span class="attachment_note_text">{_note}</span>
<span class="attachment_note_name"><a href="javascript:void(showArticle({$attachment->getId()}));">{ovk_proc_strtr($attachment->getName(), 66)}</a></span>
</div>
</div>
{else}
<div class="attachment_note">
<img class="attachment_note_icon" src="/assets/packages/static/openvk/img/note.svg">
<span class="attachment_note_text">{_note}</span>
<span class="attachment_note_name">{_deleted}</span>
</div>
{/if}
{elseif $attachment instanceof \openvk\Web\Models\Entities\Post}
{php $GLOBALS["_nesAttGloCou"] = (isset($GLOBALS["_nesAttGloCou"]) ? $GLOBALS["_nesAttGloCou"] : 0) + 1}
{if $GLOBALS["_nesAttGloCou"] > 2}
@ -62,7 +51,7 @@
{include "post.xml", post => $attachment, compact => true}
{/if}
{elseif $attachment instanceof \openvk\Web\Models\Entities\Audio}
<div style="width:100%;" data-att_type='audio' data-att_id="{$attachment->getPrettyId()}">
<div style="width:100%;">
{include "../Audio/player.xml", audio => $attachment}
</div>
{else}

View file

@ -5,7 +5,7 @@
{var $postId = $target instanceof \openvk\Web\Models\Entities\Post ? $target->getId() : NULL}
<a name="cid={$comment->getId()}"></a>
<table data-id="1_{$comment->getId()}" border="0" style="font-size: 11px;" class="post comment" id="_comment{$comment->getId()}" data-comment-id="{$comment->getId()}" data-owner-id="{$author->getId()}" data-from-group="{$author instanceof $Club}" n:attr="data-post-id => $postId">
<table border="0" style="font-size: 11px;" class="post comment" id="_comment{$comment->getId()}" data-comment-id="{$comment->getId()}" data-owner-id="{$author->getId()}" data-from-group="{$author instanceof $Club}" n:attr="data-post-id => $postId">
<tbody>
<tr>
<td width="30" valign="top">
@ -22,12 +22,12 @@
</div>
<div class="post-content" id="{$comment->getId()}">
<div class="text" id="text{$comment->getId()}">
<span class="really_text">{$comment->getText()|noescape}</span>
<span data-text="{$comment->getText(false)}" class="really_text">{$comment->getText()|noescape}</span>
{var $attachmentsLayout = $comment->getChildrenWithLayout(288)}
<div n:ifcontent class="attachments attachments_b" style="height: {$attachmentsLayout->height|noescape}; width: {$attachmentsLayout->width|noescape};">
<div class="attachment" n:foreach="$attachmentsLayout->tiles as $attachment" style="float: {$attachment[3]|noescape}; width: {$attachment[0]|noescape}; height: {$attachment[1]|noescape};" data-localized-nsfw-text="{_nsfw_warning}">
{include "attachment.xml", attachment => $attachment[2], parent => $comment, parentType => "comment", tilesCount => sizeof($attachmentsLayout->tiles)}
{include "attachment.xml", attachment => $attachment[2], parent => $comment, parentType => "comment"}
</div>
</div>
@ -77,7 +77,6 @@
</span>
</div>
</div>
<div class='post-edit'></div>
</td>
</tr>
</tbody>

View file

@ -20,3 +20,5 @@
{else}
{_comments_tip}
{/if}
{script "js/al_comments.js"}

View file

@ -18,7 +18,7 @@
{var $commentTextAreaId = $post === NULL ? rand(1,300) : $post->getId()}
<table border="0" style="font-size: 11px;" data-id="{$post->getPrettyId()}" n:class="post, !$compact ? post-divider, $post->isExplicit() ? post-nsfw">
<table border="0" style="font-size: 11px;" n:class="post, !$compact ? post-divider, $post->isExplicit() ? post-nsfw">
<tbody>
<tr>
<td width="54" valign="top">
@ -68,10 +68,13 @@
{/if}
{if $post->canBeEditedBy($thisUser) && !($forceNoEditLink ?? false) && $compact == false}
<a class="edit" id="editPost"></a>
<a class="edit" id="editPost"
data-id="{$post->getId()}"
data-nsfw="{(int)$post->isExplicit()}"
{if $post->getTargetWall() < 0 && $wallOwner->canBeModifiedBy($thisUser)}data-fromgroup="{(int)$post->isPostedOnBehalfOfGroup()}"{/if}></a>
{/if}
</div>
<div class="post-content" id="{$post->getPrettyId()}" data-localized-nsfw-text="{_nsfw_warning}">
<div class="post-content" id="{$post->getPrettyId()}">
<div class="text" id="text{$post->getPrettyId()}">
<span data-text="{$post->getText(false)}" class="really_text">{$post->getText()|noescape}</span>
@ -81,8 +84,8 @@
{/if}
{var $attachmentsLayout = $post->getChildrenWithLayout($width)}
<div n:ifcontent class="attachments attachments_b" style="height: {$attachmentsLayout->height|noescape}; width: {$attachmentsLayout->width|noescape};">
<div class="attachment" n:foreach="$attachmentsLayout->tiles as $attachment" style="float: {$attachment[3]|noescape}; width: {$attachment[0]|noescape}; height: {$attachment[1]|noescape};">
{include "../attachment.xml", attachment => $attachment[2], parent => $post, parentType => "post", tilesCount => sizeof($attachmentsLayout->tiles)}
<div class="attachment" n:foreach="$attachmentsLayout->tiles as $attachment" style="float: {$attachment[3]|noescape}; width: {$attachment[0]|noescape}; height: {$attachment[1]|noescape};" data-localized-nsfw-text="{_nsfw_warning}">
{include "../attachment.xml", attachment => $attachment[2], parent => $post, parentType => "post"}
</div>
</div>
@ -109,7 +112,6 @@
</span>
</div>
</div>
<div class='post-edit' n:if='!$compact'></div>
<div class="post-menu" n:if="$compact == false">
<a href="{if !$suggestion}/wall{$post->getPrettyId()}{else}javascript:void(0){/if}" class="date">{$post->getPublicationTime()}
<span n:if="$post->getEditTime()" class="edited editedMark">({_edited_short})</span>
@ -124,7 +126,7 @@
<a n:if="!($forceNoCommentsLink ?? false) && $commentsCount == 0" href="javascript:expand_comment_textarea({$commentTextAreaId})">{_comment}</a>
<div class="like_wrap">
<a n:if="!($forceNoShareLink ?? false)" id="reposts{$post->getPrettyId()}" class="post-share-button" href="javascript:repost('{$post->getPrettyId()}', 'post')">
<a n:if="!($forceNoShareLink ?? false)" id="reposts{$post->getPrettyId()}" class="post-share-button" href="javascript:repostPost('{$post->getPrettyId()}', '{rawurlencode($csrfToken)}')">
<div class="repost-icon" style="opacity: 0.4;"></div>
<span class="likeCnt" id="repostsCount{$post->getPrettyId()}">{if $repostsCount > 0}{$repostsCount}{/if}</span>
</a>

View file

@ -15,7 +15,7 @@
<table border="0" style="font-size: 11px;" data-id="{$post->getPrettyId()}" n:class="post, $post->isExplicit() ? post-nsfw">
<table border="0" style="font-size: 11px;" n:class="post, $post->isExplicit() ? post-nsfw">
<tbody>
<tr>
<td width="54" valign="top">
@ -67,7 +67,7 @@
</a>
</a>
</div>
<div class="post-content" id="{$post->getPrettyId()}" data-localized-nsfw-text="{_nsfw_warning}">
<div class="post-content" id="{$post->getPrettyId()}">
<div class="text" id="text{$post->getPrettyId()}">
{var $owner = $author->getId()}
@ -79,8 +79,8 @@
{/if}
{var $attachmentsLayout = $post->getChildrenWithLayout($width)}
<div n:ifcontent class="attachments attachments_b" style="height: {$attachmentsLayout->height|noescape}; width: {$attachmentsLayout->width|noescape};">
<div class="attachment" n:foreach="$attachmentsLayout->tiles as $attachment" style="float: {$attachment[3]|noescape}; width: {$attachment[0]|noescape}; height: {$attachment[1]|noescape};">
{include "../attachment.xml", attachment => $attachment[2], parent => $post, parentType => "post", tilesCount => sizeof($attachmentsLayout->tiles)}
<div class="attachment" n:foreach="$attachmentsLayout->tiles as $attachment" style="float: {$attachment[3]|noescape}; width: {$attachment[0]|noescape}; height: {$attachment[1]|noescape};" data-localized-nsfw-text="{_nsfw_warning}">
{include "../attachment.xml", attachment => $attachment[2], parent => $post, parentType => "post"}
</div>
</div>
@ -111,7 +111,6 @@
</span>
</div>
</div>
<div class='post-edit' n:if='!$compact'></div>
<div n:if="!($compact ?? false)" class="post-menu">
{if is_null($thisUser)}
{var $forceNoDeleteLink = true}
@ -120,7 +119,9 @@
{if !($forceNoEditLink ?? false) && $post->canBeEditedBy($thisUser)}
<a id="editPost"
data-id="{$post->getPrettyId()}">{_edit}</a> &nbsp;|&nbsp;
data-id="{$post->getId()}"
data-nsfw="{(int)$post->isExplicit()}"
{if $post->getTargetWall() < 0 && $wallOwner->canBeModifiedBy($thisUser)}data-fromgroup="{(int)$post->isPostedOnBehalfOfGroup()}"{/if}>{_edit}</a> &nbsp;|&nbsp;
{/if}
{if !($forceNoDeleteLink ?? false) && $canBeDeleted}
@ -147,7 +148,7 @@
&nbsp;|&nbsp;
{/if}
<a n:if="!($forceNoShareLink ?? false)" id="reposts{$post->getPrettyId()}" class="post-share-button" {ifset $thisUser} href="javascript:repost('{$post->getPrettyId()}', 'post')"{/ifset}>
<a n:if="!($forceNoShareLink ?? false)" id="reposts{$post->getPrettyId()}" class="post-share-button" {ifset $thisUser} href="javascript:repostPost('{$post->getPrettyId()}', '{rawurlencode($csrfToken)}')"{/ifset}>
{_share}
{if $repostsCount > 0}
(<b id="repostsCount{$post->getPrettyId()}">{$repostsCount}</b>)

View file

@ -2,18 +2,26 @@
{var $textAreaId = ($post ?? NULL) === NULL ? (++$GLOBALS["textAreaCtr"]) : $post->getId()}
{var $textAreaId = ($custom_id ?? NULL) === NULL ? $textAreaId : $custom_id}
<div id="write" class='model_content_textarea' style="padding: 5px 0;">
<div id="write" style="padding: 5px 0;" onfocusin="expand_wall_textarea({$textAreaId});">
<form action="{$route}" method="post" enctype="multipart/form-data" style="margin:0;">
<textarea id="wall-post-input{$textAreaId}" placeholder="{_write}" name="text" style="width: 100%;resize: none;" class="small-textarea"></textarea>
<div>
<!-- padding to fix <br/> bug -->
</div>
<div id="post-buttons{$textAreaId}" class='post-buttons' style="display: none;">
<div class="post-horizontal"></div>
<div class="post-vertical"></div>
<div id="post-buttons{$textAreaId}" style="display: none;">
<div class="upload">
</div>
<div class="post-upload">
<span style="color: inherit;"></span>
</div>
<div class="post-has-poll">
{_poll}
</div>
<div class="post-has-note"></div>
<div class="post-has-videos"></div>
<div class="post-has-audios"></div>
<div class="post-source"></div>
<div n:if="$postOpts ?? true" class="post-opts">
@ -54,44 +62,42 @@
<input type="checkbox" name="as_group" /> {_comment_as_group}
</label>
</div>
<input type="hidden" name="horizontal_attachments" value="" />
<input type="hidden" name="vertical_attachments" value="" />
<input type="hidden" name="photos" value="" />
<input type="hidden" name="videos" value="" />
<input type="hidden" name="audios" value="" />
<input type="hidden" name="poll" value="none" />
<input type="hidden" id="note" name="note" value="none" />
<input type="hidden" id="source" name="source" value="none" />
<input type="hidden" name="type" value="1" />
<input type="hidden" name="hash" value="{$csrfToken}" />
<br/>
<input type="submit" value="{_write}" class="button" />
<div style="float: right; display: flex; flex-direction: column;">
<a class='menu_toggler'>
<a href="javascript:toggleMenu({$textAreaId});">
{_attach}
</a>
<div id="wallAttachmentMenu" class="hidden">
<a class="header menu_toggler">
<a class="header" href="javascript:toggleMenu({$textAreaId});">
{_attach}
</a>
<a id="__photoAttachment" {if !is_null($club ?? NULL) && $club->canBeModifiedBy($thisUser)}data-club="{$club->getId()}"{/if}>
<a id="photosAttachments" {if !is_null($club ?? NULL) && $club->canBeModifiedBy($thisUser)}data-club="{$club->getId()}"{/if}>
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/mimetypes/application-x-egon.png" />
{_photo}
</a>
<a id="__videoAttachment">
<a id="videoAttachment">
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/mimetypes/application-vnd.rn-realmedia.png" />
{_video}
</a>
<a id="__audioAttachment">
<a id="_audioAttachment">
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/mimetypes/audio-ac3.png" />
{_audio}
</a>
<a n:if="$notes ?? false" id="__notesAttachment">
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/mimetypes/application-x-srt.png" />
{_note}
</a>
<a n:if="$graffiti ?? false" onclick="initGraffiti(event);">
<a n:if="$graffiti ?? false" href="javascript:initGraffiti({$textAreaId});">
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/actions/draw-brush.png" />
{_graffiti}
</a>
<a n:if="$polls ?? false" onclick="initPoll(event);">
<a n:if="$polls ?? false" href="javascript:initPoll({$textAreaId})">
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/actions/office-chart-bar-stacked.png" />
{_poll}
</a>
@ -106,8 +112,13 @@
</div>
<script>
u("#post-buttons{$textAreaId} input[name='horizontal_attachments']")["nodes"].at(0).value = ""
u("#post-buttons{$textAreaId} input[name='vertical_attachments']")["nodes"].at(0).value = ""
$(document).ready(() => {
setupWallPostInputHandlers({$textAreaId});
});
u("#post-buttons{$textAreaId} input[name='videos']")["nodes"].at(0).value = ""
u("#post-buttons{$textAreaId} input[name='photos']")["nodes"].at(0).value = ""
u("#post-buttons{$textAreaId} input[name='audios']")["nodes"].at(0).value = ""
</script>
{if $graffiti}

View file

@ -3,7 +3,7 @@
<tbody>
<tr>
<td valign="top">
<a href="/video{$video->getPrettyId()}" id='videoOpen' data-id="{$video->getPrettyId()}">
<a href="/video{$video->getPrettyId()}" data-id="{$video->getId()}">
<div class="video-preview">
<img src="{$video->getThumbnailURL()}"
style="max-width: 170px; max-height: 127px; margin: auto;" >
@ -15,13 +15,10 @@
{include infotable, x => $dat}
{else}
<a href="/video{$video->getPrettyId()}">
<b class='video_name' id='videoOpen' data-id="{$video->getPrettyId()}">
<b class='video_name' {$videoModal ? "id='videoOpen'" : ''} data-id="{$video->getId()}">
{$video->getName()}
</b>
</a>
{if $video->getLength()}
({$video->getFormattedLength()})
{/if}
<br/>
<p>
<span class='video_description'>{$video->getDescription() ?? ""}</span>
@ -29,7 +26,7 @@
<span style="color: grey;">{_video_uploaded} {$video->getPublicationTime()}</span><br/>
<p>
<a href="/video{$video->getPrettyId()}" id='videoOpen' data-id="{$video->getPrettyId()}">{_view_video}</a>
<a href="/video{$video->getPrettyId()}" {$videoModal ? "id='videoOpen'" : ''} data-id="{$video->getId()}">{_view_video}</a>
{if $video->getCommentsCount() > 0}| <a href="/video{$video->getPrettyId()}#comments">{_comments} ({$video->getCommentsCount()})</a>{/if}
</p>
{/ifset}

View file

@ -13,13 +13,13 @@
{include "../components/textArea.xml", route => "/wall$owner/makePost", graffiti => true, polls => true, notes => true, hasSource => true}
</div>
<div class="content scroll_container">
<div class="content">
{if sizeof($posts) > 0}
<div class='scroll_node' n:foreach='$posts as $post'>
{foreach $posts as $post}
<a name="postGarter={$post->getId()}"></a>
{include "../components/post.xml", post => $post, commentSection => true}
</div>
{/foreach}
{include "../components/paginator.xml", conf => $paginatorConf}
{else}
{_no_posts_abstract}
@ -28,3 +28,7 @@
</div>
</div>
</div>
{if isset($thisUser) && $thisUser->hasMicroblogEnabled()}
{script "js/al_comments.js"}
{/if}

View file

@ -18,7 +18,7 @@ class Makima
$this->photos = $photos;
}
private function getOrientation($photo, &$ratio): int
private function getOrientation(Photo $photo, &$ratio): int
{
[$width, $height] = $photo->getDimensions();
$ratio = $width / $height;

View file

@ -129,6 +129,8 @@ routes:
handler: "Wall->rss"
- url: "/wall{num}/makePost"
handler: "Wall->makePost"
- url: "/wall/edit"
handler: "Wall->edit"
- url: "/wall{num}_{num}"
handler: "Wall->post"
- url: "/wall{num}_{num}/like"
@ -169,8 +171,6 @@ routes:
handler: "Photos->uploadPhoto"
- url: "/photo{num}_{num}"
handler: "Photos->photo"
- url: "/photo{num}_{num}/like"
handler: "Photos->like"
- url: "/photos/thumbnails/{num}_{text}.jpeg"
handler: "Photos->thumbnail"
- url: "/photos/{text}"
@ -403,8 +403,6 @@ routes:
handler: "About->dev"
- url: "/iapi/getPhotosFromPost/{num}_{num}"
handler: "InternalAPI->getPhotosFromPost"
- url: "/iapi/getPostTemplate/{num}_{num}"
handler: "InternalAPI->getPostTemplate"
- url: "/tour"
handler: "About->tour"
- url: "/{?shortCode}"

View file

@ -267,17 +267,6 @@
color: white;
}
.audioEntry .volume {
display: flex;
flex-direction: column;
width: 14%;
}
.audioEntry .nobold {
text-align: center;
margin-top: 12px;
}
.audioEntry.nowPlaying .volume .nobold {
color: white !important;
}
@ -314,7 +303,6 @@
height: 100%;
position: relative;
width: 100%;
min-height: 39px;
}
.audioEntry .playerButton {
@ -353,7 +341,6 @@
grid-template-columns: 1fr;
width: 85%;
height: 23px;
margin-top: 12px;
}
.audioEntry .status .mediaInfo {
@ -601,6 +588,7 @@
}
.attachAudio {
float: left;
width: 28%;
height: 26px;
padding-top: 11px;
@ -783,7 +771,6 @@
.addToPlaylist {
width: 22%;
float: left;
}
#_addAudioAdditional {

View file

@ -88,7 +88,3 @@ div.ovk-video > div > img
height: 31px;
min-width: 30px;
}
.entity_vertical_list .entity_vertical_list_item img {
border-radius: 20px;
}

View file

@ -24,7 +24,6 @@
gap: 6px;
z-index: 2;
opacity: 0;
height: 43px;
}
.bsdn-player.bsdn-dirty > .bsdn_controls {

View file

@ -7,11 +7,6 @@ body.dimmed > .dimmer {
opacity: .5;
}
body.dimmed > .dimmer #absolute_territory {
margin: 100px;
height: 100%;
}
.ovk-diag-cont {
z-index: 1024;
position: fixed;
@ -64,147 +59,243 @@ body.dimmed > .dimmer #absolute_territory {
margin-left: 10px;
}
/* Modal player */
.ovk-modal-player-window {
box-shadow: 0px 0px 9px 2px rgba(0, 0, 0, 0.2);
/* fullscreen player */
.ovk-fullscreen-player {
top: 9%;
left: 50%;
margin-right: -50%;
transform: translate(-50%, 0%);
z-index: 6667;
position: absolute;
width: 823px;
min-height: 400px;
margin: 9vh auto 0 auto;
box-shadow: 0px 0px 9px 2px rgba(0, 0, 0, 0.2);
}
.ovk-modal-player-window #ovk-player-part {
height: 70vh;
background: black;
padding: 15px 20px;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.ovk-modal-player-window #ovk-player-part .top-part {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.ovk-modal-player-window #ovk-player-part .top-part b {
.top-part span {
color: #515151;
font-size: 12px;
font-size: 13px;
transition: color 200ms ease-in-out;
}
.ovk-modal-player-window #ovk-player-part .top-part .top-part-buttons, .ovk-modal-player-window #ovk-player-part .bottom-part {
color: #515151;
.top-part .clickable:hover {
color: #ffffff;
}
.ovk-modal-player-window #ovk-player-part .top-part .top-part-buttons a, .ovk-modal-player-window #ovk-player-part .bottom-part a {
color: #515151;
.ovk-fullscreen-player .bsdn_teaserTitleBox span {
color: unset;
font-size: unset;
}
.ovk-modal-player-window #ovk-player-info {
display: none;
.ovk-fullscreen-player .bsdn-player {
max-width: 80%;
max-height: 350px;
}
.ovk-modal-player-window #ovk-player-info.shown {
display: block;
.inner-player {
background: #000000;
min-height: 438px;
max-height: 439px;
position: relative;
padding-top: 11px;
}
.ovk-modal-player-window #ovk-player-info {
background: white;
min-height: 200px;
padding: 5px 15px;
.top-part-name {
font-size: 15px;
font-weight: bolder;
margin-left: 20px;
margin-top: 5px;
}
.ovk-modal-player-window .media-page-wrapper-comments {
width: 100%;
.top-part-buttons {
float: right;
margin-right: 20px;
}
.ovk-modal-player-window .center-part {
.top-part-buttons span {
cursor: pointer;
user-select: none;
}
.fplayer {
text-align: center;
height: 90%;
display: flex;
align-items: center;
justify-content: center;
margin-top: 20px;
}
.ovk-modal-player-window .center-part .gray {
.top-part-bottom-buttons {
position: absolute;
margin-left: 20px;
bottom: 0;
margin-bottom: 20px;
}
.top-part-bottom-buttons span {
user-select: none;
}
.top-part .clickable {
cursor: pointer;
}
.bottom-part {
display: none;
background: white;
padding-bottom: 20px;
padding-top: 30px;
}
.left_block {
padding-left: 20px;
/*padding-top: 20px;*/
width: 75%;
float: left;
background: white;
padding-right: 6px;
max-height: 400px;
overflow-y: auto;
}
.right_block {
padding-left: 10px;
/*padding-top: 20px;*/
width: 20%;
border-left: 1px solid gray;
float: right;
}
.bottom-part span {
font-size: 13px;
}
.bottom-part .gray {
color: gray;
}
.ovk-modal-player-window .center-part .bsdn, .ovk-modal-player-window .center-part .bsdn-player {
height: 100%;
width: 100%;
.ovk-fullscreen-dimmer {
/* спижжено у пулла с несколькими картинками там где просмотрщик фоток */
position: fixed;
left: 0px;
top: 0px;
right: 0px;
bottom: 0px;
overflow: auto;
padding-bottom: 20px;
z-index: 300;
}
.v_author {
margin-top: 20px;
}
.miniplayer {
position: absolute;
background: rgba(54, 54, 54, 0.95);
top:0;
background: rgba(54, 54, 54, 0.9);
border-radius: 3px;
min-width: 299px;
min-height: 192px;
z-index: 7777;
padding: 2px 7px;
display: flex;
flex-direction: column;
padding-top: 3px;
z-index: 9999;
}
.miniplayer .miniplayer-head {
display: flex;
justify-content: space-between;
align-items: center;
.miniplayer .bsdn-player {
max-height: 150px;
}
.miniplayer .miniplayer-head b {
color: white;
.miniplayer .fplayer {
max-width: 286px;
margin-left: 6px;
margin-top: 10px;
}
.miniplayer-actions {
float: right;
margin-right: 8px;
margin-top: 4px;
}
.miniplayer-name {
color: #8a8a8a;
font-size: 14px;
margin-left: 7px;
margin-top: -6px;
font-weight: bolder;
user-select: none;
}
.miniplayer .miniplayer-head .miniplayer-head-buttons {
display: flex;
align-items: center;
gap: 4px;
.ui-draggable {
position:fixed !important;
}
.miniplayer .miniplayer-head .miniplayer-head-buttons div {
width: 16px;
height: 16px;
background: url(/assets/packages/static/openvk/img/wall.png) no-repeat 1px 0;
background-repeat: no-repeat;
opacity: 0.5;
.miniplayer-actions img {
max-width: 11px;
cursor: pointer;
transition: opacity 200ms ease-in-out;
opacity: 70%;
}
.miniplayer .miniplayer-head .miniplayer-head-buttons div:hover {
opacity: 1;
.miniplayer .fplayer iframe {
max-width: 260px;
max-height: 160px;
}
.miniplayer .miniplayer-head .miniplayer-head-buttons #__miniplayer_return {
background-position: -28px 0px;
.miniplayer-actions img:hover {
opacity: 100%;
}
.miniplayer .miniplayer-head .miniplayer-head-buttons #__miniplayer_close {
background-position: -12px 0px;
#vidComments {
margin-top: 10px;
}
.miniplayer .miniplayer-head-buttons {
height: 20px;
.showMoreComments {
background: #eaeaea;
cursor: pointer;
text-align: center;
padding: 10px;
user-select: none;
margin-top: 10px;
}
.miniplayer .miniplayer-body {
height: 100%;
.loader {
display: none;
position: fixed;
top: -10%;
background: rgba(26, 26, 26, 0.9);;
padding-top: 12px;
width: 91px;
height: 25px;
text-align: center;
border-radius: 1px;
margin: auto;
left: 0;
right: 0;
bottom: 0;
z-index: 5555;
}
.miniplayer .miniplayer-body .bsdn {
height: 100%;
.right-arrow, .left-arrow {
position: absolute;
cursor: pointer;
transition: all 200ms ease-in-out;
margin-left: -50px;
background: none;
height: 449px;
width: 57px;
user-select: none;
}
.miniplayer .miniplayer-body .bsdn .bsdn-player {
height: 100%;
.right-arrow img, .left-arrow img {
user-select: none;
opacity: 5%;
transition: all 200ms ease-in-out;
}
.miniplayer .miniplayer-body iframe {
width: 100%;
height: 100%;
.right-arrow:hover, .left-arrow:hover {
background: rgba(0, 0, 0, 0.5);
}
.right-arrow img:hover, .left-arrow img:hover {
opacity: 50%;
}

View file

@ -13,10 +13,6 @@ body {
word-wrap: break-word;
}
body, .ovk-fullscreen-dimmer, .ovk-photo-view-dimmer {
scrollbar-gutter: stable both-edges;
}
.nobold,
nobold {
font-weight: normal;
@ -45,16 +41,6 @@ h1 {
margin-top: 0;
}
.display_flex_column {
display: flex;
flex-direction: column;
}
.display_flex_row {
display: flex;
flex-direction: row;
}
.layout {
width: 791px;
margin: 0 auto;
@ -268,28 +254,6 @@ h1 {
width: calc(550px - 16px - 38px - 171px);
}
.upLeftErrors {
position: fixed;
display: flex;
flex-direction: column;
z-index: 1025;
}
.upLeftErrors .upLeftError {
padding: 2px 2px 2px 2px;
display: inline-block;
border-radius: 0px 0px 5px 0px;
font-size: 15px;
}
.upLeftErrors .upLeftError.upLeftErrorRed {
background: #ff7474;
}
.upLeftErrors .upLeftError.upLeftErrorGreen {
background: #74ff92;
}
.page_body {
width: 632px;
float: right;
@ -657,16 +621,6 @@ input[type=checkbox]:checked:disabled {
background-position: 0 -42px;
}
input[type="number"] {
border: 1px solid #C0CAD5;
padding: 3px;
font-size: 11px;
font-family: tahoma, verdana, arial, sans-serif;
width: 100%;
box-sizing: border-box;
outline: none;
}
#auth {
padding: 10px;
}
@ -808,14 +762,6 @@ h4 {
font-size: 9px;
}
.editing .post-content, .post-edit {
display: none;
}
.editing .post-edit {
display: block;
}
.post-content .text {
padding: 4px;
font-size: 11px;
@ -1533,7 +1479,7 @@ body.scrolled .toTop:hover, .toTop.has_down:hover {
color: #3c3c3c;
}
.post-source #remove_source_button, #small_remove_button {
.post-source #remove_source_button {
display: inline-block;
background-repeat: no-repeat;
background: url('/assets/packages/static/openvk/img/arrows.png?v=2');
@ -1547,7 +1493,7 @@ body.scrolled .toTop:hover, .toTop.has_down:hover {
cursor: pointer;
}
.post-source #remove_source_button:hover, #small_remove_button:hover {
.post-source #remove_source_button:hover {
opacity: 0.8;
}
@ -1617,15 +1563,6 @@ body.scrolled .toTop:hover, .toTop.has_down:hover {
float: right;
}
.like_wrap.tidy {
float: none;
display: inline-block;
}
.like_wrap.tidy .post-like-button {
display: flex;
}
.heart {
background: url('/assets/packages/static/openvk/img/like.gif') no-repeat 1px 0;
height: 10px;
@ -1635,22 +1572,12 @@ body.scrolled .toTop:hover, .toTop.has_down:hover {
opacity: 0.4;
}
.like_wrap.tidy .heart {
float: none;
display: inline-block;
}
.likeCnt {
font-size: 10px;
margin-right: 3px;
float: left;
}
.like_wrap.tidy .likeCnt {
float: none;
display: inline;
}
.heart:hover {
opacity: 1 !important;
}
@ -1814,14 +1741,12 @@ body.scrolled .toTop:hover, .toTop.has_down:hover {
#wallAttachmentMenu {
position: absolute;
min-width: 94px;
border: 1px solid darkgrey;
background-color: white;
z-index: 32;
margin-top: -7px;
margin-left: -16px;
box-shadow: 0 1px 3px -1px;
user-select: none;
}
#wallAttachmentMenu>a {
@ -2220,10 +2145,6 @@ table td[width="120"] {
border-radius: 2px;
}
.mb_tab:hover {
background: #e2e0e0;
}
.mb_tab div, .mb_tab > a {
padding: 5px 9px;
display: block;
@ -2479,66 +2400,26 @@ a.poll-retract-vote {
}
}
.post-horizontal, .post-vertical {
margin-top: 0px;
.upload {
margin-top: 8px;
}
.post-horizontal {
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 3px;
}
.post-vertical {
display: flex;
flex-direction: column;
flex-wrap: wrap;
gap: 3px;
}
.post-horizontal .upload-item {
/*width: 75px;
height: 60px;*/
.upload .upload-item {
width: 75px;
height: 60px;
overflow: hidden;
display: inline-flex;
justify-content: center;
align-items: center;
position: relative;
min-height: 63px;
}
.post-horizontal .upload-item .play-button, .compact_video .play-button {
position: absolute;
height: 30px;
width: 30px;
background: rgba(0, 0, 0, 0.8);
display: flex;
justify-content: center;
align-items: center;
}
.post-horizontal .upload-item .play-button .play-button-ico, .compact_video .play-button .play-button-ico {
background: url(/assets/packages/static/openvk/img/wall.png) no-repeat 1px 0;
display: inline-block;
height: 15px;
width: 12px;
margin-right: 3px;
}
.upload-item.dragged {
filter: contrast(0.5);
}
.post-horizontal .upload-item .upload-delete {
.upload-item .upload-delete {
position: absolute;
background: rgba(0,0,0,0.5);
padding: 2px 5px;
text-decoration: none;
color: #fff;
font-size: 11px;
right: 0px;
top: 0px;
margin-left: 57px; /* мне лень переделывать :DDDD */
opacity: 0;
transition: 0.25s;
}
@ -2547,68 +2428,13 @@ a.poll-retract-vote {
opacity: 1;
}
.post-horizontal .upload-item img {
.upload-item img {
width: 100%;
max-height: 60px;
object-fit: cover;
border-radius: 3px;
}
.post-vertical .vertical-attachment {
display: grid;
grid-template-columns: 1fr 0fr;
}
.post-vertical .vertical-attachment:first-of-type {
margin-top: 7px;
}
.post-vertical .vertical-attachment .audioEntry {
max-height: 28px;
min-height: 18px;
}
.post-vertical .vertical-attachment .audioEntry:hover {
background: unset !important;
}
.post-vertical .vertical-attachment .audioEntry .playerButton {
padding: 0px 3px 0px 0px;
}
.post-vertical .vertical-attachment .audioEntry .buttons {
display: none;
}
.post-vertical .vertical-attachment .audioEntry .status {
margin-top: 1px;
margin-left: 2px;
height: 15px;
}
.post-vertical .vertical-attachment .audioEntry .nobold {
margin-top: 1px;
}
.post-vertical .vertical-attachment .audioEntry .subTracks {
padding-bottom: 2px;
padding-left: 3px;
padding-right: 0px;
}
.post-vertical .vertical-attachment .audioEntry .audioEntryWrapper {
height: 18px;
}
.post-vertical .vertical-attachment .vertical-attachment-content {
max-height: 27px;
}
.post-vertical .vertical-attachment .vertical-attachment-content .overflowedName {
position: initial;
width: 100% !important;
}
/* https://imgur.com/a/ihB3JZ4 */
.ovk-photo-view-dimmer {
@ -2626,33 +2452,21 @@ a.poll-retract-vote {
position: relative;
z-index: 999;
background: #fff;
min-width: 600px;
width: fit-content;
padding: 25px;
width: 610px;
padding: 20px;
padding-top: 15px;
padding-bottom: 10px;
box-shadow: 0px 0px 3px 1px #222;
margin: 10px auto 0 auto;
margin: 15px auto 0 auto;
}
.ovk-photo-view .photo_viewer_wrapper {
position: relative;
height: 80vh;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.ovk-photo-view #ovk-photo-img {
max-width: 100%;
max-height: 80vh;
user-select: none;
.ovk-photo-details {
overflow: auto;
}
.photo_com_title {
font-weight: bold;
padding-bottom: 16px;
padding-bottom: 20px;
}
.photo_com_title div {
@ -2664,6 +2478,7 @@ a.poll-retract-vote {
left: 0;
width: 35%;
height: 100%;
max-height: 60vh;
position: absolute;
cursor: pointer;
}
@ -2672,27 +2487,11 @@ a.poll-retract-vote {
right: 0;
width: 35%;
height: 100%;
max-height: 60vh;
position: absolute;
cursor: pointer;
}
.ovk-photo-view .media-page-wrapper-details {
display: flex;
gap: 10px;
}
.ovk-photo-view .media-page-wrapper-comments {
overflow-y: auto;
overflow-x: hidden;
min-height: 300px;
width: 100%;
padding: 0px 2px;
}
.ovk-photo-view .ovk-photo-details {
margin-top: 10px;
}
.client_app > img {
top: 3px;
position: relative;
@ -2750,13 +2549,12 @@ a.poll-retract-vote {
padding: 3px 0;
}
.video-wowzer .small-video-ico {
vertical-align: bottom;
display: inline-block;
width: 11px;
height: 14px;
background: url(/assets/packages/static/openvk/img/wall.png?v=2);
background-position: -87px 0px;
.video-wowzer a::before {
content: "b";
color: transparent;
width: 12px;
background-image: url(/assets/packages/static/openvk/img/videoico.png);
display: none;
}
/* Da search */
@ -3102,33 +2900,17 @@ a.poll-retract-vote {
width: 100%;
}
.attachment_note .attachment_note_icon {
.attachment_note_icon {
max-width: 9px;
}
.attachment_note .attachment_note_text {
.attachment_note_text {
color: #605F63;
margin-left: 2px;
}
.attachment_note {
user-select: none;
display: flex;
align-items: center;
gap: 1px;
}
.attachment_note svg {
width: 8px;
height: 10px;
fill: #605f63;
margin-top: 2px;
}
.attachment_note .attachment_note_content {
display: flex;
gap: 4px;
height: 12px;
}
#notesList
@ -3353,81 +3135,10 @@ body.article .floating_sidebar, body.article .page_content {
font-size: 11px;
}
.attachment_selector .topGrayBlock {
.topGrayBlock {
background: #F0F0F0;
height: 37px;
border-bottom: 1px solid #C7C7C7;
padding: 3px 10px;
align-items: center;
justify-content: center;
justify-content: space-between;
}
.attachment_selector .topGrayBlock #video_query {
width: 160px;
}
.attachment_selector .topGrayBlock #albumSelect {
width: 150px;
}
.attachment_selector #attachment_insert {
padding: 5px;
height: 281px;
overflow-y: scroll;
}
.attachment_selector #attachment_insert #attachment_insert_count {
position: fixed;
z-index: 1007;
width: 92%;
background: white;
margin-top: -5px;
padding-top: 6px;
}
#show_more {
width: 100%;
text-align: center;
background: #f0f0f0;
height: 22px;
padding-top: 9px;
cursor: pointer;
margin-top: 4px;
}
#show_more:hover {
background: #f2f2f2;
}
.attachment_selector #attachment_insert .photosList {
margin-top: 20px;
gap: 3px 6px;
}
.attachment_selector #attachment_insert .photosList .album-photo.selected img {
background-color: #646464;
}
.attachment_selector #attachment_insert .photosList .album-photo {
width: 15.8%;
margin: unset;
}
.attachment_selector #attachment_insert .videosInsert .video_list .video-preview {
height: 75px;
width: 133px;
overflow: hidden;
}
.attachment_selector #attachment_insert .videosInsert .video_list .video-preview img {
max-width: 133px;
height: 75px;
margin: auto;
}
.attachment_selector #attachment_insert .videosInsert .video_list .action_links {
width: 150px;
}
.edited {
@ -3445,20 +3156,16 @@ body.article .floating_sidebar, body.article .page_content {
user-select: none;
}
.edit_menu.loading {
.editMenu.loading {
filter: opacity(0.5);
cursor: progress;
user-select: none;
}
.edit_menu.loading * {
.editMenu.loading * {
pointer-events: none;
}
.edit_menu .edit_menu_buttons {
margin-top: 10px;
}
.lagged *, .lagged {
pointer-events: none;
}
@ -3581,7 +3288,6 @@ hr {
flex-direction: row;
justify-content: space-between;
gap: 4px;
cursor: pointer;
}
.entity_vertical_list .entity_vertical_list_item .first_column {
@ -3619,167 +3325,3 @@ hr {
width: 30px;
height: 7px;
}
.compact_video {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
height: 100%;
width: 100%;
position: relative;
margin-left: -2px;
margin-top: -2px;
}
.compact_video .video-length {
text-align: center;
position: absolute;
width: 34px;
height: 14px;
bottom: 5px;
right: 5px;
background: rgba(0,0,0,0.5);
color: white;
}
.media-page-wrapper .photo-page-wrapper-photo {
margin-bottom: 8pt;
text-align: center;
}
.media-page-wrapper .video-page-wrapper-video iframe {
width: 100%;
}
.media-page-wrapper .photo-page-wrapper-photo img {
max-width: 85%;
max-height: 60vh;
}
.media-page-wrapper-details {
width: 100%;
min-height: 100px;
display: flex;
justify-content: space-between;
gap: 10px;
}
.media-page-wrapper-comments {
min-height: 100px;
width: 68%;
margin-left: 3px;
}
.media-page-wrapper-actions {
min-height: 100px;
width: 30%;
margin-left: 1px;
}
.media-page-wrapper-description p {
margin: 0px;
}
.media-page-wrapper-description .upload_time {
color: gray;
display: inline-flex;
align-items: center;
height: 16px;
}
.media-page-author-block {
display: flex;
align-items: center;
gap: 7px;
margin-bottom: 5px;
}
.media-page-author-block img {
width: 30px;
}
.media-page-author-block .media-page-author-block-name {
display: flex;
flex-direction: column;
justify-content: center;
}
.media-page-author-block .media-page-author-block-name b {
font-weight: bold;
}
.media-page-author-block .media-page-author-block-name span {
text-transform: lowercase;
}
#ajloader {
display: none;
position: fixed;
top: -10%;
background: rgba(26, 26, 26, 0.9);;
padding-top: 12px;
width: 91px;
height: 25px;
text-align: center;
border-radius: 1px;
margin: auto;
left: 0;
right: 0;
bottom: 0;
z-index: 5555;
}
#ajloader.shown {
display: block;
}
.hoverable_color {
transition: all 0.17s ease-in-out;
}
.hoverable_color:hover {
color: white !important;
}
#__feed_settings_link {
float: right;
margin-right: 3px;
margin-top: 2px;
}
#__feed_settings_link:hover {
text-decoration: underline;
}
#_feed_settings_container {
height: 100%;
}
#_feed_settings_container #__content {
display: flex;
flex-direction: column;
gap: 4px;
padding: 5px;
height: 100%;
}
#_feed_settings_container #__content .settings_item {
display: flex;
flex-direction: column;
}
#_feed_settings_container #__content .final_settings_item {
align-self: end;
margin-top: 74px;
}
#_feed_settings_container #pageNumber {
width: 70px;
}
#_feed_settings_container .entity_vertical_list {
height: 206px;
overflow-x: hidden;
}

View file

@ -1,28 +1,28 @@
.post-nsfw .post-content {
position: relative;
.post-nsfw .post-content .media {
filter: saturate(0.8) blur(15px);
}
.post-nsfw .post-content .attachment {
overflow: hidden;
cursor: pointer;
position: relative;
}
.post-nsfw .post-content .text {
filter: saturate(0.8) blur(28px);
pointer-events: none;
.post-nsfw .post-content .attachment:active .media {
filter: none;
}
.post-nsfw .post-content::after {
.post-nsfw .post-content .attachment::after {
position: absolute;
top: 0;
top: calc(50% - 16px);
left: 0;
width: 100%;
height: 100%;
z-index: 1;
background-color: hsla(0, 0%, 0%, .7);
padding: 8px 0;
background-color: hsla(0, 0%, 0%, .5);
color: #fff;
text-align: center;
content: attr(data-localized-nsfw-text);
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.post-nsfw .post-content .attachment:active::after {
display: none;
}

BIN
Web/static/img/audio.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 932 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 932 B

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Web/static/img/left_arr.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 B

1
Web/static/img/note.svg Normal file
View file

@ -0,0 +1 @@
<svg id="note" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 35 40"><defs><style>.cls-1{fill:#a0a0a0;}</style></defs><title>note</title><polygon class="cls-1" points="0 0 0 40 35 40 35 20 17.5 20 17.5 0 0 0"/><polygon id="block" class="cls-1" points="20.26 1 35 18 20.26 18 20.26 1"/></svg>

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
Web/static/img/video.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 510 B

BIN
Web/static/img/videoico.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -34,22 +34,4 @@ window.API = new Proxy(Object.create(null), {
window.API.Types = {};
window.API.Types.Message = (class Message {
});
window.OVKAPI = new class {
async call(method, params) {
if(!method) {
return
}
const url = `/method/${method}?auth_mechanism=roaming&${new URLSearchParams(params).toString()}&v=5.200`
const res = await fetch(url)
const json_response = await res.json()
if(json_response.response) {
return json_response.response
} else {
throw new Error(json_response.error_msg)
}
}
}
});

View file

@ -8,8 +8,6 @@ u(document).on("click", ".comment-reply", function(e) {
let mention = ("[" + (fromGroup ? "club" : "id") + authorId + "|" + authorNm + "], ");
// Substitute pervious mention if present, prepend otherwise
inputbox.nodes.forEach(node => {
node.value = node.value.replace(/(^\[([A-Za-z0-9]+)\|([\p{L} 0-9@]+)\], |^)/u, mention);
})
inputbox.nodes[0].value = inputbox.nodes[0].value.replace(/(^\[([A-Za-z0-9]+)\|([\p{L} 0-9@]+)\], |^)/u, mention);
inputbox.trigger("focusin");
});

View file

@ -1,285 +0,0 @@
//u('.postFeedPageSelect').attr('style', 'display:none')
// Source ignoring
u(document).on("click", "#__ignoreSomeone", async (e) => {
e.preventDefault()
const TARGET = u(e.target)
const ENTITY_ID = Number(e.target.dataset.id)
const VAL = Number(e.target.dataset.val)
const ACT = VAL == 1 ? 'ignore' : 'unignore'
const METHOD_NAME = ACT == 'ignore' ? 'addBan' : 'deleteBan'
const PARAM_NAME = ENTITY_ID < 0 ? 'group_ids' : 'user_ids'
const ENTITY_NAME = ENTITY_ID < 0 ? 'club' : 'user'
const URL = `/method/newsfeed.${METHOD_NAME}?auth_mechanism=roaming&${PARAM_NAME}=${Math.abs(ENTITY_ID)}`
TARGET.addClass('lagged')
const REQ = await fetch(URL)
const RES = await REQ.json()
TARGET.removeClass('lagged')
if(RES.error_code) {
switch(RES.error_code) {
case -10:
fastError(';/')
break
case -50:
fastError(tr('ignored_sources_limit'))
break
default:
fastError(res.error_msg)
break
}
return
}
if(RES.response == 1) {
if(ACT == 'unignore') {
TARGET.attr('data-val', '1')
TARGET.html(tr(`ignore_${ENTITY_NAME}`))
} else {
TARGET.attr('data-val', '0')
TARGET.html(tr(`unignore_${ENTITY_NAME}`))
}
}
})
u(document).on('click', '#__feed_settings_link', (e) => {
e.preventDefault()
let current_tab = 'main';
const body = `
<div id='_feed_settings_container'>
<div id='_tabs'>
<div class="mb_tabs">
<div class="mb_tab" data-name='main'>
<a>
${tr('main')}
</a>
</div>
<div class="mb_tab" data-name='ignored'>
<a>
${tr('ignored_sources')}
</a>
</div>
</div>
</div>
<div id='__content'></div>
</div>
`
MessageBox(tr("feed_settings"), body, [tr("close")], [Function.noop])
u('.ovk-diag-body').attr('style', 'padding:0px;height: 255px;')
async function __switchTab(tab)
{
current_tab = tab
u(`#_feed_settings_container .mb_tab`).attr('id', 'ki')
u(`#_feed_settings_container .mb_tab[data-name='${tab}']`).attr('id', 'active')
u(`#_feed_settings_container .mb_tabs input`).remove()
switch(current_tab) {
case 'main':
const __temp_url = new URL(location.href)
const PAGES_COUNT = Number(e.target.dataset.pagescount ?? '10')
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 COUNT = [1, 5, 10, 20, 30, 40, 50]
u('#_feed_settings_container #__content').html(`
<table cellspacing="7" cellpadding="0" border="0" align="center">
<tbody>
<tr>
<td width="120" valign="top">
<span class="nobold">${tr('posts_per_page')}</span>
</td>
<td>
<select id="pageSelect"></select>
</td>
</tr>
<tr>
<td width="120" valign="top">
<span class="nobold">${tr('start_from_page')}</span>
</td>
<td>
<input type='number' min='1' max='${PAGES_COUNT}' id='pageNumber' value='${CURRENT_PAGE}' placeholder='${CURRENT_PAGE}'>
</td>
</tr>
<tr>
<td width="120" valign="top">
<span class="nobold">
<input type='checkbox' name='showIgnored' id="showIgnored" ${CURRENT_RETURN_BANNED == 1 ? 'checked' : ''}>
</span>
</td>
<td>
<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' 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>
<td>
<input class='button' type='button' value='${tr('apply')}'>
</td>
</tr>
</tbody>
</table>
`)
u(`#_feed_settings_container #__content input[type='button']`).on('click', (e) => {
const INPUT_PAGES_COUNT = parseInt(u('#_feed_settings_container #__content #pageSelect').nodes[0].selectedOptions[0].value ?? '10')
const INPUT_PAGE = parseInt(u('#_feed_settings_container #__content #pageNumber').nodes[0].value ?? '1')
const INPUT_IGNORED = Number(u('#_feed_settings_container #__content #showIgnored').nodes[0].checked ?? false)
const FINAL_URL = new URL(location.href)
if(CURRENT_PERPAGE != INPUT_PAGES_COUNT) {
FINAL_URL.searchParams.set('posts', INPUT_PAGES_COUNT)
}
if(CURRENT_PAGE != INPUT_PAGE && INPUT_PAGE <= PAGES_COUNT) {
FINAL_URL.searchParams.set('p', Math.max(1, INPUT_PAGE))
}
if(INPUT_IGNORED == 1) {
FINAL_URL.searchParams.set('return_banned', 1)
} else {
FINAL_URL.searchParams.delete('return_banned')
}
window.location.assign(FINAL_URL.href)
})
COUNT.forEach(item => {
u('#_feed_settings_container #pageSelect').append(`
<option value="${item}" ${item == CURRENT_PERPAGE ? 'selected' : ''}>${item}</option>
`)
})
break
case 'ignored':
u('#_feed_settings_container #__content').html(`
<div id='gif_loader'></div>
`)
if(!window.openvk.ignored_list) {
const IGNORED_RES = await fetch('/method/newsfeed.getBanned?auth_mechanism=roaming&extended=1&fields=real_id,screen_name,photo_50&merge=1')
const IGNORED_LIST = await IGNORED_RES.json()
window.openvk.ignored_list = IGNORED_LIST
}
u('#_feed_settings_container #__content').html(`
<div class='entity_vertical_list mini'></div>
`)
u('#_feed_settings_container .mb_tabs').append(`
<input class='button lagged' id='_remove_ignores' type='button' value='${tr('stop_ignore')}'>
`)
if(window.openvk.ignored_list.error_code) {
fastError(IGNORED_LIST.error_msg)
return
}
if(window.openvk.ignored_list.response.items.length < 1) {
u('#_feed_settings_container #__content').html(`
<div class="information">
${tr('no_ignores_count')}
</div>`)
u('#_remove_ignores').remove()
}
window.openvk.ignored_list.response.items.forEach(ignore_item => {
let name = ignore_item.name
if(!name) {
name = ignore_item.first_name + ' ' + ignore_item.last_name
}
u('#_feed_settings_container #__content .entity_vertical_list').append(`
<label class='entity_vertical_list_item with_third_column' data-id='${ignore_item.real_id}'>
<div class='first_column'>
<a href='/${ignore_item.screen_name}' class='avatar'>
<img src='${ignore_item.photo_50}'>
</a>
<div class='info'>
<b class='noOverflow'>
<a href="/${ignore_item.screen_name}">
${ovk_proc_strtr(escapeHtml(name), 100)}
</a>
</b>
</div>
</div>
<div class='third_column' style="display: grid; align-items: center;">
<input type='checkbox' name='remove_me'>
</div>
</label>
`)
})
u("#_feed_settings_container").on("click", "input[name='remove_me']", async (e) => {
const checks_count = u(`input[name='remove_me']:checked`).length
if(checks_count > 0) {
u('.mb_tabs #_remove_ignores').removeClass('lagged')
} else {
u('.mb_tabs #_remove_ignores').addClass('lagged')
}
if(checks_count > 10) {
e.preventDefault()
}
})
u('#_feed_settings_container').on('click', '#_remove_ignores', async (e) => {
e.target.classList.add('lagged')
const ids = []
u('#__content .entity_vertical_list label').nodes.forEach(item => {
const _checkbox = item.querySelector(`input[type='checkbox'][name='remove_me']`)
if(_checkbox.checked) {
ids.push(item.dataset.id)
}
})
const user_ids = []
const group_ids = []
ids.forEach(id => {
id > 0 ? user_ids.push(id) : group_ids.push(Math.abs(id))
})
const res = await fetch(`/method/newsfeed.deleteBan?auth_mechanism=roaming&user_ids=${user_ids.join(',')}&group_ids=${group_ids.join(',')}`)
const resp = await res.json()
if(resp.error_code) {
console.error(resp.error_msg)
return
}
window.openvk.ignored_list = null
__switchTab('ignored')
})
break
}
}
u("#_feed_settings_container").on("click", ".mb_tab a", async (e) => {
await __switchTab(u(e.target).closest('.mb_tab').attr('data-name'))
})
__switchTab('main')
})
u(document).on('change', `input[data-act='localstorage_item']`, (e) => {
localStorage.setItem(e.target.name, Number(e.target.checked))
})

View file

@ -19,8 +19,7 @@ var tooltipTemplate = Handlebars.compile(`
</table>
`);
tippy.delegate("body", {
target: '.mention',
tippy(".mention", {
theme: "light vk",
content: "⌛",
allowHTML: true,

View file

@ -1,3 +1,13 @@
function fmtTime(time) {
const mins = String(Math.floor(time / 60)).padStart(2, '0');
const secs = String(Math.floor(time % 60)).padStart(2, '0');
return `${ mins}:${ secs}`;
}
function fastError(message) {
MessageBox(tr("error"), message, [tr("ok")], [Function.noop])
}
// elapsed это вроде прошедшие, а оставшееся это remaining но ладно уже
function getElapsedTime(fullTime, time) {
let timer = fullTime - time
@ -1344,8 +1354,8 @@ $(document).on("click", "#_deletePlaylist", (e) => {
}, Function.noop])
})
$(document).on("click", "#__audioAttachment", (e) => {
const form = e.target.closest("form")
$(document).on("click", "#_audioAttachment", (e) => {
let form = e.currentTarget.closest("form")
let body = `
<div class="searchBox">
<input name="query" type="text" maxlength="50" placeholder="${tr("header_search")}">
@ -1357,7 +1367,7 @@ $(document).on("click", "#__audioAttachment", (e) => {
<div class="audiosInsert"></div>
`
MessageBox(tr("select_audio"), body, [tr("close")], [Function.noop])
MessageBox(tr("select_audio"), body, [tr("ok")], [Function.noop])
document.querySelector(".ovk-diag-body").style.padding = "0"
document.querySelector(".ovk-diag-cont").style.width = "580px"
@ -1378,24 +1388,23 @@ $(document).on("click", "#__audioAttachment", (e) => {
result.querySelectorAll(".audioEmbed").forEach(el => {
let id = el.dataset.prettyid
const is_attached = (u(form).find(`.post-vertical .vertical-attachment[data-id='${id}']`)).length > 0
let name = el.dataset.name
let isAttached = (form.querySelector("input[name='audios']").value.includes(`${id},`))
document.querySelector(".audiosInsert").insertAdjacentHTML("beforeend", `
<div class='audio_attachment_header' style="display: flex;width: 100%;">
<div class='player_part' style="width: 72%;">${el.outerHTML}</div>
<div class="attachAudio" data-attachmentdata="${id}">
<span>${is_attached ? tr("detach_audio") : tr("attach_audio")}</span>
<div style="display: table;width: 100%;clear: both;">
<div style="width: 72%;float: left;">${el.outerHTML}</div>
<div class="attachAudio" data-attachmentdata="${id}" data-name="${name}">
<span>${isAttached ? tr("detach_audio") : tr("attach_audio")}</span>
</div>
</div>
`)
})
u("#loader").remove()
u('#show_more').remove()
if(thisc.page < pagesCount) {
document.querySelector(".audiosInsert").insertAdjacentHTML("beforeend", `
<div id="show_more" data-pagesCount="${pagesCount}" data-page="${thisc.page + 1}" class="showMore">
<div id="showMoreAudios" data-pagesCount="${pagesCount}" data-page="${thisc.page + 1}" class="showMore">
<span>${tr("show_more_audios")}</span>
</div>`)
}
@ -1415,12 +1424,14 @@ $(document).on("click", "#__audioAttachment", (e) => {
searcher.movePage(1)
u(".audiosInsert").on("click", "#show_more", async (e) => {
u(e.target).closest('#show_more').addClass('lagged')
$(".audiosInsert").on("click", "#showMoreAudios", (e) => {
u(e.currentTarget).remove()
searcher.movePage(Number(e.currentTarget.dataset.page))
})
$(".searchBox input").on("change", async (e) => {
await new Promise(r => setTimeout(r, 500));
if(e.currentTarget.value === document.querySelector(".searchBox input").value) {
searcher.clearContainer()
@ -1451,34 +1462,44 @@ $(document).on("click", "#__audioAttachment", (e) => {
return;
})
u(".audiosInsert").on("click", ".attachAudio", (ev) => {
const id = ev.currentTarget.dataset.attachmentdata
const is_attached = u(form).find(`.post-vertical .vertical-attachment[data-id='${id}']`).length > 0
function insertAttachment(id) {
let audios = form.querySelector("input[name='audios']")
// 04.11.2024 19:03
if(is_attached) {
u(form).find(`.post-vertical .vertical-attachment[data-id='${id}']`).remove()
u(ev.currentTarget).find("span").html(tr("attach_audio"))
} else {
if(u(form).find(`.upload-item`).length > window.openvk.max_attachments) {
makeError(tr('too_many_attachments'), 'Red', 10000, 1)
return
if(!audios.value.includes(id + ",")) {
if(audios.value.split(",").length > 10) {
NewNotification(tr("error"), tr("max_attached_audios"))
return false
}
u(ev.currentTarget).find("span").html(tr("detach_audio"))
form.querySelector("input[name='audios']").value += (id + ",")
const header = u(ev.currentTarget).closest('.audio_attachment_header')
const player = header.find('.player_part')
u(form).find(".post-vertical").append(`
<div class="vertical-attachment upload-item" data-type='audio' data-id="${ev.currentTarget.dataset.attachmentdata}">
<div class='vertical-attachment-content'>
${player.html()}
</div>
<div class='vertical-attachment-remove'>
<div id='small_remove_button'></div>
</div>
return true
} else {
form.querySelector("input[name='audios']").value = form.querySelector("input[name='audios']").value.replace(id + ",", "")
return false
}
}
$(".audiosInsert").on("click", ".attachAudio", (ev) => {
if(!insertAttachment(ev.currentTarget.dataset.attachmentdata)) {
u(`.post-has-audios .post-has-audio[data-id='${ev.currentTarget.dataset.attachmentdata}']`).remove()
ev.currentTarget.querySelector("span").innerHTML = tr("attach_audio")
} else {
ev.currentTarget.querySelector("span").innerHTML = tr("detach_audio")
form.querySelector(".post-has-audios").insertAdjacentHTML("beforeend", `
<div class="post-has-audio" id="unattachAudio" data-id="${ev.currentTarget.dataset.attachmentdata}">
<span>${ovk_proc_strtr(escapeHtml(ev.currentTarget.dataset.name), 40)}</span>
</div>
`)
u(`#unattachAudio[data-id='${ev.currentTarget.dataset.attachmentdata}']`).on("click", (e) => {
let id = ev.currentTarget.dataset.attachmentdata
form.querySelector("input[name='audios']").value = form.querySelector("input[name='audios']").value.replace(id + ",", "")
u(e.currentTarget).remove()
})
}
})
})
@ -1488,13 +1509,7 @@ $(document).on("click", ".audioEmbed.processed .playerButton", (e) => {
})
$(document).on("click", ".audioEmbed.withdrawn", (e) => {
const msg = new CMessageBox({
title: tr('error'),
body: tr('audio_embed_withdrawn'),
unique_name: 'withdrawn_notify',
buttons: [tr('ok')],
callbacks: [Function.noop]
})
MessageBox(tr("error"), tr("audio_embed_withdrawn"), [tr("ok")], [Function.noop])
})
$(document).on("click", ".musicIcon.report-icon", (e) => {

View file

@ -64,9 +64,8 @@ function pollRadioPressed(radio) {
form.submit();
}
function initPoll(event) {
let form = $(event.target.closest('.post-buttons')).parent();
const id = random_int(0, 100)
function initPoll(id) {
let form = $(`#wall-post-input${id}`).parent();
let mBody = `
<div id="poll_editor${id}">
@ -88,9 +87,9 @@ function initPoll(event) {
</div>
`;
const msg = MessageBox(tr("create_poll"), mBody, [tr("attach"), tr("cancel")], [
MessageBox(tr("create_poll"), mBody, [tr("attach"), tr("cancel")], [
function() {
let dialog = $(msg.getNode().nodes[0]);
let dialog = $(this.$dialog().nodes[0]);
$("input", dialog).unbind();
let title = $("input[name=title]", dialog).val();
@ -118,9 +117,9 @@ function initPoll(event) {
$(".post-has-poll", form).show();
},
function() {
$("input", $(msg.getNode())).unbind();
$("input", $(this.$dialog().nodes[0])).unbind();
}
], true);
]);
let editor = $(`#poll_editor${id}`);
$("input[name=newOption]", editor).bind("focus", function() {

File diff suppressed because it is too large Load diff

View file

@ -1,177 +1,42 @@
Function.noop = () => {};
class CMessageBox {
constructor(options = {}) {
const title = options.title ?? 'Untitled'
const body = options.body ?? '<hr>'
const buttons = options.buttons ?? []
const callbacks = options.callbacks ?? []
const close_on_buttons = options.close_on_buttons ?? true
const unique_name = options.unique_name ?? null
const warn_on_exit = options.warn_on_exit ?? false
const custom_template = options.custom_template ?? null
if(unique_name && window.messagebox_stack.find(item => item.unique_name == unique_name) != null) {
return
}
this.title = title
this.body = body
this.id = random_int(0, 10000)
this.close_on_buttons = close_on_buttons
this.unique_name = unique_name
this.warn_on_exit = warn_on_exit
if(!custom_template) {
u('body').addClass('dimmed').append(this.__getTemplate())
} else {
custom_template.addClass('ovk-msg-all')
custom_template.attr('data-id', this.id)
u('body').addClass('dimmed').append(custom_template)
}
function MessageBox(title, body, buttons, callbacks) {
if(u(".ovk-diag-cont").length > 0) return false;
document.querySelector("html").style.overflowY = "hidden"
let dialog = u(
`<div class="ovk-diag-cont">
<div class="ovk-diag">
<div class="ovk-diag-head">${title}</div>
<div class="ovk-diag-body">${body}</div>
<div class="ovk-diag-action"></div>
</div>
</div>`);
u("body").addClass("dimmed").append(dialog);
buttons.forEach((text, callback) => {
u(".ovk-diag-action").append(u(`<button class="button">${text}</button>`));
let button = u(u(".ovk-diag-action > button.button").last());
u('html').attr('style', 'overflow-y:hidden')
buttons.forEach((text, callback) => {
this.getNode().find('.ovk-diag-action').append(u(`<button class="button">${text}</button>`))
let button = u(this.getNode().find('.ovk-diag-action > button.button').last())
button.on("click", (e) => {
callbacks[callback]()
if(close_on_buttons) {
this.close()
button.on("click", function(e) {
let __closeDialog = () => {
if(document.querySelector(".ovk-photo-view-dimmer") == null && document.querySelector(".ovk-fullscreen-player") == null) {
u("body").removeClass("dimmed");
document.querySelector("html").style.overflowY = "scroll"
}
})
})
window.messagebox_stack.push(this)
}
__getTemplate() {
return u(
`<div class="ovk-diag-cont ovk-msg-all" data-id="${this.id}">
<div class="ovk-diag">
<div class="ovk-diag-head">${this.title}</div>
<div class="ovk-diag-body">${this.body}</div>
<div class="ovk-diag-action"></div>
</div>
</div>`)
}
getNode() {
return u(`.ovk-msg-all[data-id='${this.id}']`)
}
async __showCloseConfirmationDialog() {
return new Promise((resolve, reject) => {
const msg = new CMessageBox({
title: tr('exit_noun'),
body: tr('exit_confirmation'),
warn_on_exit: false,
unique_name: 'close_confirmation',
buttons: [tr('no'), tr('yes')],
callbacks: [() => {
msg.close()
resolve(false)
}, () => {
this.__exitDialog()
resolve(true)
}]
})
})
}
__exitDialog() {
this.getNode().remove()
if(u('.ovk-msg-all').length < 1) {
u('body').removeClass('dimmed')
u('html').attr('style', 'overflow-y:scroll')
}
const current_item = window.messagebox_stack.find(item => item.id == this.id)
const index_of_item = window.messagebox_stack.indexOf(current_item)
window.messagebox_stack = array_splice(window.messagebox_stack, index_of_item)
u(".ovk-diag-cont").remove();
};
Reflect.apply(callbacks[callback], {
closeDialog: () => __closeDialog(),
$dialog: () => u(".ovk-diag-cont")
}, [e]);
delete this
}
close() {
this.__exitDialog()
}
hide() {
u('body').removeClass('dimmed')
u('html').attr('style', 'overflow-y:scroll')
this.getNode().attr('style', 'display: none;')
}
reveal() {
u('body').addClass('dimmed')
u('html').attr('style', 'overflow-y:hidden')
this.getNode().attr('style', 'display: block;')
}
static toggleLoader() {
u('#ajloader').toggleClass('shown')
}
__closeDialog();
});
});
return u(".ovk-diag-cont");
}
window.messagebox_stack = []
function MessageBox(title, body, buttons, callbacks, return_msg = false) {
const msg = new CMessageBox({
title: title,
body: body,
buttons: buttons,
callbacks: callbacks,
})
if(return_msg) {
return msg
}
return msg.getNode()
}
// Close on 'Escape' key
u(document).on('keyup', async (e) => {
if(e.keyCode == 27 && window.messagebox_stack.length > 0) {
const msg = window.messagebox_stack[window.messagebox_stack.length - 1]
if(!msg) {
return
}
if(msg.close_on_buttons) {
msg.close()
return
}
if(msg.warn_on_exit) {
const res = await msg.__showCloseConfirmationDialog()
if(res === true) {
msg.close()
}
}
}
})
// Close when clicking on shadow
u(document).on('click', 'body.dimmed .dimmer', async (e) => {
if(u(e.target).hasClass('dimmer')) {
const msg = window.messagebox_stack[window.messagebox_stack.length - 1]
if(!msg) {
return
}
if(msg.close_on_buttons) {
msg.close()
return
}
if(msg.warn_on_exit) {
const res = await msg.__showCloseConfirmationDialog()
if(res === true) {
msg.close()
}
}
}
})

View file

@ -1,5 +1,9 @@
if(typeof u == 'undefined') {
console.error('!!! You forgot to install NPM packages !!!')

function expand_wall_textarea(id) {
var el = document.getElementById('post-buttons'+id);
var wi = document.getElementById('wall-post-input'+id);
el.style.display = "block";
wi.className = "expanded-textarea";
}
function expand_comment_textarea(id) {
@ -9,6 +13,19 @@ function expand_comment_textarea(id) {
wi.focus();
}
function edit_post(id, wid) {
var el = document.getElementById('text'+wid+'_'+id);
var ed = document.getElementById('text_edit'+wid+'_'+id);
if (el.style.display == "none") {
el.style.display = "block";
ed.style.display = "none";
} else {
el.style.display = "none";
ed.style.display = "block";
}
}
function hidePanel(panel, count = 0)
{
$(panel).toggleClass("content_title_expanded content_title_unexpanded");
@ -39,9 +56,19 @@ function parseAjaxResponse(responseString) {
}
}
function toggleMenu(id) {
if($(`#post-buttons${id} #wallAttachmentMenu`).is('.hidden')) {
$(`#post-buttons${id} #wallAttachmentMenu`).css({ opacity: 0 });
$(`#post-buttons${id} #wallAttachmentMenu`).toggleClass('hidden').fadeTo(250, 1);
} else {
$(`#post-buttons${id} #wallAttachmentMenu`).fadeTo(250, 0, function () {
$(this).toggleClass('hidden');
});
}
}
document.addEventListener("DOMContentLoaded", function() { //BEGIN
$(document).on("click", "#_photoDelete, #_videoDelete", function(e) {
$(document).on("click", "#_photoDelete", function(e) {
var formHtml = "<form id='tmpPhDelF' action='" + u(this).attr("href") + "' >";
formHtml += "<input type='hidden' name='hash' value='" + u("meta[name=csrf]").attr("value") + "' />";
formHtml += "</form>";
@ -159,6 +186,74 @@ document.addEventListener("DOMContentLoaded", function() { //BEGIN
})
}); //END ONREADY DECLS
async function repostPost(id, hash) {
uRepostMsgTxt = `
<b>${tr('auditory')}:</b> <br/>
<input type="radio" name="type" onchange="signs.setAttribute('hidden', 'hidden');document.getElementById('groupId').setAttribute('hidden', 'hidden')" value="wall" checked>${tr("in_wall")}<br/>
<input type="radio" name="type" onchange="signs.removeAttribute('hidden');document.getElementById('groupId').removeAttribute('hidden')" value="group" id="group">${tr("in_group")}<br/>
<select style="width:50%;" id="groupId" name="groupId" hidden>
</select><br/>
<b>${tr('your_comment')}:</b>
<textarea id='uRepostMsgInput_${id}'></textarea>
<div id="signs" hidden>
<label><input onchange="signed.checked ? signed.checked = false : null" type="checkbox" id="asgroup" name="asGroup">${tr('post_as_group')}</label><br>
<label><input onchange="asgroup.checked = true" type="checkbox" id="signed" name="signed">${tr('add_signature')}</label>
</div>
<br/><br/>`;
let clubs = [];
repostsCount = document.getElementById("repostsCount"+id)
prevVal = repostsCount != null ? Number(repostsCount.innerHTML) : 0;
MessageBox(tr('share'), uRepostMsgTxt, [tr('send'), tr('cancel')], [
(function() {
text = document.querySelector("#uRepostMsgInput_"+id).value;
type = "user";
radios = document.querySelectorAll('input[name="type"]')
for(const r of radios)
{
if(r.checked)
{
type = r.value;
break;
}
}
groupId = document.querySelector("#groupId").value;
asGroup = asgroup.checked == true ? 1 : 0;
signed = signed.checked == true ? 1 : 0;
hash = encodeURIComponent(hash);
xhr = new XMLHttpRequest();
xhr.open("POST", "/wall"+id+"/repost?hash="+hash, true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.onload = (function() {
if(xhr.responseText.indexOf("wall_owner") === -1)
MessageBox(tr('error'), tr('error_repost_fail'), [tr('ok')], [Function.noop]);
else {
let jsonR = JSON.parse(xhr.responseText);
NewNotification(tr('information_-1'), tr('shared_succ'), null, () => {window.location.href = "/wall" + jsonR.wall_owner});
repostsCount != null ?
repostsCount.innerHTML = prevVal+1 :
document.getElementById("reposts"+id).insertAdjacentHTML("beforeend", "(<b id='repostsCount"+id+"'>1</b>)") //для старого вида постов
}
});
xhr.send('text='+encodeURI(text) + '&type='+type + '&groupId='+groupId + "&asGroup="+asGroup + "&signed="+signed);
}),
Function.noop
]);
try
{
clubs = await API.Groups.getWriteableClubs();
for(const el of clubs) {
document.getElementById("groupId").insertAdjacentHTML("beforeend", `<option value="${el.id}">${escapeHtml(el.name)}</option>`)
}
} catch(rejection) {
console.error(rejection)
document.getElementById("group").setAttribute("disabled", "disabled")
}
}
function setClubAdminComment(clubId, adminId, hash) {
MessageBox("Изменить комментарий к администратору", `
<form action="/club${clubId}/setAdmin" method="post" id="uClubAdminCommentForm_${clubId}_${adminId}">
@ -224,6 +319,17 @@ function showCoinsTransferDialog(coinsCount, hash) {
]);
}
function chunkSubstr(string, size) {
const numChunks = Math.ceil(string.length / size);
const chunks = new Array(numChunks);
for (let i = 0, o = 0; i < numChunks; ++i, o += size) {
chunks[i] = string.substr(o, size);
}
return chunks;
}
function autoTab(original, next, previous) {
if(original.getAttribute && original.value.length == original.getAttribute("maxlength") && next !== undefined)
next.focus();
@ -255,6 +361,11 @@ function supportFastAnswerDialogOnClick(answer) {
answerInput.focus();
}
function ovk_proc_strtr(string, length = 0) {
const newString = string.substring(0, length);
return newString + (string !== newString ? "…" : "");
}
function showProfileDeactivateDialog(hash) {
MessageBox(tr("profile_deactivate"), `
<div class="messagebox-content-header">
@ -377,6 +488,57 @@ function showIncreaseRatingDialog(coinsCount, userUrl, hash) {
};
}
function escapeHtml(text) {
var map = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#039;'
};
return text.replace(/[&<>"']/g, function(m) { return map[m]; });
}
function highlightText(searchText, container_selector, selectors = []) {
const container = u(container_selector)
const regexp = new RegExp(`(${searchText})`, 'gi')
function highlightNode(node) {
if(node.nodeType == 3) {
let newNode = escapeHtml(node.nodeValue)
newNode = newNode.replace(regexp, (match, ...args) => {
return `<span class='highlight'>${escapeHtml(match)}</span>`
})
const tempDiv = document.createElement('div')
tempDiv.innerHTML = newNode
while(tempDiv.firstChild) {
node.parentNode.insertBefore(tempDiv.firstChild, node)
}
node.parentNode.removeChild(node)
} else if(node.nodeType === 1 && node.tagName !== 'SCRIPT' && node.tagName !== 'BR' && node.tagName !== 'STYLE' && !node.classList.contains('highlight')) {
Array.from(node.childNodes).forEach(highlightNode);
}
}
selectors.forEach(selector => {
elements = container.find(selector)
if(!elements || elements.length < 1) return;
elements.nodes.forEach(highlightNode)
})
}
String.prototype.escapeHtml = function() {
try {
return escapeHtml(this)
} catch(e) {
return ''
}
}
$(document).on("scroll", () => {
if($(document).scrollTop() > $(".sidebar").height() + 50) {
$(".floating_sidebar")[0].classList.add("show");

File diff suppressed because it is too large Load diff

View file

@ -1,175 +0,0 @@
function escapeHtml(text) {
var map = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#039;'
};
return text.replace(/[&<>"']/g, function(m) { return map[m]; });
}
function highlightText(searchText, container_selector, selectors = []) {
const container = u(container_selector)
const regexp = new RegExp(`(${searchText})`, 'gi')
function highlightNode(node) {
if(node.nodeType == 3) {
let newNode = escapeHtml(node.nodeValue)
newNode = newNode.replace(regexp, (match, ...args) => {
return `<span class='highlight'>${escapeHtml(match)}</span>`
})
const tempDiv = document.createElement('div')
tempDiv.innerHTML = newNode
while(tempDiv.firstChild) {
node.parentNode.insertBefore(tempDiv.firstChild, node)
}
node.parentNode.removeChild(node)
} else if(node.nodeType === 1 && node.tagName !== 'SCRIPT' && node.tagName !== 'BR' && node.tagName !== 'STYLE' && !node.classList.contains('highlight')) {
Array.from(node.childNodes).forEach(highlightNode);
}
}
selectors.forEach(selector => {
elements = container.find(selector)
if(!elements || elements.length < 1) return;
elements.nodes.forEach(highlightNode)
})
}
String.prototype.escapeHtml = function() {
try {
return escapeHtml(this)
} catch(e) {
return ''
}
}
function fmtTime(time) {
const mins = String(Math.floor(time / 60)).padStart(2, '0');
const secs = String(Math.floor(time % 60)).padStart(2, '0');
return `${ mins}:${ secs}`;
}
function fastError(message) {
MessageBox(tr("error"), message, [tr("ok")], [Function.noop])
}
function humanFileSize(bytes, si) {
var thresh = si ? 1000 : 1024;
if(Math.abs(bytes) < thresh) {
return bytes + ' B';
}
var units = si
? ['kB','MB','GB','TB','PB','EB','ZB','YB']
: ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB'];
var u = -1;
do {
bytes /= thresh;
++u;
} while(Math.abs(bytes) >= thresh && u < units.length - 1);
return bytes.toFixed(1)+' '+units[u];
}
function trim(string) {
var newStr = string.substring(0, 10);
if(newStr.length !== string.length)
newStr += "…";
return newStr;
}
function trimNum(string, num) {
return ovk_proc_strtr(string, num);
}
function ovk_proc_strtr(string, length = 0) {
const newString = string.substring(0, length);
return newString + (string !== newString ? "…" : "");
}
function chunkSubstr(string, size) {
const numChunks = Math.ceil(string.length / size);
const chunks = new Array(numChunks);
for (let i = 0, o = 0; i < numChunks; ++i, o += size) {
chunks[i] = string.substr(o, size);
}
return chunks;
}
function random_int(min, max) {
return Math.round(Math.random() * (max - min) + min)
}
function makeError(text, color = 'Red', timeout = 10000, uid = 0) {
const rand_id = uid != 0 ? uid : random_int(0, 10000)
if(uid != 0 && u(`.upLeftErrors .upLeftError[data-id='${uid}']`).length > 0) {
return
}
u('.upLeftErrors').append(`
<div class='upLeftError upLeftError${color}' data-id='${rand_id}'>${escapeHtml(text)}</div>
`)
setTimeout(() => {
u(`.upLeftError[data-id='${rand_id}']`).remove()
}, timeout)
}
function array_splice(array, key)
{
let resultArray = [];
for(let i = 0; i < array.length; i++){
if(i != key){
resultArray.push(array[i]);
}
}
return resultArray;
}
function strip_tags(text)
{
return text.replace(/(<([^>]+)>)/gi, "")
}
function find_author(id, profiles, groups)
{
if(id > 0) {
const profile = profiles.find(prof => prof.id == id)
if(profile) {
return profile
}
} else {
const group = groups.find(grou => grou.id == Math.abs(id))
if(group) {
return group
}
}
return null
}
function collect_attachments(target) {
const horizontal_array = []
const horizontal_attachments = target.find(`.post-horizontal > a`)
horizontal_attachments.nodes.forEach(_node => {
horizontal_array.push(`${_node.dataset.type}${_node.dataset.id}`)
})
const vertical_array = []
const vertical_attachments = target.find(`.post-vertical > .vertical-attachment`)
vertical_attachments.nodes.forEach(_node => {
vertical_array.push(`${_node.dataset.type}${_node.dataset.id}`)
})
return horizontal_array.concat(vertical_array)
}

424
Web/static/js/yarn.lock Normal file
View file

@ -0,0 +1,424 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@atlassian/aui@^9.6.0":
version "9.6.0"
resolved "https://registry.yarnpkg.com/@atlassian/aui/-/aui-9.6.0.tgz#9f35e67359022f1e6d5efa2653e79aeec95b9e77"
integrity sha512-o/bCufj0tUU6pRk3AWoXlcyVMTMx4QswB1UY5oJWSjopA+z/QUx0fhc4rRIIbxP0MrJMNRDpgPyuzkoPb7Z7ow==
dependencies:
"@atlassian/tipsy" "1.3.3"
"@popperjs/core" "2.11.6"
backbone "1.4.1"
css.escape "1.5.1"
dompurify "2.4.5"
fancy-file-input "2.0.4"
jquery-ui "1.13.2"
skatejs "0.13.17"
skatejs-template-html "0.0.0"
trim-extra-html-whitespace "1.3.0"
underscore "1.13.6"
"@atlassian/tipsy@1.3.3":
version "1.3.3"
resolved "https://registry.yarnpkg.com/@atlassian/tipsy/-/tipsy-1.3.3.tgz#3f77754c4c70324c5c938e41abaa2ca682f22036"
integrity sha512-6jd9wdoiPdCbwsNi1Xrn/oMdGz22dKPeCoZ/cCGKqjnh+UYkBKb5W3spW+WNqRSxGvVtfUEEg6TXotRK/FPDaw==
"@popperjs/core@2.11.6", "@popperjs/core@^2.9.0":
version "2.11.6"
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45"
integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==
asap@~2.0.3:
version "2.0.6"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
backbone@1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/backbone/-/backbone-1.4.1.tgz#099a78184bc07b034048a8332229c2ccca1e3e62"
integrity sha512-ADy1ztN074YkWbHi8ojJVFe3vAanO/lrzMGZWUClIP7oDD/Pjy2vrASraUP+2EVCfIiTtCW4FChVow01XneivA==
dependencies:
underscore ">=1.8.3"
codem-isoboxer@0.3.6:
version "0.3.6"
resolved "https://registry.yarnpkg.com/codem-isoboxer/-/codem-isoboxer-0.3.6.tgz#867f670459b881d44f39168d5ff2a8f14c16151d"
integrity sha512-LuO8/7LW6XuR5ERn1yavXAfodGRhuY2yP60JTZIw5yNYMCE5lUVbk3NFUCJxjnphQH+Xemp5hOGb1LgUXm00Xw==
core-js@^1.0.0:
version "1.2.7"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
integrity sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=
create-react-class@^15.7.0:
version "15.7.0"
resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.7.0.tgz#7499d7ca2e69bb51d13faf59bd04f0c65a1d6c1e"
integrity sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng==
dependencies:
loose-envify "^1.3.1"
object-assign "^4.1.1"
cropperjs@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/cropperjs/-/cropperjs-1.6.1.tgz#fd132021d93b824b1b0f2c2c3b763419fb792d89"
integrity sha512-F4wsi+XkDHCOMrHMYjrTEE4QBOrsHHN5/2VsVAaRq8P7E5z7xQpT75S+f/9WikmBEailas3+yo+6zPIomW+NOA==
css.escape@1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb"
integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==
dashjs@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/dashjs/-/dashjs-4.3.0.tgz#cccda5a490cabf6c3b48aa887ec8c8ac0df1a233"
integrity sha512-cqpnJaPQpEY4DsEdF9prwD00+5dp5EGHCFc7yo9n2uuAH9k4zPkZJwXQ8dXmVRhPf3M89JfKSoAYIP3dbXmqcg==
dependencies:
codem-isoboxer "0.3.6"
es6-promise "^4.2.8"
fast-deep-equal "2.0.1"
html-entities "^1.2.1"
imsc "^1.0.2"
localforage "^1.7.1"
dompurify@2.4.5:
version "2.4.5"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.4.5.tgz#0e89a27601f0bad978f9a924e7a05d5d2cccdd87"
integrity sha512-jggCCd+8Iqp4Tsz0nIvpcb22InKEBrGz5dw3EQJMs8HPJDsKbFIO3STYtAvCfDx26Muevn1MHVI0XxjgFfmiSA==
encoding@^0.1.11:
version "0.1.13"
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9"
integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==
dependencies:
iconv-lite "^0.6.2"
es6-promise@^4.2.8:
version "4.2.8"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
event-lite@^0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/event-lite/-/event-lite-0.1.2.tgz#838a3e0fdddef8cc90f128006c8e55a4e4e4c11b"
integrity sha512-HnSYx1BsJ87/p6swwzv+2v6B4X+uxUteoDfRxsAb1S1BePzQqOLevVmkdA15GHJVd9A9Ok6wygUR18Hu0YeV9g==
fancy-file-input@2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/fancy-file-input/-/fancy-file-input-2.0.4.tgz#698c216482e07649a827681c4db3054fddc9a32b"
integrity sha512-l+J0WwDl4nM/zMJ/C8qleYnXMUJKsLng7c5uWH/miAiHoTvPDtEoLW1tmVO6Cy2O8i/1VfA+2YOwg/Q3+kgO6w==
fast-deep-equal@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
fbjs@^0.8.0:
version "0.8.17"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd"
integrity sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=
dependencies:
core-js "^1.0.0"
isomorphic-fetch "^2.1.1"
loose-envify "^1.0.0"
object-assign "^4.1.0"
promise "^7.1.1"
setimmediate "^1.0.5"
ua-parser-js "^0.7.18"
handlebars@^4.7.7:
version "4.7.7"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1"
integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==
dependencies:
minimist "^1.2.5"
neo-async "^2.6.0"
source-map "^0.6.1"
wordwrap "^1.0.0"
optionalDependencies:
uglify-js "^3.1.4"
html-entities@^1.2.1:
version "1.4.0"
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc"
integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==
iconv-lite@^0.6.2:
version "0.6.3"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
dependencies:
safer-buffer ">= 2.1.2 < 3.0.0"
id3js@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/id3js/-/id3js-2.1.1.tgz#0c307d0d2f194bc5fa7a809bbed0b1a93577f16d"
integrity sha512-9Gi+sG0RHSa5qn8hkwi2KCl+2jV8YrtiZidXbOO3uLfRAxc2jilRg0fiQ3CbeoAmR7G7ap3RVs1kqUVhIyZaog==
ieee754@^1.1.8:
version "1.2.1"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
immediate@~3.0.5:
version "3.0.6"
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=
imsc@^1.0.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/imsc/-/imsc-1.1.3.tgz#e96a60a50d4000dd7b44097272768b9fd6a4891d"
integrity sha512-IY0hMkVTNoqoYwKEp5UvNNKp/A5jeJUOrIO7judgOyhHT+xC6PA4VBOMAOhdtAYbMRHx9DTgI8p6Z6jhYQPFDA==
dependencies:
sax "1.2.1"
int64-buffer@^0.1.9:
version "0.1.10"
resolved "https://registry.yarnpkg.com/int64-buffer/-/int64-buffer-0.1.10.tgz#277b228a87d95ad777d07c13832022406a473423"
integrity sha1-J3siiofZWtd30HwTgyAiQGpHNCM=
is-stream@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
isarray@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
isomorphic-fetch@^2.1.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
integrity sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=
dependencies:
node-fetch "^1.0.1"
whatwg-fetch ">=0.10.0"
jquery-ui@1.13.2:
version "1.13.2"
resolved "https://registry.yarnpkg.com/jquery-ui/-/jquery-ui-1.13.2.tgz#de03580ae6604773602f8d786ad1abfb75232034"
integrity sha512-wBZPnqWs5GaYJmo1Jj0k/mrSkzdQzKDwhXNtHKcBdAcKVxMM3KNYFq+iJ2i1rwiG53Z8M4mTn3Qxrm17uH1D4Q==
dependencies:
jquery ">=1.8.0 <4.0.0"
"jquery@>=1.8.0 <4.0.0":
version "3.6.0"
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.6.0.tgz#c72a09f15c1bdce142f49dbf1170bdf8adac2470"
integrity sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==
jquery@^3.0.0:
version "3.7.0"
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.7.0.tgz#fe2c01a05da500709006d8790fe21c8a39d75612"
integrity sha512-umpJ0/k8X0MvD1ds0P9SfowREz2LenHsQaxSohMZ5OMNEU2r0tf8pdeEFTHMFxWVxKNyU9rTtK3CWzUCTKJUeQ==
"js-tokens@^3.0.0 || ^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
knockout@^3.5.1:
version "3.5.1"
resolved "https://registry.yarnpkg.com/knockout/-/knockout-3.5.1.tgz#62c81e81843bea2008fd23c575edd9ca978e75cf"
integrity sha512-wRJ9I4az0QcsH7A4v4l0enUpkS++MBx0BnL/68KaLzJg7x1qmbjSlwEoCNol7KTYZ+pmtI7Eh2J0Nu6/2Z5J/Q==
ky@^0.19.0:
version "0.19.0"
resolved "https://registry.yarnpkg.com/ky/-/ky-0.19.0.tgz#d6ad117e89efe2d85a1c2e91462d48ca1cda1f7a"
integrity sha512-RkDgbg5ahMv1MjHfJI2WJA2+Qbxq0iNSLWhreYiCHeHry9Q12sedCnP5KYGPt7sydDvsyH+8UcG6Kanq5mpsyw==
lie@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e"
integrity sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=
dependencies:
immediate "~3.0.5"
literallycanvas@^0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/literallycanvas/-/literallycanvas-0.5.2.tgz#7d4800a8d9c4b38a593e91695d52466689586abd"
integrity sha512-SPxZ0DfzUWOXBPnsFD/Y1OulGKpv33IKGB+DCoUkNKQsc38kRDy1mGjbWbs/JAAyIGM1C9Y0CYI23SQmtXR5aw==
dependencies:
react-addons-pure-render-mixin "^15.1"
localforage@^1.7.1:
version "1.10.0"
resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.10.0.tgz#5c465dc5f62b2807c3a84c0c6a1b1b3212781dd4"
integrity sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==
dependencies:
lie "3.1.1"
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
minimist@^1.2.5:
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
monaco-editor@^0.20.0:
version "0.20.0"
resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.20.0.tgz#5d5009343a550124426cb4d965a4d27a348b4dea"
integrity sha512-hkvf4EtPJRMQlPC3UbMoRs0vTAFAYdzFQ+gpMb8A+9znae1c43q8Mab9iVsgTcg/4PNiLGGn3SlDIa8uvK1FIQ==
msgpack-lite@^0.1.26:
version "0.1.26"
resolved "https://registry.yarnpkg.com/msgpack-lite/-/msgpack-lite-0.1.26.tgz#dd3c50b26f059f25e7edee3644418358e2a9ad89"
integrity sha1-3TxQsm8FnyXn7e42REGDWOKprYk=
dependencies:
event-lite "^0.1.1"
ieee754 "^1.1.8"
int64-buffer "^0.1.9"
isarray "^1.0.0"
neo-async@^2.6.0:
version "2.6.2"
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
node-fetch@^1.0.1:
version "1.7.3"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef"
integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==
dependencies:
encoding "^0.1.11"
is-stream "^1.0.1"
object-assign@^4.1.0, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
plotly.js-dist@^1.52.3:
version "1.52.3"
resolved "https://registry.yarnpkg.com/plotly.js-dist/-/plotly.js-dist-1.52.3.tgz#4c16c6da6adab6cdba169087b5005bdddbf10834"
integrity sha512-kpuNwveRk6M/5cCW1ZgJTbMLD0bRZhJlLK0cUHVkTsP/PWKCVJqO3QiiqrypFGE/xEhWfHCY+YKAKjMmEbo4Gw==
promise@^7.1.1:
version "7.3.1"
resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==
dependencies:
asap "~2.0.3"
react-addons-pure-render-mixin@^15.1:
version "15.6.3"
resolved "https://registry.yarnpkg.com/react-addons-pure-render-mixin/-/react-addons-pure-render-mixin-15.6.3.tgz#5dc73af0fa32186dbc4887f20667b46d3f9caed7"
integrity sha512-e7F2OsLiyYGr9SHWHGlI/FfHRh+kbYx0hNfdN5zivHIf4vzeno7gsRJKXg71E35CpUCnre+JfM6UgWWgsvJBzA==
dependencies:
object-assign "^4.1.0"
react-dom-factories@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/react-dom-factories/-/react-dom-factories-1.0.2.tgz#eb7705c4db36fb501b3aa38ff759616aa0ff96e0"
integrity sha1-63cFxNs2+1AbOqOP91lhaqD/luA=
react-dom@15.1:
version "15.1.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.1.0.tgz#d0c2b24c8b47a41a2b9ec766662d4e686f353153"
integrity sha1-0MKyTItHpBornsdmZi1OaG81MVM=
react@15.1:
version "15.1.0"
resolved "https://registry.yarnpkg.com/react/-/react-15.1.0.tgz#5f7a9f085a00509898efd2b24cb12ea1dfaf8b40"
integrity sha1-X3qfCFoAUJiY79KyTLEuod+vi0A=
dependencies:
fbjs "^0.8.0"
loose-envify "^1.1.0"
object-assign "^4.1.0"
requirejs@^2.3.6:
version "2.3.6"
resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.6.tgz#e5093d9601c2829251258c0b9445d4d19fa9e7c9"
integrity sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==
"safer-buffer@>= 2.1.2 < 3.0.0":
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
sax@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a"
integrity sha1-e45lYZCyKOgaZq6nSEgNgozS03o=
setimmediate@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=
skatejs-template-html@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/skatejs-template-html/-/skatejs-template-html-0.0.0.tgz#e990c1a7d4b58b7305ffcc3338939bf402023df7"
integrity sha1-6ZDBp9S1i3MF/8wzOJOb9AICPfc=
skatejs@0.13.17:
version "0.13.17"
resolved "https://registry.yarnpkg.com/skatejs/-/skatejs-0.13.17.tgz#7a21fbb3434da45e52b47b61647168ee9e778071"
integrity sha1-eiH7s0NNpF5StHthZHFo7p53gHE=
soundjs@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/soundjs/-/soundjs-1.0.1.tgz#99970542d28d0df2a1ebd061ae75c961a98c8180"
integrity sha512-MgFPvmKYfpcNiE3X5XybNvScie3DMQlZgmNzUn4puBcpw64f4LqjH/fhM8Sb/eTJ8hK57Crr7mWy0bfJOqPj6Q==
source-map@^0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
textfit@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/textfit/-/textfit-2.4.0.tgz#80cba8006bfb9c3d9d552739257957bdda95c79c"
integrity sha512-/x4aoY5+/tJmu+iwpBH1yw75TFp86M6X15SvaaY/Eep7YySQYtqdOifEtfvVyMwzl7SZ+G4RQw00FD9g5R6i1Q==
tippy.js@^6.3.7:
version "6.3.7"
resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-6.3.7.tgz#8ccfb651d642010ed9a32ff29b0e9e19c5b8c61c"
integrity sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==
dependencies:
"@popperjs/core" "^2.9.0"
trim-extra-html-whitespace@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/trim-extra-html-whitespace/-/trim-extra-html-whitespace-1.3.0.tgz#b47efb0d1a5f2a56a85cc45cea525651e93404cf"
integrity sha1-tH77DRpfKlaoXMRc6lJWUek0BM8=
ua-parser-js@^0.7.18:
version "0.7.33"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.33.tgz#1d04acb4ccef9293df6f70f2c3d22f3030d8b532"
integrity sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw==
uglify-js@^3.1.4:
version "3.17.3"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.3.tgz#f0feedf019c4510f164099e8d7e72ff2d7304377"
integrity sha512-JmMFDME3iufZnBpyKL+uS78LRiC+mK55zWfM5f/pWBJfpOttXAqYfdDGRukYhJuyRinvPVAtUhvy7rlDybNtFg==
umbrellajs@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/umbrellajs/-/umbrellajs-3.1.0.tgz#a4e6f0f6381f9d93110b5eee962e0e0864b10bd0"
integrity sha512-3qichMg1Q6EetLweBAT0L55O2W6CJe9qyiSt1RBnf+bcOqwJ4R7e2PDcoIUrCsg+uRo3DXOvurWdklBu0ia7fg==
underscore@1.13.6:
version "1.13.6"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.6.tgz#04786a1f589dc6c09f761fc5f45b89e935136441"
integrity sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==
underscore@>=1.8.3:
version "1.13.1"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.1.tgz#0c1c6bd2df54b6b69f2314066d65b6cde6fcf9d1"
integrity sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==
whatwg-fetch@>=0.10.0:
version "3.6.2"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c"
integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==
wordwrap@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==

View file

@ -232,104 +232,49 @@ function ovk_is_ssl(): bool
return $GLOBALS["requestIsSSL"];
}
function parseAttachments($attachments, array $allow_types = ['photo', 'video', 'note', 'audio']): array
function parseAttachments(string $attachments): array
{
$exploded_attachments = is_array($attachments) ? $attachments : explode(",", $attachments);
$exploded_attachments = array_slice($exploded_attachments, 0, OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["postSizes"]["maxAttachments"] ?? 10);
$exploded_attachments = array_unique($exploded_attachments);
$imploded_types = implode('|', $allow_types);
$output_attachments = [];
$repositories = [
'photo' => [
'repo' => 'openvk\Web\Models\Repositories\Photos',
'method' => 'getByOwnerAndVID',
],
'video' => [
'repo' => 'openvk\Web\Models\Repositories\Videos',
'method' => 'getByOwnerAndVID',
],
'audio' => [
'repo' => 'openvk\Web\Models\Repositories\Audios',
'method' => 'getByOwnerAndVID',
],
'note' => [
'repo' => 'openvk\Web\Models\Repositories\Notes',
'method' => 'getNoteById',
],
'poll' => [
'repo' => 'openvk\Web\Models\Repositories\Polls',
'method' => 'get',
'onlyId' => true,
],
];
$attachmentsArr = explode(",", $attachments);
$returnArr = [];
foreach($exploded_attachments as $attachment_string) {
if(preg_match("/$imploded_types/", $attachment_string, $matches) == 1) {
try {
$attachment_type = $matches[0];
if(!$repositories[$attachment_type])
continue;
$attachment_ids = str_replace($attachment_type, '', $attachment_string);
if($repositories[$attachment_type]['onlyId']) {
[$attachment_id] = array_map('intval', explode('_', $attachment_ids));
$repository_class = $repositories[$attachment_type]['repo'];
if(!$repository_class) continue;
$attachment_model = (new $repository_class)->{$repositories[$attachment_type]['method']}($attachment_id);
$output_attachments[] = $attachment_model;
} else {
[$attachment_owner, $attachment_id] = array_map('intval', explode('_', $attachment_ids));
$repository_class = $repositories[$attachment_type]['repo'];
if(!$repository_class) continue;
$attachment_model = (new $repository_class)->{$repositories[$attachment_type]['method']}($attachment_owner, $attachment_id);
$output_attachments[] = $attachment_model;
}
} catch(\Throwable) {continue;}
foreach($attachmentsArr as $attachment) {
$attachmentType = NULL;
if(str_contains($attachment, "photo"))
$attachmentType = "photo";
elseif(str_contains($attachment, "video"))
$attachmentType = "video";
elseif(str_contains($attachment, "note"))
$attachmentType = "note";
elseif(str_contains($attachment, "audio"))
$attachmentType = "audio";
$attachmentIds = str_replace($attachmentType, "", $attachment);
$attachmentOwner = (int) explode("_", $attachmentIds)[0];
$gatoExplotano = explode("_", $attachmentIds);
$attachmentId = (int) end($gatoExplotano);
switch($attachmentType) {
case "photo":
$attachmentObj = (new openvk\Web\Models\Repositories\Photos)->getByOwnerAndVID($attachmentOwner, $attachmentId);
$returnArr[] = $attachmentObj;
break;
case "video":
$attachmentObj = (new openvk\Web\Models\Repositories\Videos)->getByOwnerAndVID($attachmentOwner, $attachmentId);
$returnArr[] = $attachmentObj;
break;
case "note":
$attachmentObj = (new openvk\Web\Models\Repositories\Notes)->getNoteById($attachmentOwner, $attachmentId);
$returnArr[] = $attachmentObj;
break;
case "audio":
$attachmentObj = (new openvk\Web\Models\Repositories\Audios)->getByOwnerAndVID($attachmentOwner, $attachmentId);
$returnArr[] = $attachmentObj;
break;
}
}
return $output_attachments;
}
function get_entity_by_id(int $id)
{
if($id > 0)
return (new openvk\Web\Models\Repositories\Users)->get($id);
return (new openvk\Web\Models\Repositories\Clubs)->get(abs($id));
}
function get_entities(array $ids = []): array
{
$main_result = [];
$users = [];
$clubs = [];
foreach($ids as $id) {
$id = (int)$id;
if($id < 0)
$clubs[] = abs($id);
if($id > 0)
$users[] = $id;
}
if(sizeof($users) > 0) {
$users_tmp = (new openvk\Web\Models\Repositories\Users)->getByIds($users);
foreach($users_tmp as $user) {
$main_result[] = $user;
}
}
if(sizeof($clubs) > 0) {
$clubs_tmp = (new openvk\Web\Models\Repositories\Clubs)->getByIds($clubs);
foreach($clubs_tmp as $club) {
$main_result[] = $club;
}
}
return $main_result;
return $returnArr;
}
function ovk_scheme(bool $with_slashes = false): string

377
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "987e26c5520b71fccd0cd31de00eead2",
"content-hash": "0d3b0eb1916eaf088444ef637743284a",
"packages": [
{
"name": "al/emoji-detector",
@ -197,16 +197,16 @@
},
{
"name": "chillerlan/php-settings-container",
"version": "3.2.1",
"version": "3.2.0",
"source": {
"type": "git",
"url": "https://github.com/chillerlan/php-settings-container.git",
"reference": "95ed3e9676a1d47cab2e3174d19b43f5dbf52681"
"reference": "8f93648fac8e6bacac8e00a8d325eba4950295e6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/chillerlan/php-settings-container/zipball/95ed3e9676a1d47cab2e3174d19b43f5dbf52681",
"reference": "95ed3e9676a1d47cab2e3174d19b43f5dbf52681",
"url": "https://api.github.com/repos/chillerlan/php-settings-container/zipball/8f93648fac8e6bacac8e00a8d325eba4950295e6",
"reference": "8f93648fac8e6bacac8e00a8d325eba4950295e6",
"shasum": ""
},
"require": {
@ -214,16 +214,15 @@
"php": "^8.1"
},
"require-dev": {
"phan/phan": "^5.4",
"phpmd/phpmd": "^2.15",
"phpstan/phpstan": "^1.11",
"phpstan/phpstan-deprecation-rules": "^1.2",
"phpunit/phpunit": "^10.5",
"squizlabs/php_codesniffer": "^3.10"
"squizlabs/php_codesniffer": "^3.9"
},
"type": "library",
"autoload": {
"psr-4": {
"chillerlan\\Settings\\": "src"
"chillerlan\\Settings\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@ -259,7 +258,7 @@
"type": "ko_fi"
}
],
"time": "2024-07-16T11:13:48+00:00"
"time": "2024-03-02T20:07:15+00:00"
},
{
"name": "erusev/parsedown",
@ -267,20 +266,20 @@
"source": {
"type": "git",
"url": "https://github.com/erusev/parsedown.git",
"reference": "582f9f9cd12a894a0901bef1652854a3c5a1d874"
"reference": "1ff038273949df7d6a455352659a878f3c89b29c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/erusev/parsedown/zipball/582f9f9cd12a894a0901bef1652854a3c5a1d874",
"reference": "582f9f9cd12a894a0901bef1652854a3c5a1d874",
"url": "https://api.github.com/repos/erusev/parsedown/zipball/1ff038273949df7d6a455352659a878f3c89b29c",
"reference": "1ff038273949df7d6a455352659a878f3c89b29c",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": ">=7.1"
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "^7.5|^8.5|^9.6"
"phpunit/phpunit": "^4.8.35"
},
"default-branch": true,
"type": "library",
@ -310,7 +309,7 @@
"issues": "https://github.com/erusev/parsedown/issues",
"source": "https://github.com/erusev/parsedown/tree/master"
},
"time": "2024-10-12T07:06:08+00:00"
"time": "2024-03-12T05:27:45+00:00"
},
{
"name": "ezyang/htmlpurifier",
@ -318,12 +317,12 @@
"source": {
"type": "git",
"url": "https://github.com/ezyang/htmlpurifier.git",
"reference": "cb56001e54359df7ae76dc522d08845dc741621b"
"reference": "4828fdf45a93eeeacfcbcc855f96f9a7e6b4ed44"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/cb56001e54359df7ae76dc522d08845dc741621b",
"reference": "cb56001e54359df7ae76dc522d08845dc741621b",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/4828fdf45a93eeeacfcbcc855f96f9a7e6b4ed44",
"reference": "4828fdf45a93eeeacfcbcc855f96f9a7e6b4ed44",
"shasum": ""
},
"require": {
@ -370,9 +369,9 @@
],
"support": {
"issues": "https://github.com/ezyang/htmlpurifier/issues",
"source": "https://github.com/ezyang/htmlpurifier/tree/v4.18.0"
"source": "https://github.com/ezyang/htmlpurifier/tree/master"
},
"time": "2024-11-01T03:51:45+00:00"
"time": "2024-03-13T03:41:45+00:00"
},
{
"name": "guzzlehttp/guzzle",
@ -679,12 +678,12 @@
"source": {
"type": "git",
"url": "https://github.com/JamesHeinrich/getID3.git",
"reference": "eb358a0d4943c0cc23e783f1a72141f46153c13a"
"reference": "143af3325ee40e77c5d041d3f674c8bdd4762dc7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/JamesHeinrich/getID3/zipball/eb358a0d4943c0cc23e783f1a72141f46153c13a",
"reference": "eb358a0d4943c0cc23e783f1a72141f46153c13a",
"url": "https://api.github.com/repos/JamesHeinrich/getID3/zipball/143af3325ee40e77c5d041d3f674c8bdd4762dc7",
"reference": "143af3325ee40e77c5d041d3f674c8bdd4762dc7",
"shasum": ""
},
"require": {
@ -739,7 +738,7 @@
"issues": "https://github.com/JamesHeinrich/getID3/issues",
"source": "https://github.com/JamesHeinrich/getID3/tree/master"
},
"time": "2024-09-20T19:45:51+00:00"
"time": "2024-03-26T12:26:30+00:00"
},
{
"name": "league/uri",
@ -1100,20 +1099,20 @@
},
{
"name": "psr/http-factory",
"version": "1.1.0",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-factory.git",
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a"
"reference": "e616d01114759c4c489f93b099585439f795fe35"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35",
"reference": "e616d01114759c4c489f93b099585439f795fe35",
"shasum": ""
},
"require": {
"php": ">=7.1",
"php": ">=7.0.0",
"psr/http-message": "^1.0 || ^2.0"
},
"type": "library",
@ -1137,7 +1136,7 @@
"homepage": "https://www.php-fig.org/"
}
],
"description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
"description": "Common interfaces for PSR-7 HTTP message factories",
"keywords": [
"factory",
"http",
@ -1149,9 +1148,9 @@
"response"
],
"support": {
"source": "https://github.com/php-fig/http-factory"
"source": "https://github.com/php-fig/http-factory/tree/1.0.2"
},
"time": "2024-04-15T12:06:14+00:00"
"time": "2023-04-10T20:10:41+00:00"
},
{
"name": "psr/http-message",
@ -1319,22 +1318,21 @@
"source": {
"type": "git",
"url": "https://github.com/scssphp/scssphp.git",
"reference": "12d3cdf0fc2a73e9438ded5a5a82fb353b68d718"
"reference": "5659341b5da400dafd5672171215f4534c06236b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/scssphp/scssphp/zipball/12d3cdf0fc2a73e9438ded5a5a82fb353b68d718",
"reference": "12d3cdf0fc2a73e9438ded5a5a82fb353b68d718",
"url": "https://api.github.com/repos/scssphp/scssphp/zipball/5659341b5da400dafd5672171215f4534c06236b",
"reference": "5659341b5da400dafd5672171215f4534c06236b",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-json": "*",
"league/uri": "^7.4",
"league/uri-interfaces": "^7.4",
"league/uri": "^7.4@dev",
"league/uri-interfaces": "^7.3",
"php": ">=8.1",
"symfony/filesystem": "^5.4 || ^6.0 || ^7.0",
"symfony/polyfill-mbstring": "^1.30"
"symfony/filesystem": "^5.4 || ^6.0 || ^7.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.4",
@ -1349,7 +1347,8 @@
"zurb/foundation": "~6.7.0"
},
"suggest": {
"ext-mbstring": "For best performance, mbstring should be installed as it is faster than the polyfill"
"ext-iconv": "Can be used as fallback when ext-mbstring is not available",
"ext-mbstring": "For best performance, mbstring should be installed as it is faster than ext-iconv"
},
"default-branch": true,
"type": "library",
@ -1393,7 +1392,7 @@
"issues": "https://github.com/scssphp/scssphp/issues",
"source": "https://github.com/scssphp/scssphp/tree/main"
},
"time": "2024-10-24T15:03:30+00:00"
"time": "2024-01-13T13:17:46+00:00"
},
{
"name": "symfony/console",
@ -1401,12 +1400,12 @@
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "108d436c2af470858bdaba3257baab3a74172017"
"reference": "39f75d9d73d0c11952fdcecf4877b4d0f62a8f6e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/108d436c2af470858bdaba3257baab3a74172017",
"reference": "108d436c2af470858bdaba3257baab3a74172017",
"url": "https://api.github.com/repos/symfony/console/zipball/39f75d9d73d0c11952fdcecf4877b4d0f62a8f6e",
"reference": "39f75d9d73d0c11952fdcecf4877b4d0f62a8f6e",
"shasum": ""
},
"require": {
@ -1492,20 +1491,20 @@
"type": "tidelift"
}
],
"time": "2024-10-08T07:27:17+00:00"
"time": "2024-02-20T16:33:57+00:00"
},
{
"name": "symfony/deprecation-contracts",
"version": "v3.5.0",
"version": "v3.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1"
"reference": "7c3aff79d10325257a001fcf92d991f24fc967cf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
"reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf",
"reference": "7c3aff79d10325257a001fcf92d991f24fc967cf",
"shasum": ""
},
"require": {
@ -1514,7 +1513,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.5-dev"
"dev-main": "3.4-dev"
},
"thanks": {
"name": "symfony/contracts",
@ -1543,7 +1542,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0"
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0"
},
"funding": [
{
@ -1559,30 +1558,27 @@
"type": "tidelift"
}
],
"time": "2024-04-18T09:32:20+00:00"
"time": "2023-05-23T14:45:45+00:00"
},
{
"name": "symfony/filesystem",
"version": "v7.2.0-BETA1",
"version": "v6.4.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb"
"reference": "7f3b1755eb49297a0827a7575d5d2b2fd11cc9fb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/b8dce482de9d7c9fe2891155035a7248ab5c7fdb",
"reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/7f3b1755eb49297a0827a7575d5d2b2fd11cc9fb",
"reference": "7f3b1755eb49297a0827a7575d5d2b2fd11cc9fb",
"shasum": ""
},
"require": {
"php": ">=8.2",
"php": ">=8.1",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.8"
},
"require-dev": {
"symfony/process": "^6.4|^7.0"
},
"type": "library",
"autoload": {
"psr-4": {
@ -1609,7 +1605,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/filesystem/tree/v7.2.0-BETA1"
"source": "https://github.com/symfony/filesystem/tree/v6.4.3"
},
"funding": [
{
@ -1625,24 +1621,24 @@
"type": "tidelift"
}
],
"time": "2024-10-25T15:15:23+00:00"
"time": "2024-01-23T14:51:35+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.31.0",
"version": "v1.29.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
"reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4",
"reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4",
"shasum": ""
},
"require": {
"php": ">=7.2"
"php": ">=7.1"
},
"provide": {
"ext-ctype": "*"
@ -1688,7 +1684,7 @@
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0"
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0"
},
"funding": [
{
@ -1704,24 +1700,24 @@
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
"time": "2024-01-29T20:11:03+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
"version": "v1.31.0",
"version": "v1.29.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
"reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe"
"reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
"reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f",
"reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f",
"shasum": ""
},
"require": {
"php": ">=7.2"
"php": ">=7.1"
},
"suggest": {
"ext-intl": "For best performance"
@ -1766,7 +1762,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0"
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.29.0"
},
"funding": [
{
@ -1782,25 +1778,26 @@
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
"time": "2024-01-29T20:11:03+00:00"
},
{
"name": "symfony/polyfill-intl-idn",
"version": "v1.31.0",
"version": "v1.29.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git",
"reference": "c36586dcf89a12315939e00ec9b4474adcb1d773"
"reference": "a287ed7475f85bf6f61890146edbc932c0fff919"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773",
"reference": "c36586dcf89a12315939e00ec9b4474adcb1d773",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/a287ed7475f85bf6f61890146edbc932c0fff919",
"reference": "a287ed7475f85bf6f61890146edbc932c0fff919",
"shasum": ""
},
"require": {
"php": ">=7.2",
"symfony/polyfill-intl-normalizer": "^1.10"
"php": ">=7.1",
"symfony/polyfill-intl-normalizer": "^1.10",
"symfony/polyfill-php72": "^1.10"
},
"suggest": {
"ext-intl": "For best performance"
@ -1849,7 +1846,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0"
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.29.0"
},
"funding": [
{
@ -1865,24 +1862,24 @@
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
"time": "2024-01-29T20:11:03+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.31.0",
"version": "v1.29.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "3833d7255cc303546435cb650316bff708a1c75c"
"reference": "bc45c394692b948b4d383a08d7753968bed9a83d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c",
"reference": "3833d7255cc303546435cb650316bff708a1c75c",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d",
"reference": "bc45c394692b948b4d383a08d7753968bed9a83d",
"shasum": ""
},
"require": {
"php": ">=7.2"
"php": ">=7.1"
},
"suggest": {
"ext-intl": "For best performance"
@ -1930,7 +1927,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0"
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0"
},
"funding": [
{
@ -1946,24 +1943,24 @@
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
"time": "2024-01-29T20:11:03+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.31.0",
"version": "v1.29.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
"reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
"reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
"shasum": ""
},
"require": {
"php": ">=7.2"
"php": ">=7.1"
},
"provide": {
"ext-mbstring": "*"
@ -2010,7 +2007,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0"
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0"
},
"funding": [
{
@ -2026,24 +2023,97 @@
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
"time": "2024-01-29T20:11:03+00:00"
},
{
"name": "symfony/polyfill-php73",
"version": "v1.31.0",
"name": "symfony/polyfill-php72",
"version": "v1.29.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php73.git",
"reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb"
"url": "https://github.com/symfony/polyfill-php72.git",
"reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb",
"reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/861391a8da9a04cbad2d232ddd9e4893220d6e25",
"reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25",
"shasum": ""
},
"require": {
"php": ">=7.2"
"php": ">=7.1"
},
"type": "library",
"extra": {
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php72\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php72/tree/v1.29.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-01-29T20:11:03+00:00"
},
{
"name": "symfony/polyfill-php73",
"version": "v1.29.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php73.git",
"reference": "21bd091060673a1177ae842c0ef8fe30893114d2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/21bd091060673a1177ae842c0ef8fe30893114d2",
"reference": "21bd091060673a1177ae842c0ef8fe30893114d2",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"type": "library",
"extra": {
@ -2086,7 +2156,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php73/tree/v1.31.0"
"source": "https://github.com/symfony/polyfill-php73/tree/v1.29.0"
},
"funding": [
{
@ -2102,24 +2172,24 @@
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
"time": "2024-01-29T20:11:03+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.31.0",
"version": "v1.29.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8"
"reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
"reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
"reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
"shasum": ""
},
"require": {
"php": ">=7.2"
"php": ">=7.1"
},
"type": "library",
"extra": {
@ -2166,7 +2236,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0"
"source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0"
},
"funding": [
{
@ -2182,26 +2252,25 @@
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
"time": "2024-01-29T20:11:03+00:00"
},
{
"name": "symfony/service-contracts",
"version": "v3.5.0",
"version": "v3.4.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f"
"reference": "fe07cbc8d837f60caf7018068e350cc5163681a0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f",
"reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/fe07cbc8d837f60caf7018068e350cc5163681a0",
"reference": "fe07cbc8d837f60caf7018068e350cc5163681a0",
"shasum": ""
},
"require": {
"php": ">=8.1",
"psr/container": "^1.1|^2.0",
"symfony/deprecation-contracts": "^2.5|^3"
"psr/container": "^1.1|^2.0"
},
"conflict": {
"ext-psr": "<1.1|>=2"
@ -2209,7 +2278,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.5-dev"
"dev-main": "3.4-dev"
},
"thanks": {
"name": "symfony/contracts",
@ -2249,7 +2318,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/service-contracts/tree/v3.5.0"
"source": "https://github.com/symfony/service-contracts/tree/v3.4.1"
},
"funding": [
{
@ -2265,20 +2334,20 @@
"type": "tidelift"
}
],
"time": "2024-04-18T09:32:20+00:00"
"time": "2023-12-26T14:02:43+00:00"
},
{
"name": "symfony/string",
"version": "v6.4.13",
"version": "v6.4.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "38371c60c71c72b3d64d8d76f6b1bb81a2cc3627"
"reference": "4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/38371c60c71c72b3d64d8d76f6b1bb81a2cc3627",
"reference": "38371c60c71c72b3d64d8d76f6b1bb81a2cc3627",
"url": "https://api.github.com/repos/symfony/string/zipball/4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9",
"reference": "4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9",
"shasum": ""
},
"require": {
@ -2335,7 +2404,7 @@
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v6.4.13"
"source": "https://github.com/symfony/string/tree/v6.4.4"
},
"funding": [
{
@ -2351,7 +2420,7 @@
"type": "tidelift"
}
],
"time": "2024-09-25T14:18:03+00:00"
"time": "2024-02-01T13:16:41+00:00"
},
{
"name": "vearutop/php-obscene-censor-rus",
@ -2456,12 +2525,12 @@
"source": {
"type": "git",
"url": "https://github.com/wapmorgan/Morphos.git",
"reference": "d22876709756b538a52b30a50a3f37cd89efeb91"
"reference": "302b56636cf604ad07e20020076d8a4880554286"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/wapmorgan/Morphos/zipball/d22876709756b538a52b30a50a3f37cd89efeb91",
"reference": "d22876709756b538a52b30a50a3f37cd89efeb91",
"url": "https://api.github.com/repos/wapmorgan/Morphos/zipball/302b56636cf604ad07e20020076d8a4880554286",
"reference": "302b56636cf604ad07e20020076d8a4880554286",
"shasum": ""
},
"require": {
@ -2523,7 +2592,7 @@
"issues": "https://github.com/wapmorgan/Morphos/issues",
"source": "https://github.com/wapmorgan/Morphos/tree/master"
},
"time": "2024-09-26T12:41:09+00:00"
"time": "2024-03-26T07:24:27+00:00"
},
{
"name": "whichbrowser/parser",
@ -2531,12 +2600,12 @@
"source": {
"type": "git",
"url": "https://github.com/WhichBrowser/Parser-PHP.git",
"reference": "581d614d686bfbec3529ad60562a5213ac5d8d72"
"reference": "1044880bc792dbce5948fbff22ae731c43c280d9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/WhichBrowser/Parser-PHP/zipball/581d614d686bfbec3529ad60562a5213ac5d8d72",
"reference": "581d614d686bfbec3529ad60562a5213ac5d8d72",
"url": "https://api.github.com/repos/WhichBrowser/Parser-PHP/zipball/1044880bc792dbce5948fbff22ae731c43c280d9",
"reference": "1044880bc792dbce5948fbff22ae731c43c280d9",
"shasum": ""
},
"require": {
@ -2560,7 +2629,8 @@
"autoload": {
"psr-4": {
"WhichBrowser\\": [
"src/"
"src/",
"tests/src/"
]
}
},
@ -2585,28 +2655,28 @@
],
"support": {
"issues": "https://github.com/WhichBrowser/Parser-PHP/issues",
"source": "https://github.com/WhichBrowser/Parser-PHP/tree/v2.1.8"
"source": "https://github.com/WhichBrowser/Parser-PHP/tree/v2.1.7"
},
"time": "2024-04-17T12:47:41+00:00"
"time": "2022-04-19T20:14:54+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "beta",
"stability-flags": {
"al/emoji-detector": 20,
"bhaktaraz/php-rss-generator": 20,
"erusev/parsedown": 20,
"ezyang/htmlpurifier": 20,
"whichbrowser/parser": 20,
"james-heinrich/getid3": 20,
"lfkeitel/phptotp": 20,
"rybakit/msgpack": 20,
"scssphp/scssphp": 20,
"symfony/console": 20,
"vearutop/php-obscene-censor-rus": 20,
"wapmorgan/binary-stream": 20,
"wapmorgan/morphos": 20,
"whichbrowser/parser": 20
"al/emoji-detector": 20,
"ezyang/htmlpurifier": 20,
"scssphp/scssphp": 20,
"lfkeitel/phptotp": 20,
"vearutop/php-obscene-censor-rus": 20,
"erusev/parsedown": 20,
"bhaktaraz/php-rss-generator": 20,
"symfony/console": 20,
"wapmorgan/morphos": 20
},
"prefer-stable": false,
"prefer-lowest": false,
@ -2614,9 +2684,8 @@
"php": "~7.3||~8.1",
"ext-openssl": "*",
"ext-simplexml": "*",
"ext-sodium": "*",
"ext-iconv": "*"
"ext-sodium": "*"
},
"platform-dev": {},
"plugin-api-version": "2.6.0"
"platform-dev": [],
"plugin-api-version": "2.3.0"
}

View file

@ -30,7 +30,7 @@ docker build -t ghcr.io/openvk/openvk/php:8.2-apache ../../.. -f base-php-apache
DB images:
```
docker build -t ghcr.io/openvk/openvk/mariadb:10.9-primary ../../.. -f mariadb-primary.Dockerfile
docker build -t ghcr.io/openvk/openvk/mariadb:10.9-eventdb ../../.. -f mariadb-eventdb.Dockerfile
docker build -t ghcr.io/openvk/openvk/mariadb:10.9-eventdb ../../.. --f mariadb-eventdb.Dockerfile
```
OpenVK main image:
```

View file

@ -1,5 +1,5 @@
ARG GITREPO=openvk/openvk
FROM ghcr.io/${GITREPO}/php:8.2-cli AS builder
FROM ghcr.io/${GITREPO}/php:8.2-cli as builder
WORKDIR /opt
@ -27,15 +27,15 @@ ADD composer.* .
RUN composer install
FROM docker.io/node:20 AS nodejs
FROM docker.io/node:14 as nodejs
COPY --from=builder /opt/chandler /opt/chandler
WORKDIR /opt/chandler/extensions/available/openvk/Web/static/js
ADD Web/static/js/package.json Web/static/js/package-lock.json ./
ADD Web/static/js/package.json Web/static/js/package-lock.json Web/static/js/yarn.lock ./
RUN npm ci
RUN yarn install
WORKDIR /opt/chandler/extensions/available/openvk
@ -57,6 +57,4 @@ VOLUME [ "/opt/chandler/extensions/available/openvk/tmp/api-storage/audios" ]
VOLUME [ "/opt/chandler/extensions/available/openvk/tmp/api-storage/photos" ]
VOLUME [ "/opt/chandler/extensions/available/openvk/tmp/api-storage/videos" ]
USER www-data
WORKDIR /opt/chandler/extensions/available/openvk
USER www-data

View file

@ -1,2 +0,0 @@
CREATE TABLE `ignored_sources` (`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT , `owner` BIGINT(20) UNSIGNED NOT NULL , `source` BIGINT(20) NOT NULL , PRIMARY KEY (`id`), INDEX (`owner`)) ENGINE = InnoDB;
ALTER TABLE `ignored_sources` ADD INDEX `owner_source` (`owner`, `source`);

View file

@ -1,2 +0,0 @@
ALTER TABLE `videos` ADD `length` SMALLINT(5) UNSIGNED NULL DEFAULT NULL AFTER `name`, ADD INDEX `length` (`length`);
ALTER TABLE `videos` ADD `height` SMALLINT(5) UNSIGNED NULL DEFAULT NULL AFTER `length`, ADD `width` SMALLINT(5) UNSIGNED NULL DEFAULT NULL AFTER `height`;

View file

@ -219,8 +219,6 @@
"my_news" = "My news";
"all_news" = "All news";
"posts_per_page" = "Number of posts per page";
"show_ignored_sources" = "Show ignored sources";
"auto_scroll" = "Autoscroll";
"attachment" = "Attachment";
"post_as_group" = "Post as group";
@ -253,24 +251,12 @@
"edited_short" = "edited";
"feed_settings" = "Feed settings";
"ignored_sources" = "Ignored sources";
"ignore_user" = "Ignore user";
"unignore_user" = "Unignore user";
"ignore_club" = "Ignore club";
"unignore_club" = "Unignore club";
"no_ignores_count" = "No ignored sources.";
"stop_ignore" = "Unignore";
"start_from_page" = "Start from page";
"all_posts" = "All posts";
"users_posts" = "Posts by $1";
"clubs_posts" = "Group's posts";
"others_posts" = "Others posts";
"show_more" = "Show more";
"has_repost" = "Has repost";
/* Friends */
@ -519,7 +505,6 @@
"click_to_go_to_album" = "Click here to go to album.";
"error_uploading_photo" = "Error when uploading photo";
"too_many_pictures" = "No more than 10 pictures";
"too_many_attachments" = "Too many attachments.";
"drag_files_here" = "Drag files here";
"only_images_accepted" = "File \"$1\" is not an image";
@ -851,9 +836,6 @@
"no_videos" = "You don't have uploaded videos.";
"no_videos_results" = "No results.";
"video_file_upload" = "Upload file";
"video_youtube_upload" = "Add from YouTube";
"change_video" = "Change video";
"unknown_video" = "This video is not supported in your version of OpenVK.";
@ -1562,9 +1544,6 @@
"group_is_banned" = "Group was successfully banned";
"description_too_long" = "Description is too long.";
"invalid_club" = "This group does not exists.";
"invalid_user" = "This user does not exists.";
"ignored_sources_limit" = "Limit of ignored sources has exceed";
"invalid_audio" = "Invalid audio.";
"do_not_have_audio" = "You don't have this audio.";
@ -1783,9 +1762,6 @@
"question_confirm" = "This action can't be undone. Do you really wanna do it?";
"confirm_m" = "Confirm";
"action_successfully" = "Success";
"exit_noun" = "Exit";
"exit_confirmation" = "Are you sure want to exit?";
"apply" = "Apply";
/* User Alerts */
@ -2090,7 +2066,7 @@
"showing_x_y" = "(showing $1—$2)";
"no_results_by_this_query" = "Nothing was found by this query.";
"s_additional" = "Additional";
"s_it_is_you" = "that's you";
"s_it_is_you" = "it is you";
/* BadBrowser */

View file

@ -13,7 +13,7 @@ list:
flag: "ua"
name: "Ukrainian"
native_name: "Українcька"
author: "Jaroslav (ovk.to/id6908), Andrej Lenťaj, Maxim Hrabovi (dechioyo) and Kirill (mbsoft)"
author: "Aqukie (yaroslav.bielograd@ukr.net), Andrej Lenťaj, Maxim Hrabovi (dechioyo) and Kirill (mbsoft)"
- code: "by"
flag: "by"
name: "Belarussian"

View file

@ -204,8 +204,6 @@
"my_news" = "Мои новости";
"all_news" = "Все новости";
"posts_per_page" = "Количество записей на странице";
"show_ignored_sources" = "Показывать игнорируемые источники";
"auto_scroll" = "Автоматическая прокрутка";
"attachment" = "Вложение";
"post_as_group" = "От имени сообщества";
"comment_as_group" = "От имени сообщества";
@ -233,23 +231,11 @@
"post_is_ad" = "Этот пост был размещён за взятку.";
"edited_short" = "ред.";
"feed_settings" = "Настройки ленты";
"ignored_sources" = "Игнорируемые источники";
"ignore_user" = "Игнорировать пользователя";
"unignore_user" = "Не игнорировать пользователя";
"ignore_club" = "Игнорировать группу";
"unignore_club" = "Не игнорировать группу";
"no_ignores_count" = "Игнорируемых источников нет.";
"stop_ignore" = "Не игнорировать";
"start_from_page" = "Начинать со страницы";
"all_posts" = "Все записи";
"users_posts" = "Записи $1";
"clubs_posts" = "Записи сообщества";
"others_posts" = "Чужие записи";
"show_more" = "Показать больше";
"has_repost" = "Содержит репост";
/* Friends */
@ -502,10 +488,9 @@
"click_to_go_to_album" = "Нажмите, чтобы перейти к альбому.";
"error_uploading_photo" = "Не удалось загрузить фотографию";
"too_many_pictures" = "Не больше 10 фотографий";
"too_many_attachments" = "Слишком много вложений.";
"drag_files_here" = "Перетащите файлы сюда";
"only_images_accepted" = "Файл \"$1\" не является изображением или видео.";
"only_images_accepted" = "Файл \"$1\" не является изображением";
"max_filesize" = "Максимальный размер файла — $1 мегабайт";
"uploading_photos_from_computer" = "Загрузка фотографий с Вашего компьютера";
@ -810,9 +795,6 @@
"no_videos" = "У вас нет видео.";
"no_videos_results" = "Нет результатов.";
"video_file_upload" = "Загрузить файл";
"video_youtube_upload" = "Добавить с YouTube";
/* Audios */
"my" = "Моё";
@ -1463,11 +1445,6 @@
"group_owner_is_banned" = "Создатель сообщества успешно забанен.";
"group_is_banned" = "Сообщество успешно забанено";
"description_too_long" = "Описание слишком длинное.";
"invalid_club" = "Такой группы не существует.";
"invalid_user" = "Такого пользователя не существует.";
"ignored_sources_limit" = "Превышен лимит игнорируемых источников.";
"invalid_audio" = "Такой аудиозаписи не существует.";
"do_not_have_audio" = "У вас нет этой аудиозаписи.";
"do_have_audio" = "У вас уже есть эта аудиозапись.";
@ -1487,7 +1464,7 @@
"error_adding_source_regex" = "Ошибка добавления источника: некорректная ссылка.";
"error_adding_source_long" = "Ошибка добавления источника: слишком длинная ссылка.";
"error_adding_source_sus" = "Ошибка добавления источника: гиперссылка заблокирована.";
"error_adding_source_sus" = "Ошибка добавления источника: подозрительная ссылка.";
/* Admin actions */
@ -1675,9 +1652,6 @@
"question_confirm" = "Это действие нельзя отменить. Вы действительно уверены в том что хотите сделать?";
"confirm_m" = "Подтвердить";
"action_successfully" = "Операция успешна";
"exit_noun" = "Выход";
"exit_confirmation" = "Уверены, что хотите выйти?";
"apply" = "Применить";
/* User alerts */
@ -2036,7 +2010,7 @@
/* Fullscreen player */
"hide_player" = "Свернуть";
"hide_player" = "Скрыть";
"close_player" = "Закрыть";
"show_comments" = "Показать информацию";
"close_comments" = "Скрыть информацию";

File diff suppressed because it is too large Load diff

View file

@ -52,15 +52,12 @@ openvk:
strict: false
music:
exposeOriginalURLs: true
newsfeed:
ignoredSourcesLimit: 50
wall:
christian: false
anonymousPosting:
enable: false
account: 100
postSizes:
maxAttachments: 10
maxSize: 60000
processingLimit: 3000
emojiProcessingLimit: 1000

View file

@ -1,7 +1,7 @@
.page_header {
background-image: url('/themepack/midnight/0.0.3.1/resource/xheader.png') !important;
background-image: url('/themepack/midnight/0.0.3.0/resource/xheader.png') !important;
}
.page_custom_header {
background-image: url('/themepack/midnight/0.0.3.1/resource/xheader_custom.png') !important;
background-image: url('/themepack/midnight/0.0.3.0/resource/xheader_custom.png') !important;
}

View file

@ -186,12 +186,8 @@ hr {
.menu_divider,
.ovk-diag-action,
.minilink .counter,
.topGrayBlock,
.showMore,
.showMoreAudiosPlaylist,
#showMorePhotos,
#showMoreVideos {
background-color: #2c2640 !important;
.topGrayBlock {
background-color: #2c2640;
}
.bsdn_contextMenu {
@ -317,11 +313,11 @@ tr.v,
}
.content_title_expanded {
background-image: url("/themepack/midnight/0.0.3.1/resource/flex_arrow_open.png") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/flex_arrow_open.png") !important;
}
.content_title_unexpanded {
background-image: url("/themepack/midnight/0.0.3.1/resource/flex_arrow_shut.gif") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/flex_arrow_shut.gif") !important;
}
.ovk-video>.preview,
@ -348,17 +344,17 @@ tr.h {
.page_yellowheader {
color: #c6d2e8;
background-image: url("/themepack/midnight/0.0.3.1/resource/header_purple.png") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/header_purple.png") !important;
background-color: #231f34;
border-color: #231f34;
}
.page_header {
background-image: url("/themepack/midnight/0.0.3.1/resource/header.png") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/header.png") !important;
}
.page_custom_header {
background-image: url("/themepack/midnight/0.0.3.1/resource/header_custom.png") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/header_custom.png") !important;
}
.page_yellowheader span,
@ -396,11 +392,11 @@ select,
}
input[type="checkbox"] {
background-image: url("/themepack/midnight/0.0.3.1/resource/checkbox.png") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/checkbox.png") !important;
}
input[type="radio"] {
background-image: url("/themepack/midnight/0.0.3.1/resource/radio.png") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/radio.png") !important;
}
.header_navigation .link, .header_navigation .header_divider_stick {
@ -408,20 +404,20 @@ input[type="radio"] {
}
.heart {
background-image: url("/themepack/midnight/0.0.3.1/resource/like.gif") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/like.gif") !important;
}
.pinned-mark,
.post-author .pin {
background-image: url("/themepack/midnight/0.0.3.1/resource/pin.png") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/pin.png") !important;
}
.repost-icon {
background-image: url("/themepack/midnight/0.0.3.1/resource/published.gif") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/published.gif") !important;
}
.post-author .delete {
background-image: url("/themepack/midnight/0.0.3.1/resource/input_clear.gif") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/input_clear.gif") !important;
}
.user-alert {
@ -454,7 +450,7 @@ input[type="radio"] {
}
#backdropEditor {
background-image: url("/themepack/midnight/0.0.3.1/resource/backdrop-editor.gif") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/backdrop-editor.gif") !important;
border-color: #473e66 !important;
}
@ -592,6 +588,11 @@ ul {
cursor: pointer;
}
.showMore,
.showMoreAudiosPlaylist {
background: #181826 !important;
}
/* Tour */
.rightNav h1 {
background: #000;

View file

@ -1,5 +1,5 @@
id: midnight
version: "0.0.3.1"
version: "0.0.3.0"
openvk_version: 0
enabled: 1
metadata: