mirror of
https://github.com/openvk/openvk
synced 2024-11-15 03:31:18 +03:00
Merge branch 'master' into ignored-sources
This commit is contained in:
commit
a99ffbdafe
139 changed files with 7152 additions and 2180 deletions
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
|
@ -1 +1 @@
|
|||
custom: "https://openvk.su/donate"
|
||||
custom: "https://ovk.to/donate"
|
||||
|
|
18
.github/workflows/build-base.yaml
vendored
18
.github/workflows/build-base.yaml
vendored
|
@ -6,7 +6,7 @@ on:
|
|||
|
||||
env:
|
||||
BASE_IMAGE_NAME: php
|
||||
BASE_IMAGE_VERSION: "8.1"
|
||||
BASE_IMAGE_VERSION: "8.2"
|
||||
|
||||
jobs:
|
||||
build-cli:
|
||||
|
@ -24,12 +24,18 @@ jobs:
|
|||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Change repository string to lowercase
|
||||
id: repositorystring
|
||||
uses: Entepotenz/change-string-case-action-min-dependencies@v1.1.0
|
||||
with:
|
||||
string: ${{ github.repository }}
|
||||
|
||||
- name: Log into registry
|
||||
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
||||
|
||||
- name: Build cli image
|
||||
run: |
|
||||
IMAGE_NAME=ghcr.io/${{ github.repository }}/$BASE_IMAGE_NAME:$BASE_IMAGE_VERSION-cli
|
||||
IMAGE_NAME=ghcr.io/${{ steps.repositorystring.outputs.lowercase }}/$BASE_IMAGE_NAME:$BASE_IMAGE_VERSION-cli
|
||||
|
||||
docker buildx build --platform linux/amd64,linux/arm64 -t $IMAGE_NAME . --push -f install/automated/docker/base-php-cli.Dockerfile --build-arg VERSION=$BASE_IMAGE_VERSION
|
||||
|
||||
|
@ -48,11 +54,17 @@ jobs:
|
|||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Change repository string to lowercase
|
||||
id: repositorystring
|
||||
uses: Entepotenz/change-string-case-action-min-dependencies@v1.1.0
|
||||
with:
|
||||
string: ${{ github.repository }}
|
||||
|
||||
- name: Log into registry
|
||||
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
||||
|
||||
- name: Build apache image
|
||||
run: |
|
||||
IMAGE_NAME=ghcr.io/${{ github.repository }}/$BASE_IMAGE_NAME:$BASE_IMAGE_VERSION-apache
|
||||
IMAGE_NAME=ghcr.io/${{ steps.repositorystring.outputs.lowercase }}/$BASE_IMAGE_NAME:$BASE_IMAGE_VERSION-apache
|
||||
|
||||
docker buildx build --platform linux/amd64,linux/arm64 -t $IMAGE_NAME . --push -f install/automated/docker/base-php-apache.Dockerfile --build-arg VERSION=$BASE_IMAGE_VERSION
|
||||
|
|
14
.github/workflows/build.yaml
vendored
14
.github/workflows/build.yaml
vendored
|
@ -36,12 +36,18 @@ jobs:
|
|||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Change repository string to lowercase
|
||||
id: repositorystring
|
||||
uses: Entepotenz/change-string-case-action-min-dependencies@v1.1.0
|
||||
with:
|
||||
string: ${{ github.repository }}
|
||||
|
||||
- name: Log into registry
|
||||
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
||||
|
||||
- name: Build base image
|
||||
run: |
|
||||
IMAGE_ID=ghcr.io/${{ github.repository }}/$BASE_IMAGE_NAME
|
||||
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//')
|
||||
|
@ -49,16 +55,16 @@ jobs:
|
|||
echo IMAGE_ID=$IMAGE_ID
|
||||
echo VERSION=$VERSION
|
||||
|
||||
docker buildx build --platform linux/amd64,linux/arm64 -t $IMAGE_ID:$VERSION . --push -f install/automated/docker/openvk.Dockerfile --build-arg GITREPO=${{ github.repository }}
|
||||
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
|
||||
run: |
|
||||
IMAGE_NAME=ghcr.io/${{ github.repository }}/$DB_IMAGE_NAME:$DB_VERSION-primary
|
||||
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
|
||||
run: |
|
||||
IMAGE_NAME=ghcr.io/${{ github.repository }}/$EVENT_IMAGE_NAME:$DB_VERSION-eventdb
|
||||
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
|
|
@ -12,7 +12,7 @@
|
|||
<tr>
|
||||
<td class="float-center" align="center" valign="top">
|
||||
<center>
|
||||
Добро пожаловать в OpenVK! Приятного времяприпровождения, надеюсь вам понравится.<br><br>Если появились вопросы, касаемые нашего сайта, пишите <a href="https://openvk.su/support?act=new">сюда</a>
|
||||
Добро пожаловать в OpenVK! Приятного времяприпровождения, надеюсь вам понравится.<br><br>Если появились вопросы, касаемые нашего сайта, пишите <a href="https://ovk.to/support?act=new">сюда</a>
|
||||
</center>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
18
README.md
18
README.md
|
@ -1,4 +1,4 @@
|
|||
# <img align="right" src="https://github.com/openvk/openvk/raw/master/Web/static/img/logo_shadow.png" alt="openvk" title="openvk" width="15%">OpenVK
|
||||
# <img align="right" src="/Web/static/img/logo_shadow.png" alt="openvk" title="openvk" width="15%">OpenVK
|
||||
|
||||
_[Русский](README_RU.md)_
|
||||
|
||||
|
@ -6,7 +6,7 @@ _[Русский](README_RU.md)_
|
|||
|
||||
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://openvk.su/support?act=new) (you will need an OpenVK account for this).
|
||||
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).
|
||||
|
||||
## When's the release?
|
||||
|
||||
|
@ -26,6 +26,14 @@ However, OVK makes use of Chandler Application Server. This software requires ex
|
|||
|
||||
If you want, you can add your instance to the list above so that people can register there.
|
||||
|
||||
### System requirements
|
||||
|
||||
Here is our minimum hardware recommendation:
|
||||
|
||||
* **CPU: Recent** (AMD Zen2 or equivalent) quad-core 2GHz+ CPU
|
||||
* **RAM:** At least 2GB RAM (we recommend 6GB or 8GB for OpenVK with Kafka)
|
||||
* **Minimum database space:** 10GB
|
||||
|
||||
### Installation procedure
|
||||
|
||||
1. Install PHP 7.4, web-server, Composer, Node.js, Yarn and [Chandler](https://github.com/openvk/chandler)
|
||||
|
@ -66,12 +74,12 @@ Once you are done, you can login as a system administrator on the network itself
|
|||
* **Password**: `admin`
|
||||
* It is recommended to change the password of the built-in account or disable it.
|
||||
|
||||
💡Confused? Full installation walkthrough is available [here](https://docs.openvk.uk/openvk_engine/centos8_installation/) (CentOS 8 [and](https://almalinux.org/) [family](https://yum.oracle.com/oracle-linux-isos.html)).
|
||||
💡 Confused? Full installation walkthrough is available [here](https://docs.ovk.to/openvk_engine/centos8_installation/) (CentOS 8 [and](https://almalinux.org/) [family](https://yum.oracle.com/oracle-linux-isos.html)).
|
||||
|
||||
### Looking for Docker or Kubernetes deployment?
|
||||
See `install/automated/docker/README.md` and `install/automated/kubernetes/README.md` for Docker and Kubernetes deployment instructions.
|
||||
|
||||
### If my website uses OpenVK, should I release it's sources?
|
||||
### If my website uses OpenVK, should I release its sources?
|
||||
|
||||
It depends. You can keep the sources to yourself if you do not plan to distribute your website binaries. If your website software must be distributed, it can stay non-OSS provided the OpenVK is not used as a primary application and is not modified. If you modified OpenVK for your needs or your work is based on it and you are planning to redistribute this, then you should license it under terms of any LGPL-compatible license (like OSL, GPL, LGPL etc).
|
||||
|
||||
|
@ -80,7 +88,7 @@ It depends. You can keep the sources to yourself if you do not plan to distribut
|
|||
You may reach out to us via:
|
||||
|
||||
* [Bug Tracker](https://github.com/openvk/openvk/projects/1)
|
||||
* [Ticketing System](https://openvk.su/support?act=new)
|
||||
* [Ticketing System](https://ovk.to/support?act=new)
|
||||
* Telegram Chat: Go to [our channel](https://t.me/openvkenglish) and open discussion in our channel menu.
|
||||
* [Reddit](https://www.reddit.com/r/openvk/)
|
||||
* [GitHub Discussions](https://github.com/openvk/openvk/discussions)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# <img align="right" src="https://github.com/openvk/openvk/raw/master/Web/static/img/logo_shadow.png" alt="openvk" title="openvk" width="15%">OpenVK
|
||||
# <img align="right" src="/Web/static/img/logo_shadow.png" alt="openvk" title="openvk" width="15%">OpenVK
|
||||
|
||||
_[English](README.md)_
|
||||
|
||||
|
@ -6,7 +6,7 @@ _[English](README.md)_
|
|||
|
||||
ВКонтакте принадлежит Павлу Дурову и VK Group.
|
||||
|
||||
Честно говоря, мы даже не знаем, работает ли она вообще. Однако, эта версия поддерживается, и мы будем рады принять ваши сообщения об ошибках [в нашем баг-трекере](https://github.com/openvk/openvk/projects/1). Вы также можете отправлять их через [вкладку "Помощь"](https://openvk.su/support?act=new) (для этого вам понадобится учетная запись OpenVK).
|
||||
Честно говоря, мы даже не знаем, работает ли она вообще. Однако, эта версия поддерживается, и мы будем рады принять ваши сообщения об ошибках [в нашем баг-трекере](https://github.com/openvk/openvk/projects/1). Вы также можете отправлять их через [вкладку "Помощь"](https://ovk.to/support?act=new) (для этого вам понадобится учетная запись OpenVK).
|
||||
|
||||
## Когда выйдет релизная версия?
|
||||
|
||||
|
@ -66,7 +66,7 @@ ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions
|
|||
* **Пароль**: `admin`
|
||||
* Перед использованием встроенной учетной записи рекомендуется сменить пароль или отключить её.
|
||||
|
||||
💡Запутались? Полное руководство по установке доступно [здесь](https://docs.openvk.uk/openvk_engine/centos8_installation/) (CentOS 8 [и](https://almalinux.org/ru/) [семейство](https://yum.oracle.com/oracle-linux-isos.html)).
|
||||
💡Запутались? Полное руководство по установке доступно [здесь](https://docs.ovk.to/openvk_engine/centos8_installation/) (CentOS 8 [и](https://almalinux.org/ru/) [семейство](https://yum.oracle.com/oracle-linux-isos.html)).
|
||||
|
||||
# Установка в Docker/Kubernetes
|
||||
Подробные иструкции можно найти в `install/automated/docker/README.md` и `install/automated/kubernetes/README.md` соответственно.
|
||||
|
@ -80,7 +80,7 @@ ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions
|
|||
Вы можете связаться с нами через:
|
||||
|
||||
* [Баг-трекер](https://github.com/openvk/openvk/projects/1)
|
||||
* [Помощь в OVK](https://openvk.su/support?act=new)
|
||||
* [Помощь в OVK](https://ovk.to/support?act=new)
|
||||
* Telegram-чат: Перейдите на [наш канал](https://t.me/openvk) и откройте обсуждение в меню нашего канала.
|
||||
* [Reddit](https://www.reddit.com/r/openvk/)
|
||||
* [GitHub Discussions](https://github.com/openvk/openvk/discussions)
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\ServiceAPI;
|
||||
|
||||
use openvk\Web\Models\Entities\APIToken;
|
||||
use openvk\Web\Models\Entities\User;
|
||||
use openvk\Web\Models\Repositories\APITokens;
|
||||
use openvk\Web\Models\Repositories\Applications;
|
||||
use WhichBrowser;
|
||||
|
||||
class Apps implements Handler
|
||||
{
|
||||
|
@ -89,4 +92,25 @@ class Apps implements Handler
|
|||
$app->withdrawCoins();
|
||||
$resolve($coins);
|
||||
}
|
||||
|
||||
function getRegularToken(string $clientName, bool $acceptsStale, callable $resolve, callable $reject): void
|
||||
{
|
||||
$token = NULL;
|
||||
$stale = true;
|
||||
if($acceptsStale)
|
||||
$token = (new APITokens)->getStaleByUser($this->user->getId(), $clientName);
|
||||
|
||||
if(is_null($token)) {
|
||||
$stale = false;
|
||||
$token = new APIToken;
|
||||
$token->setUser($this->user);
|
||||
$token->setPlatform($clientName ?? (new WhichBrowser\Parser(getallheaders()))->toString());
|
||||
$token->save();
|
||||
}
|
||||
|
||||
$resolve([
|
||||
'is_stale' => $stale,
|
||||
'token' => $token->getFormattedToken(),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\ServiceAPI;
|
||||
use openvk\Web\Models\Entities\{User, Club};
|
||||
use openvk\Web\Models\Repositories\{Users, Clubs, Videos};
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
|
||||
class Search implements Handler
|
||||
{
|
||||
protected $user;
|
||||
private $users;
|
||||
private $clubs;
|
||||
private $videos;
|
||||
|
||||
function __construct(?User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->users = new Users;
|
||||
$this->clubs = new Clubs;
|
||||
$this->videos = new Videos;
|
||||
}
|
||||
|
||||
function fastSearch(string $query, string $type = "users", callable $resolve, callable $reject)
|
||||
{
|
||||
if($query == "" || strlen($query) < 3)
|
||||
$reject(12, "No input or input < 3");
|
||||
|
||||
$repo;
|
||||
$sort;
|
||||
|
||||
switch($type) {
|
||||
default:
|
||||
case "users":
|
||||
$repo = (new Users);
|
||||
$sort = "rating DESC";
|
||||
|
||||
break;
|
||||
case "groups":
|
||||
$repo = (new Clubs);
|
||||
$sort = "id ASC";
|
||||
|
||||
break;
|
||||
case "videos":
|
||||
$repo = (new Videos);
|
||||
$sort = "created ASC";
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$res = $repo->find($query, ["doNotSearchMe" => $this->user->getId(), "doNotSearchPrivate" => true,], $sort);
|
||||
|
||||
$results = array_slice(iterator_to_array($res), 0, 5);
|
||||
|
||||
$count = sizeof($results);
|
||||
|
||||
$arr = [
|
||||
"count" => $count,
|
||||
"items" => []
|
||||
];
|
||||
|
||||
if(sizeof($results) < 1) {
|
||||
$reject(2, "No results");
|
||||
}
|
||||
|
||||
foreach($results as $res) {
|
||||
$arr["items"][] = [
|
||||
"id" => $res->getId(),
|
||||
"name" => $type == "users" ? $res->getCanonicalName() : $res->getName(),
|
||||
"avatar" => $type != "videos" ? $res->getAvatarUrl() : $res->getThumbnailURL(),
|
||||
"url" => $type != "videos" ? $res->getUrl() : "/video".$res->getPrettyId(),
|
||||
"description" => ovk_proc_strtr($res->getDescription() ?? "...", 40)
|
||||
];
|
||||
}
|
||||
|
||||
$resolve($arr);
|
||||
}
|
||||
}
|
|
@ -7,20 +7,32 @@ final class Account extends VKAPIRequestHandler
|
|||
function getProfileInfo(): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
return (object) [
|
||||
"first_name" => $this->getUser()->getFirstName(),
|
||||
"id" => $this->getUser()->getId(),
|
||||
"last_name" => $this->getUser()->getLastName(),
|
||||
"home_town" => $this->getUser()->getHometown(),
|
||||
"status" => $this->getUser()->getStatus(),
|
||||
"audio_status" => is_null($this->getUser()->getCurrentAudioStatus()) ? NULL : $this->getUser()->getCurrentAudioStatus()->toVkApiStruct($this->getUser()),
|
||||
"bdate" => is_null($this->getUser()->getBirthday()) ? '01.01.1970' : $this->getUser()->getBirthday()->format('%e.%m.%Y'),
|
||||
"bdate_visibility" => $this->getUser()->getBirthdayPrivacy(),
|
||||
$user = $this->getUser();
|
||||
$return_object = (object) [
|
||||
"first_name" => $user->getFirstName(),
|
||||
"photo_200" => $user->getAvatarURL("normal"),
|
||||
"nickname" => $user->getPseudo(),
|
||||
"is_service_account" => false,
|
||||
"id" => $user->getId(),
|
||||
"is_verified" => $user->isVerified(),
|
||||
"verification_status" => $user->isVerified() ? 'verified' : 'unverified',
|
||||
"last_name" => $user->getLastName(),
|
||||
"home_town" => $user->getHometown(),
|
||||
"status" => $user->getStatus(),
|
||||
"bdate" => is_null($user->getBirthday()) ? '01.01.1970' : $user->getBirthday()->format('%e.%m.%Y'),
|
||||
"bdate_visibility" => $user->getBirthdayPrivacy(),
|
||||
"phone" => "+420 ** *** 228", # TODO
|
||||
"relation" => $this->getUser()->getMaritalStatus(),
|
||||
"sex" => $this->getUser()->isFemale() ? 1 : 2
|
||||
"relation" => $user->getMaritalStatus(),
|
||||
"screen_name" => $user->getShortCode(),
|
||||
"sex" => $user->isFemale() ? 1 : 2,
|
||||
#"email" => $user->getEmail(),
|
||||
];
|
||||
|
||||
$audio_status = $user->getCurrentAudioStatus();
|
||||
if(!is_null($audio_status))
|
||||
$return_object->audio_status = $audio_status->toVkApiStruct($user);
|
||||
|
||||
return $return_object;
|
||||
}
|
||||
|
||||
function getInfo(): object
|
||||
|
@ -152,4 +164,30 @@ final class Account extends VKAPIRequestHandler
|
|||
|
||||
return (object) $output;
|
||||
}
|
||||
|
||||
function getBalance(): object
|
||||
{
|
||||
$this->requireUser();
|
||||
if(!OPENVK_ROOT_CONF['openvk']['preferences']['commerce'])
|
||||
$this->fail(105, "Commerce is disabled on this instance");
|
||||
|
||||
return (object) ['votes' => $this->getUser()->getCoins()];
|
||||
}
|
||||
|
||||
function getOvkSettings(): object
|
||||
{
|
||||
$this->requireUser();
|
||||
$user = $this->getUser();
|
||||
|
||||
$settings_list = (object)[
|
||||
'avatar_style' => $user->getStyleAvatar(),
|
||||
'style' => $user->getStyle(),
|
||||
'show_rating' => !$user->prefersNotToSeeRating(),
|
||||
'nsfw_tolerance' => $user->getNsfwTolerance(),
|
||||
'post_view' => $user->hasMicroblogEnabled() ? 'microblog' : 'old',
|
||||
'main_page' => $user->getMainPage() == 0 ? 'my_page' : 'news',
|
||||
];
|
||||
|
||||
return $settings_list;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -581,13 +581,18 @@ final class Audio extends VKAPIRequestHandler
|
|||
];
|
||||
}
|
||||
|
||||
function searchAlbums(string $query, int $offset = 0, int $limit = 25, int $drop_private = 0): object
|
||||
function searchAlbums(string $query = '', int $offset = 0, int $limit = 25, int $drop_private = 0, int $order = 0, int $from_me = 0): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$playlists = [];
|
||||
$search = (new Audios)->searchPlaylists($query)->offsetLimit($offset, $limit);
|
||||
foreach($search as $playlist) {
|
||||
$params = [];
|
||||
$order_str = (['id', 'length', 'listens'][$order] ?? 'id');
|
||||
if($from_me === 1)
|
||||
$params['from_me'] = $this->getUser()->getId();
|
||||
|
||||
$search = (new Audios)->findPlaylists($query, $params, ['type' => $order_str, 'invert' => false]);
|
||||
foreach($search->offsetLimit($offset, $limit) as $playlist) {
|
||||
if(!$playlist->canBeViewedBy($this->getUser())) {
|
||||
if($drop_private == 0)
|
||||
$playlists[] = NULL;
|
||||
|
@ -599,7 +604,7 @@ final class Audio extends VKAPIRequestHandler
|
|||
}
|
||||
|
||||
return (object) [
|
||||
"count" => sizeof($playlists),
|
||||
"count" => $search->size(),
|
||||
"items" => $playlists,
|
||||
];
|
||||
}
|
||||
|
|
|
@ -147,7 +147,7 @@ final class Friends extends VKAPIRequestHandler
|
|||
return $response;
|
||||
}
|
||||
|
||||
function getRequests(string $fields = "", int $offset = 0, int $count = 100, int $extended = 0): object
|
||||
function getRequests(string $fields = "", int $out = 0, int $offset = 0, int $count = 100, int $extended = 0): object
|
||||
{
|
||||
if ($count >= 1000)
|
||||
$this->fail(100, "One of the required parameters was not passed or is invalid.");
|
||||
|
@ -158,10 +158,19 @@ final class Friends extends VKAPIRequestHandler
|
|||
$offset++;
|
||||
$followers = [];
|
||||
|
||||
if ($out != 0) {
|
||||
foreach($this->getUser()->getFollowers($offset, $count) as $follower) {
|
||||
$followers[$i] = $follower->getId();
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach($this->getUser()->getRequests($offset, $count) as $follower) {
|
||||
$followers[$i] = $follower->getId();
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
$response = $followers;
|
||||
$usersApi = new Users($this->getUser());
|
||||
|
|
|
@ -6,15 +6,18 @@ use openvk\Web\Models\Entities\Notifications\GiftNotification;
|
|||
|
||||
final class Gifts extends VKAPIRequestHandler
|
||||
{
|
||||
function get(int $user_id, int $count = 10, int $offset = 0)
|
||||
function get(int $user_id = NULL, int $count = 10, int $offset = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$i = 0;
|
||||
|
||||
$i += $offset;
|
||||
$server_url = ovk_scheme(true) . $_SERVER["HTTP_HOST"];
|
||||
|
||||
if($user_id)
|
||||
$user = (new UsersRepo)->get($user_id);
|
||||
else
|
||||
$user = $this->getUser();
|
||||
|
||||
if(!$user || $user->isDeleted())
|
||||
$this->fail(177, "Invalid user");
|
||||
|
@ -47,9 +50,9 @@ final class Gifts extends VKAPIRequestHandler
|
|||
"date" => $gift->sent->timestamp(),
|
||||
"gift" => [
|
||||
"id" => $gift->gift->getId(),
|
||||
"thumb_256" => $gift->gift->getImage(2),
|
||||
"thumb_96" => $gift->gift->getImage(2),
|
||||
"thumb_48" => $gift->gift->getImage(2)
|
||||
"thumb_256" => $server_url. $gift->gift->getImage(2),
|
||||
"thumb_96" => $server_url . $gift->gift->getImage(2),
|
||||
"thumb_48" => $server_url . $gift->gift->getImage(2)
|
||||
],
|
||||
"privacy" => 0
|
||||
];
|
||||
|
@ -125,12 +128,13 @@ final class Gifts extends VKAPIRequestHandler
|
|||
$this->fail(501, "Not implemented");
|
||||
}
|
||||
|
||||
# этих методов не было в ВК, но я их добавил чтобы можно было отобразить список подарков
|
||||
# в vk кстати называется gifts.getCatalog
|
||||
function getCategories(bool $extended = false, int $page = 1)
|
||||
{
|
||||
$cats = (new GiftsRepo)->getCategories($page);
|
||||
$categ = [];
|
||||
$i = 0;
|
||||
$server_url = ovk_scheme(true) . $_SERVER["HTTP_HOST"];
|
||||
|
||||
if(!OPENVK_ROOT_CONF['openvk']['preferences']['commerce'])
|
||||
$this->fail(105, "Commerce is disabled on this instance");
|
||||
|
@ -140,7 +144,7 @@ final class Gifts extends VKAPIRequestHandler
|
|||
"name" => $cat->getName(),
|
||||
"description" => $cat->getDescription(),
|
||||
"id" => $cat->getId(),
|
||||
"thumbnail" => $cat->getThumbnailURL(),
|
||||
"thumbnail" => $server_url . $cat->getThumbnailURL(),
|
||||
];
|
||||
|
||||
if($extended == true) {
|
||||
|
@ -178,7 +182,7 @@ final class Gifts extends VKAPIRequestHandler
|
|||
"name" => $gift->getName(),
|
||||
"image" => $gift->getImage(2),
|
||||
"usages_left" => (int)$gift->getUsagesLeft($this->getUser()),
|
||||
"price" => $gift->getPrice(), # голосов
|
||||
"price" => $gift->getPrice(),
|
||||
"is_free" => $gift->isFree()
|
||||
];
|
||||
}
|
||||
|
|
|
@ -88,6 +88,10 @@ final class Groups extends VKAPIRequestHandler
|
|||
case "can_suggest":
|
||||
$rClubs[$i]->can_suggest = !$usr->canBeModifiedBy($this->getUser()) && $usr->getWallType() == 2;
|
||||
break;
|
||||
case "background":
|
||||
$backgrounds = $usr->getBackDropPictureURLs();
|
||||
$rClubs[$i]->background = $backgrounds;
|
||||
break;
|
||||
# unstandard feild
|
||||
case "suggested_count":
|
||||
if($usr->getWallType() != 2) {
|
||||
|
@ -208,6 +212,10 @@ final class Groups extends VKAPIRequestHandler
|
|||
case "can_suggest":
|
||||
$response[$i]->can_suggest = !$clb->canBeModifiedBy($this->getUser()) && $clb->getWallType() == 2;
|
||||
break;
|
||||
case "background":
|
||||
$backgrounds = $clb->getBackDropPictureURLs();
|
||||
$response[$i]->background = $backgrounds;
|
||||
break;
|
||||
# unstandard feild
|
||||
case "suggested_count":
|
||||
if($clb->getWallType() != 2) {
|
||||
|
@ -244,23 +252,30 @@ final class Groups extends VKAPIRequestHandler
|
|||
return $response;
|
||||
}
|
||||
|
||||
function search(string $q, int $offset = 0, int $count = 100)
|
||||
function search(string $q, int $offset = 0, int $count = 100, string $fields = "screen_name,is_admin,is_member,is_advertiser,photo_50,photo_100,photo_200")
|
||||
{
|
||||
if($count > 100) {
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: count should be less or equal to 100");
|
||||
}
|
||||
|
||||
$clubs = new ClubsRepo;
|
||||
|
||||
$array = [];
|
||||
$find = $clubs->find($q);
|
||||
|
||||
foreach ($find as $group)
|
||||
foreach ($find->offsetLimit($offset, $count) as $group)
|
||||
$array[] = $group->getId();
|
||||
|
||||
if(!$array || sizeof($array) < 1) {
|
||||
return (object) [
|
||||
"count" => 0,
|
||||
"items" => [],
|
||||
];
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"count" => $find->size(),
|
||||
"items" => $this->getById(implode(',', $array), "", "is_admin,is_member,is_advertiser,photo_50,photo_100,photo_200", $offset, $count)
|
||||
/*
|
||||
* As there is no thing as "fields" by the original documentation
|
||||
* i'll just bake this param by the example shown here: https://dev.vk.com/method/groups.search
|
||||
*/
|
||||
"items" => $this->getById(implode(',', $array), "", $fields)
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -347,7 +362,10 @@ final class Groups extends VKAPIRequestHandler
|
|||
!empty($topics) ? $club->setEveryone_Can_Create_Topics($topics) : NULL;
|
||||
!empty($adminlist) ? $club->setAdministrators_List_Display($adminlist) : NULL;
|
||||
!empty($topicsAboveWall) ? $club->setDisplay_Topics_Above_Wall($topicsAboveWall) : NULL;
|
||||
|
||||
if (!$club->isHidingFromGlobalFeedEnforced()) {
|
||||
!empty($hideFromGlobalFeed) ? $club->setHide_From_Global_Feed($hideFromGlobalFeed) : NULL;
|
||||
}
|
||||
|
||||
in_array($audio, [0, 1]) ? $club->setEveryone_can_upload_audios($audio) : NULL;
|
||||
|
||||
|
|
|
@ -151,7 +151,6 @@ final class Users extends VKAPIRequestHandler
|
|||
}
|
||||
case "music":
|
||||
if(!$canView) {
|
||||
$response[$i]->music = "secret";
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -159,7 +158,6 @@ final class Users extends VKAPIRequestHandler
|
|||
break;
|
||||
case "movies":
|
||||
if(!$canView) {
|
||||
$response[$i]->movies = "secret";
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -167,7 +165,6 @@ final class Users extends VKAPIRequestHandler
|
|||
break;
|
||||
case "tv":
|
||||
if(!$canView) {
|
||||
$response[$i]->tv = "secret";
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -175,7 +172,6 @@ final class Users extends VKAPIRequestHandler
|
|||
break;
|
||||
case "books":
|
||||
if(!$canView) {
|
||||
$response[$i]->books = "secret";
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -183,7 +179,6 @@ final class Users extends VKAPIRequestHandler
|
|||
break;
|
||||
case "city":
|
||||
if(!$canView) {
|
||||
$response[$i]->city = "Воскресенск";
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -191,7 +186,6 @@ final class Users extends VKAPIRequestHandler
|
|||
break;
|
||||
case "interests":
|
||||
if(!$canView) {
|
||||
$response[$i]->interests = "secret";
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -199,7 +193,6 @@ final class Users extends VKAPIRequestHandler
|
|||
break;
|
||||
case "quotes":
|
||||
if(!$canView) {
|
||||
$response[$i]->quotes = "secret";
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -207,7 +200,6 @@ final class Users extends VKAPIRequestHandler
|
|||
break;
|
||||
case "email":
|
||||
if(!$canView) {
|
||||
$response[$i]->email = "secret@gmail.com";
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -215,7 +207,6 @@ final class Users extends VKAPIRequestHandler
|
|||
break;
|
||||
case "telegram":
|
||||
if(!$canView) {
|
||||
$response[$i]->telegram = "@secret";
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -223,7 +214,6 @@ final class Users extends VKAPIRequestHandler
|
|||
break;
|
||||
case "about":
|
||||
if(!$canView) {
|
||||
$response[$i]->about = "secret";
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -231,7 +221,6 @@ final class Users extends VKAPIRequestHandler
|
|||
break;
|
||||
case "rating":
|
||||
if(!$canView) {
|
||||
$response[$i]->rating = 22;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -240,12 +229,43 @@ final class Users extends VKAPIRequestHandler
|
|||
case "counters":
|
||||
$response[$i]->counters = (object) [
|
||||
"friends_count" => $usr->getFriendsCount(),
|
||||
"photos_count" => (new Albums)->getUserPhotosCount($usr),
|
||||
"photos_count" => (new Photos)->getUserPhotosCount($usr),
|
||||
"videos_count" => (new Videos)->getUserVideosCount($usr),
|
||||
"audios_count" => (new Audios)->getUserCollectionSize($usr),
|
||||
"notes_count" => (new Notes)->getUserNotesCount($usr)
|
||||
];
|
||||
break;
|
||||
case "correct_counters":
|
||||
$response[$i]->counters = (object) [
|
||||
"friends" => $usr->getFriendsCount(),
|
||||
"photos" => (new Photos)->getUserPhotosCount($usr),
|
||||
"videos" => (new Videos)->getUserVideosCount($usr),
|
||||
"audios" => (new Audios)->getUserCollectionSize($usr),
|
||||
"notes" => (new Notes)->getUserNotesCount($usr),
|
||||
"groups" => $usr->getClubCount(),
|
||||
"online_friends" => $usr->getFriendsOnlineCount(),
|
||||
];
|
||||
break;
|
||||
case "guid":
|
||||
$response[$i]->guid = $usr->getChandlerGUID();
|
||||
break;
|
||||
case 'background':
|
||||
$backgrounds = $usr->getBackDropPictureURLs();
|
||||
$response[$i]->background = $backgrounds;
|
||||
break;
|
||||
case 'reg_date':
|
||||
if(!$canView) {
|
||||
break;
|
||||
}
|
||||
|
||||
$response[$i]->reg_date = $usr->getRegistrationTime()->timestamp();
|
||||
break;
|
||||
case 'is_dead':
|
||||
$response[$i]->is_dead = $usr->isDead();
|
||||
break;
|
||||
case 'nickname':
|
||||
$response[$i]->nickname = $usr->getPseudo();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -297,89 +317,90 @@ final class Users extends VKAPIRequestHandler
|
|||
int $count = 100,
|
||||
string $city = "",
|
||||
string $hometown = "",
|
||||
int $sex = 2,
|
||||
int $status = 0, # это про marital status
|
||||
int $sex = 3,
|
||||
int $status = 0, # marital_status
|
||||
bool $online = false,
|
||||
# дальше идут параметры которых нету в vkapi но есть на сайте
|
||||
string $profileStatus = "", # а это уже нормальный статус
|
||||
# non standart params:
|
||||
int $sort = 0,
|
||||
int $before = 0,
|
||||
int $politViews = 0,
|
||||
int $after = 0,
|
||||
string $interests = "",
|
||||
int $polit_views = 0,
|
||||
string $fav_music = "",
|
||||
string $fav_films = "",
|
||||
string $fav_shows = "",
|
||||
string $fav_books = "",
|
||||
string $fav_quotes = ""
|
||||
string $fav_books = ""
|
||||
)
|
||||
{
|
||||
if($count > 100) {
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: count should be less or equal to 100");
|
||||
}
|
||||
|
||||
$users = new UsersRepo;
|
||||
|
||||
$sortg = "id ASC";
|
||||
|
||||
$nfilds = $fields;
|
||||
|
||||
switch($sort) {
|
||||
case 0:
|
||||
$sortg = "id DESC";
|
||||
break;
|
||||
case 1:
|
||||
$sortg = "id ASC";
|
||||
break;
|
||||
case 2:
|
||||
$sortg = "first_name DESC";
|
||||
break;
|
||||
case 3:
|
||||
$sortg = "first_name ASC";
|
||||
break;
|
||||
case 4:
|
||||
$sortg = "rating DESC";
|
||||
|
||||
if(!str_contains($nfilds, "rating")) {
|
||||
$nfilds .= "rating";
|
||||
}
|
||||
|
||||
break;
|
||||
case 5:
|
||||
$sortg = "rating DESC";
|
||||
|
||||
if(!str_contains($nfilds, "rating")) {
|
||||
$nfilds .= "rating";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$array = [];
|
||||
|
||||
$parameters = [
|
||||
"city" => !empty($city) ? $city : NULL,
|
||||
"hometown" => !empty($hometown) ? $hometown : NULL,
|
||||
"gender" => $sex < 2 ? $sex : NULL,
|
||||
"maritalstatus" => (bool)$status ? $status : NULL,
|
||||
"politViews" => (bool)$politViews ? $politViews : NULL,
|
||||
"is_online" => $online ? 1 : NULL,
|
||||
"status" => !empty($profileStatus) ? $profileStatus : NULL,
|
||||
"before" => $before != 0 ? $before : NULL,
|
||||
"after" => $after != 0 ? $after : NULL,
|
||||
"interests" => !empty($interests) ? $interests : NULL,
|
||||
"fav_music" => !empty($fav_music) ? $fav_music : NULL,
|
||||
"fav_films" => !empty($fav_films) ? $fav_films : NULL,
|
||||
"fav_shows" => !empty($fav_shows) ? $fav_shows : NULL,
|
||||
"fav_books" => !empty($fav_books) ? $fav_books : NULL,
|
||||
"fav_quotes" => !empty($fav_quotes) ? $fav_quotes : NULL,
|
||||
"doNotSearchPrivate" => true,
|
||||
$output_sort = ['type' => 'id', 'invert' => false];
|
||||
$output_params = [
|
||||
"ignore_private" => true,
|
||||
];
|
||||
|
||||
$find = $users->find($q, $parameters, $sortg);
|
||||
switch($sort) {
|
||||
default:
|
||||
case 0:
|
||||
$output_sort = ['type' => 'id', 'invert' => false];
|
||||
break;
|
||||
case 1:
|
||||
$output_sort = ['type' => 'id', 'invert' => true];
|
||||
break;
|
||||
case 4:
|
||||
$output_sort = ['type' => 'rating', 'invert' => false];
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($find as $user)
|
||||
if(!empty($city))
|
||||
$output_params['city'] = $city;
|
||||
|
||||
if(!empty($hometown))
|
||||
$output_params['hometown'] = $hometown;
|
||||
|
||||
if($sex != 3)
|
||||
$output_params['gender'] = $sex;
|
||||
|
||||
if($status != 0)
|
||||
$output_params['marital_status'] = $status;
|
||||
|
||||
if($polit_views != 0)
|
||||
$output_params['polit_views'] = $polit_views;
|
||||
|
||||
if(!empty($interests))
|
||||
$output_params['interests'] = $interests;
|
||||
|
||||
if(!empty($fav_music))
|
||||
$output_params['fav_music'] = $fav_music;
|
||||
|
||||
if(!empty($fav_films))
|
||||
$output_params['fav_films'] = $fav_films;
|
||||
|
||||
if(!empty($fav_shows))
|
||||
$output_params['fav_shows'] = $fav_shows;
|
||||
|
||||
if(!empty($fav_books))
|
||||
$output_params['fav_books'] = $fav_books;
|
||||
|
||||
if($online)
|
||||
$output_params['is_online'] = 1;
|
||||
|
||||
$array = [];
|
||||
$find = $users->find($q, $output_params, $output_sort);
|
||||
|
||||
foreach ($find->offsetLimit($offset, $count) as $user)
|
||||
$array[] = $user->getId();
|
||||
|
||||
if(!$array || sizeof($array) < 1) {
|
||||
return (object) [
|
||||
"count" => 0,
|
||||
"items" => [],
|
||||
];
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"count" => $find->size(),
|
||||
"items" => $this->get(implode(',', $array), $nfilds, $offset, $count)
|
||||
"items" => $this->get(implode(',', $array), $fields)
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ final class Utils extends VKAPIRequestHandler
|
|||
"object_id" => (int) substr($screen_name, strlen("club")),
|
||||
"type" => "group"
|
||||
];
|
||||
}
|
||||
} else $this->fail(104, "Not found");
|
||||
} else {
|
||||
$user = (new Users)->getByShortURL($screen_name);
|
||||
if($user) {
|
||||
|
@ -40,7 +40,16 @@ final class Utils extends VKAPIRequestHandler
|
|||
];
|
||||
}
|
||||
|
||||
return (object) [];
|
||||
$this->fail(104, "Not found");
|
||||
}
|
||||
}
|
||||
|
||||
function resolveGuid(string $guid): object
|
||||
{
|
||||
$user = (new Users)->getByChandlerUserId($guid);
|
||||
if (is_null($user))
|
||||
$this->fail(104, "Not found");
|
||||
|
||||
return $user->toVkApiStruct($this->getUser());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,4 +60,60 @@ final class Video extends VKAPIRequestHandler
|
|||
];
|
||||
}
|
||||
}
|
||||
|
||||
function search(string $q = '', int $sort = 0, int $offset = 0, int $count = 10, bool $extended = false, string $fields = ''): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$params = [];
|
||||
$db_sort = ['type' => 'id', 'invert' => false];
|
||||
$videos = (new VideosRepo)->find($q, $params, $db_sort);
|
||||
$items = iterator_to_array($videos->offsetLimit($offset, $count));
|
||||
$count = $videos->size();
|
||||
|
||||
$return_items = [];
|
||||
$profiles = [];
|
||||
$groups = [];
|
||||
foreach($items as $item)
|
||||
$return_item = $item->getApiStructure($this->getUser());
|
||||
$return_item = $return_item->video;
|
||||
$return_items[] = $return_item;
|
||||
|
||||
if($return_item['owner_id']) {
|
||||
if($return_item['owner_id'] > 0)
|
||||
$profiles[] = $return_item['owner_id'];
|
||||
else
|
||||
$groups[] = abs($return_item['owner_id']);
|
||||
}
|
||||
|
||||
if($extended) {
|
||||
$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" => $count,
|
||||
"items" => $return_items,
|
||||
"profiles" => $profilesFormatted,
|
||||
"groups" => $groupsFormatted,
|
||||
];
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"count" => $count,
|
||||
"items" => $return_items,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,65 +126,41 @@ final class Wall extends VKAPIRequestHandler
|
|||
else
|
||||
$profiles[] = $attachment->getOwner()->getId();
|
||||
|
||||
$post_source = [];
|
||||
|
||||
if($attachment->getPlatform(true) === NULL) {
|
||||
$post_source = (object)["type" => "vk"];
|
||||
} else {
|
||||
$post_source = (object)[
|
||||
"type" => "api",
|
||||
"platform" => $attachment->getPlatform(true)
|
||||
];
|
||||
}
|
||||
|
||||
$repost[] = [
|
||||
"id" => $attachment->getVirtualId(),
|
||||
"owner_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(),
|
||||
"from_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(),
|
||||
"date" => $attachment->getPublicationTime()->timestamp(),
|
||||
"post_type" => "post",
|
||||
"post_type" => $attachment->getVkApiType(),
|
||||
"text" => $attachment->getText(false),
|
||||
"attachments" => $repostAttachments,
|
||||
"post_source" => $post_source,
|
||||
"post_source" => $attachment->getPostSourceInfo(),
|
||||
];
|
||||
|
||||
if ($attachment->getVirtualId() > 0)
|
||||
$profiles[] = $attachment->getVirtualId();
|
||||
if ($attachment->getTargetWall() > 0)
|
||||
$profiles[] = $attachment->getTargetWall();
|
||||
else
|
||||
$groups[] = $attachment->getVirtualId();
|
||||
$groups[] = abs($attachment->getTargetWall());
|
||||
if($post->isSigned())
|
||||
$profiles[] = $attachment->getOwner()->getId();
|
||||
}
|
||||
}
|
||||
|
||||
$post_source = [];
|
||||
|
||||
if($post->getPlatform(true) === NULL) {
|
||||
$post_source = (object)["type" => "vk"];
|
||||
} else {
|
||||
$post_source = (object)[
|
||||
"type" => "api",
|
||||
"platform" => $post->getPlatform(true)
|
||||
];
|
||||
}
|
||||
|
||||
$postType = "post";
|
||||
$signerId = NULL;
|
||||
if($post->getSuggestionType() != 0)
|
||||
$postType = "suggest";
|
||||
|
||||
|
||||
if($post->isSigned()) {
|
||||
$actualAuthor = $post->getOwner(false);
|
||||
$signerId = $actualAuthor->getId();
|
||||
}
|
||||
|
||||
$items[] = (object)[
|
||||
# TODO "can_pin", "copy_history" и прочее не должны возвращаться, если равны null или false
|
||||
# Ну и ещё всё надо перенести в toVkApiStruct, а то слишком много дублированного кода
|
||||
|
||||
$post_temp_obj = (object)[
|
||||
"id" => $post->getVirtualId(),
|
||||
"from_id" => $from_id,
|
||||
"owner_id" => $post->getTargetWall(),
|
||||
"date" => $post->getPublicationTime()->timestamp(),
|
||||
"post_type" => $postType,
|
||||
"post_type" => $post->getVkApiType(),
|
||||
"text" => $post->getText(false),
|
||||
"copy_history" => $repost,
|
||||
"can_edit" => $post->canBeEditedBy($this->getUser()),
|
||||
|
@ -195,8 +171,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
"is_pinned" => $post->isPinned(),
|
||||
"is_explicit" => $post->isExplicit(),
|
||||
"attachments" => $attachments,
|
||||
"post_source" => $post_source,
|
||||
"signer_id" => $signerId,
|
||||
"post_source" => $post->getPostSourceInfo(),
|
||||
"comments" => (object)[
|
||||
"count" => $post->getCommentsCount(),
|
||||
"can_post" => 1
|
||||
|
@ -213,6 +188,14 @@ final class Wall extends VKAPIRequestHandler
|
|||
]
|
||||
];
|
||||
|
||||
if($signerId)
|
||||
$post_temp_obj->signer_id = $signerId;
|
||||
|
||||
if($post->isDeactivationMessage())
|
||||
$post_temp_obj->final_post = 1;
|
||||
|
||||
$items[] = $post_temp_obj;
|
||||
|
||||
if ($from_id > 0)
|
||||
$profiles[] = $from_id;
|
||||
else
|
||||
|
@ -332,17 +315,6 @@ final class Wall extends VKAPIRequestHandler
|
|||
else
|
||||
$profiles[] = $attachment->getOwner()->getId();
|
||||
|
||||
$post_source = [];
|
||||
|
||||
if($attachment->getPlatform(true) === NULL) {
|
||||
$post_source = (object)["type" => "vk"];
|
||||
} else {
|
||||
$post_source = (object)[
|
||||
"type" => "api",
|
||||
"platform" => $attachment->getPlatform(true)
|
||||
];
|
||||
}
|
||||
|
||||
$repost[] = [
|
||||
"id" => $attachment->getVirtualId(),
|
||||
"owner_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(),
|
||||
|
@ -351,47 +323,29 @@ final class Wall extends VKAPIRequestHandler
|
|||
"post_type" => "post",
|
||||
"text" => $attachment->getText(false),
|
||||
"attachments" => $repostAttachments,
|
||||
"post_source" => $post_source,
|
||||
"post_source" => $attachment->getPostSourceInfo(),
|
||||
];
|
||||
|
||||
if ($attachment->getVirtualId() > 0)
|
||||
$profiles[] = $attachment->getVirtualId();
|
||||
if ($attachment->getTargetWall() > 0)
|
||||
$profiles[] = $attachment->getTargetWall();
|
||||
else
|
||||
$groups[] = $attachment->getVirtualId();
|
||||
$groups[] = abs($attachment->getTargetWall());
|
||||
if($post->isSigned())
|
||||
$profiles[] = $attachment->getOwner()->getId();
|
||||
}
|
||||
}
|
||||
|
||||
$post_source = [];
|
||||
|
||||
if($post->getPlatform(true) === NULL) {
|
||||
$post_source = (object)["type" => "vk"];
|
||||
} else {
|
||||
$post_source = (object)[
|
||||
"type" => "api",
|
||||
"platform" => $post->getPlatform(true)
|
||||
];
|
||||
}
|
||||
|
||||
# TODO: $post->getVkApiType()
|
||||
$postType = "post";
|
||||
$signerId = NULL;
|
||||
if($post->getSuggestionType() != 0)
|
||||
$postType = "suggest";
|
||||
|
||||
|
||||
if($post->isSigned()) {
|
||||
$actualAuthor = $post->getOwner(false);
|
||||
$signerId = $actualAuthor->getId();
|
||||
}
|
||||
|
||||
$items[] = (object)[
|
||||
$post_temp_obj = (object)[
|
||||
"id" => $post->getVirtualId(),
|
||||
"from_id" => $from_id,
|
||||
"owner_id" => $post->getTargetWall(),
|
||||
"date" => $post->getPublicationTime()->timestamp(),
|
||||
"post_type" => $postType,
|
||||
"post_type" => $post->getVkApiType(),
|
||||
"text" => $post->getText(false),
|
||||
"copy_history" => $repost,
|
||||
"can_edit" => $post->canBeEditedBy($this->getUser()),
|
||||
|
@ -401,8 +355,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
"is_archived" => false,
|
||||
"is_pinned" => $post->isPinned(),
|
||||
"is_explicit" => $post->isExplicit(),
|
||||
"post_source" => $post_source,
|
||||
"signer_id" => $signerId,
|
||||
"post_source" => $post->getPostSourceInfo(),
|
||||
"attachments" => $attachments,
|
||||
"comments" => (object)[
|
||||
"count" => $post->getCommentsCount(),
|
||||
|
@ -420,6 +373,14 @@ final class Wall extends VKAPIRequestHandler
|
|||
]
|
||||
];
|
||||
|
||||
if($signerId)
|
||||
$post_temp_obj->signer_id = $signerId;
|
||||
|
||||
if($post->isDeactivationMessage())
|
||||
$post_temp_obj->final_post = 1;
|
||||
|
||||
$items[] = $post_temp_obj;
|
||||
|
||||
if ($from_id > 0)
|
||||
$profiles[] = $from_id;
|
||||
else
|
||||
|
@ -792,6 +753,9 @@ final class Wall extends VKAPIRequestHandler
|
|||
]
|
||||
];
|
||||
|
||||
if($comment->isFromPostAuthor($post))
|
||||
$item['is_from_post_author'] = true;
|
||||
|
||||
if($need_likes == true)
|
||||
$item['likes'] = [
|
||||
"can_like" => 1,
|
||||
|
@ -875,6 +839,9 @@ final class Wall extends VKAPIRequestHandler
|
|||
]
|
||||
];
|
||||
|
||||
if($comment->isFromPostAuthor())
|
||||
$item['is_from_post_author'] = true;
|
||||
|
||||
if($extended == true)
|
||||
$profiles[] = $comment->getOwner()->getId();
|
||||
|
||||
|
@ -890,8 +857,6 @@ final class Wall extends VKAPIRequestHandler
|
|||
$response['profiles'] = (!empty($profiles) ? (new Users)->get(implode(',', $profiles), $fields) : []);
|
||||
}
|
||||
|
||||
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ exceptions. It is still a work-in-progress functionality.
|
|||
**Note**: requests to API are routed through
|
||||
openvk.Web.Presenters.VKAPIPresenter, this dir contains only handlers.
|
||||
|
||||
[Documentation for API clients](https://docs.openvk.uk/openvk_engine/api/description/)
|
||||
[Documentation for API clients](https://docs.ovk.to/openvk_engine/api/description/)
|
||||
|
||||
## Implementing API methods
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ class Audio extends Media
|
|||
|
||||
# Taken from winamp :D
|
||||
const genres = [
|
||||
'Blues','Big Band','Classic Rock','Chorus','Country','Easy Listening','Dance','Acoustic','Disco','Humour','Funk','Speech','Grunge','Chanson','Hip-Hop','Opera','Jazz','Chamber Music','Metal','Sonata','New Age','Symphony','Oldies','Booty Bass','Other','Primus','Pop','Porn Groove','R&B','Satire','Rap','Slow Jam','Reggae','Club','Rock','Tango','Techno','Samba','Industrial','Folklore','Alternative','Ballad','Ska','Power Ballad','Death Metal','Rhythmic Soul','Pranks','Freestyle','Soundtrack','Duet','Euro-Techno','Punk Rock','Ambient','Drum Solo','Trip-Hop','A Cappella','Vocal','Euro-House','Jazz+Funk','Dance Hall','Fusion','Goa','Trance','Drum & Bass','Classical','Club-House','Instrumental','Hardcore','Acid','Terror','House','Indie','Game','BritPop','Sound Clip','Negerpunk','Gospel','Polsk Punk','Noise','Beat','AlternRock','Christian Gangsta Rap','Bass','Heavy Metal','Soul','Black Metal','Punk','Crossover','Space','Contemporary Christian','Meditative','Christian Rock','Instrumental Pop','Merengue','Instrumental Rock','Salsa','Ethnic','Thrash Metal','Gothic','Anime','Darkwave','JPop','Techno-Industrial','Synthpop','Electronic','Abstract','Pop-Folk','Art Rock','Eurodance','Baroque','Dream','Bhangra','Southern Rock','Big Beat','Comedy','Breakbeat','Cult','Chillout','Gangsta Rap','Downtempo','Top 40','Dub','Christian Rap','EBM','Pop / Funk','Eclectic','Jungle','Electro','Native American','Electroclash','Cabaret','Emo','New Wave','Experimental','Psychedelic','Garage','Rave','Global','Showtunes','IDM','Trailer','Illbient','Lo-Fi','Industro-Goth','Tribal','Jam Band','Acid Punk','Krautrock','Acid Jazz','Leftfield','Polka','Lounge','Retro','Math Rock','Musical','New Romantic','Rock & Roll','Nu-Breakz','Hard Rock','Post-Punk','Folk','Post-Rock','Folk-Rock','Psytrance','National Folk','Shoegaze','Swing','Space Rock','Fast Fusion','Trop Rock','Bebob','World Music','Latin','Neoclassical','Revival','Audiobook','Celtic','Audio Theatre','Bluegrass','Neue Deutsche Welle','Avantgarde','Podcast','Gothic Rock','Indie Rock','Progressive Rock','G-Funk','Psychedelic Rock','Dubstep','Symphonic Rock','Garage Rock','Slow Rock','Psybient','Psychobilly','Touhou'
|
||||
'A Cappella', 'Abstract', 'Acid', 'Acid Jazz', 'Acid Punk', 'Acoustic', 'AlternRock', 'Alternative', 'Ambient', 'Anime', 'Art Rock', 'Audio Theatre', 'Audiobook', 'Avantgarde', 'Ballad', 'Baroque', 'Bass', 'Beat', 'Bebob', 'Bhangra', 'Big Band', 'Big Beat', 'Black Metal', 'Bluegrass', 'Blues', 'Booty Bass', 'Breakbeat', 'BritPop', 'Cabaret', 'Celtic', 'Chamber Music', 'Chanson', 'Chillout', 'Chorus', 'Christian Gangsta Rap', 'Christian Rap', 'Christian Rock', 'Classic Rock', 'Classical', 'Club', 'Club-House', 'Comedy', 'Contemporary Christian', 'Country', 'Crossover', 'Cult', 'Dance', 'Dance Hall', 'Darkwave', 'Death Metal', 'Disco', 'Downtempo', 'Dream', 'Drum & Bass', 'Drum Solo', 'Dub', 'Dubstep', 'Duet', 'EBM', 'Easy Listening', 'Eclectic', 'Electro', 'Electroclash', 'Electronic', 'Emo', 'Ethnic', 'Euro-House', 'Euro-Techno', 'Eurodance', 'Experimental', 'Fast Fusion', 'Folk', 'Folk-Rock', 'Folklore', 'Freestyle', 'Funk', 'Fusion', 'G-Funk', 'Game', 'Gangsta Rap', 'Garage', 'Garage Rock', 'Global', 'Goa', 'Gospel', 'Gothic', 'Gothic Rock', 'Grunge', 'Hard Rock', 'Hardcore', 'Heavy Metal', 'Hip-Hop', 'House', 'Humour', 'IDM', 'Illbient', 'Indie', 'Indie Rock', 'Industrial', 'Industro-Goth', 'Instrumental', 'Instrumental Pop', 'Instrumental Rock', 'JPop', 'Jam Band', 'Jazz', 'Jazz+Funk', 'Jungle', 'Krautrock', 'Latin', 'Leftfield', 'Lo-Fi', 'Lounge', 'Math Rock', 'Meditative', 'Merengue', 'Metal', 'Musical', 'National Folk', 'Native American', 'Negerpunk', 'Neoclassical', 'Neue Deutsche Welle', 'New Age', 'New Romantic', 'New Wave', 'Noise', 'Nu-Breakz', 'Oldies', 'Opera', 'Other', 'Podcast', 'Polka', 'Polsk Punk', 'Pop', 'Pop / Funk', 'Pop-Folk', 'Porn Groove', 'Post-Punk', 'Post-Rock', 'Power Ballad', 'Pranks', 'Primus', 'Progressive Rock', 'Psybient', 'Psychedelic', 'Psychedelic Rock', 'Psychobilly', 'Psytrance', 'Punk', 'Punk Rock', 'R&B', 'Rap', 'Rave', 'Reggae', 'Retro', 'Revival', 'Rhythmic Soul', 'Rock', 'Rock & Roll', 'Salsa', 'Samba', 'Satire', 'Shoegaze', 'Showtunes', 'Ska', 'Slow Jam', 'Slow Rock', 'Sonata', 'Soul', 'Sound Clip', 'Soundtrack', 'Southern Rock', 'Space', 'Space Rock', 'Speech', 'Swing', 'Symphonic Rock', 'Symphony', 'Synthpop', 'Tango', 'Techno', 'Techno-Industrial', 'Terror', 'Thrash Metal', 'Top 40', 'Touhou', 'Trailer', 'Trance', 'Tribal', 'Trip-Hop', 'Trop Rock', 'Vocal', 'World Music'
|
||||
];
|
||||
|
||||
# Taken from: https://web.archive.org/web/20220322153107/https://dev.vk.com/reference/objects/audio-genres
|
||||
|
@ -152,6 +152,11 @@ class Audio extends Media
|
|||
return $this->getPerformer() . " — " . $this->getTitle();
|
||||
}
|
||||
|
||||
function getDownloadName(): string
|
||||
{
|
||||
return preg_replace('/[\\/:*?"<>|]/', '_', str_replace(' ', '_', $this->getName()));
|
||||
}
|
||||
|
||||
function getGenre(): ?string
|
||||
{
|
||||
return $this->getRecord()->genre;
|
||||
|
|
|
@ -152,6 +152,11 @@ class Club extends RowModel
|
|||
return (bool) $this->getRecord()->hide_from_global_feed;
|
||||
}
|
||||
|
||||
function isHidingFromGlobalFeedEnforced(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->enforce_hiding_from_global_feed;
|
||||
}
|
||||
|
||||
function getType(): int
|
||||
{
|
||||
return $this->getRecord()->type;
|
||||
|
@ -432,7 +437,7 @@ class Club extends RowModel
|
|||
return (new \openvk\Web\Models\Repositories\Audios)->getClubCollectionSize($this);
|
||||
}
|
||||
|
||||
function toVkApiStruct(?User $user = NULL): object
|
||||
function toVkApiStruct(?User $user = NULL, string $fields = ''): object
|
||||
{
|
||||
$res = (object) [];
|
||||
|
||||
|
|
|
@ -104,6 +104,22 @@ class Comment extends Post
|
|||
return $this->getTarget()->canBeViewedBy($user);
|
||||
}
|
||||
|
||||
function isFromPostAuthor($target = NULL)
|
||||
{
|
||||
if(!$target)
|
||||
$target = $this->getTarget();
|
||||
|
||||
$target_owner = $target->getOwner();
|
||||
$comment_owner = $this->getOwner();
|
||||
|
||||
if($target_owner->getRealId() === $comment_owner->getRealId())
|
||||
return true;
|
||||
|
||||
# TODO: make it work with signer_id
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function toNotifApiStruct()
|
||||
{
|
||||
$res = (object)[];
|
||||
|
@ -124,4 +140,31 @@ class Comment extends Post
|
|||
|
||||
return $user->getId() == $this->getOwner(false)->getId();
|
||||
}
|
||||
|
||||
function getTargetURL(): string
|
||||
{
|
||||
$target = $this->getTarget();
|
||||
$target_name = 'wall';
|
||||
|
||||
if(!$target) {
|
||||
return '/404';
|
||||
}
|
||||
|
||||
switch(get_class($target)) {
|
||||
case 'openvk\Web\Models\Entities\Note':
|
||||
$target_name = 'note';
|
||||
break;
|
||||
case 'openvk\Web\Models\Entities\Photo':
|
||||
$target_name = 'photo';
|
||||
break;
|
||||
case 'openvk\Web\Models\Entities\Video':
|
||||
$target_name = 'video';
|
||||
break;
|
||||
case 'openvk\Web\Models\Entities\Topic':
|
||||
$target_name = 'topic';
|
||||
break;
|
||||
}
|
||||
|
||||
return $target_name . $target->getPrettyId();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ class Message extends RowModel
|
|||
$dateTime = new DateTime($this->getRecord()->created);
|
||||
|
||||
if($dateTime->format("%d.%m.%y") == ovk_strftime_safe("%d.%m.%y", time())) {
|
||||
return $dateTime->format("%T %p");
|
||||
return $dateTime->format("%T");
|
||||
} else {
|
||||
return $dateTime->format("%d.%m.%y");
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ class Photo extends Media
|
|||
return true;
|
||||
}
|
||||
|
||||
function crop(real $left, real $top, real $width, real $height): void
|
||||
function crop(float $left, float $top, float $width, float $height): void
|
||||
{
|
||||
if(isset($this->changes["hash"]))
|
||||
$hash = $this->changes["hash"];
|
||||
|
|
|
@ -42,6 +42,21 @@ class Playlist extends MediaCollection
|
|||
return $this->getRecord()->length;
|
||||
}
|
||||
|
||||
function fetchClassic(int $offset = 0, ?int $limit = NULL): \Traversable
|
||||
{
|
||||
$related = $this->getRecord()->related("$this->relTableName.collection")
|
||||
->limit($limit ?? OPENVK_DEFAULT_PER_PAGE, $offset)
|
||||
->order("index ASC");
|
||||
|
||||
foreach($related as $rel) {
|
||||
$media = $rel->ref($this->entityTableName, "media");
|
||||
if(!$media)
|
||||
continue;
|
||||
|
||||
yield new $this->entityClassName($media);
|
||||
}
|
||||
}
|
||||
|
||||
function getAudios(int $offset = 0, ?int $limit = NULL, ?int $shuffleSeed = NULL): \Traversable
|
||||
{
|
||||
if(!$shuffleSeed) {
|
||||
|
@ -162,6 +177,7 @@ class Playlist extends MediaCollection
|
|||
"bookmarked" => $this->isBookmarkedBy($user),
|
||||
"listens" => $this->getListens(),
|
||||
"cover_url" => $this->getCoverURL(),
|
||||
"searchable" => !$this->isUnlisted(),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -200,6 +216,11 @@ class Playlist extends MediaCollection
|
|||
return $this->getRecord()->cover_photo_id;
|
||||
}
|
||||
|
||||
function getCoverPhoto(): ?Photo
|
||||
{
|
||||
return (new Photos)->get((int) $this->getRecord()->cover_photo_id);
|
||||
}
|
||||
|
||||
function canBeModifiedBy(User $user): bool
|
||||
{
|
||||
if(!$user)
|
||||
|
@ -253,4 +274,9 @@ class Playlist extends MediaCollection
|
|||
|
||||
return implode(" • ", $props);
|
||||
}
|
||||
|
||||
function isUnlisted(): bool
|
||||
{
|
||||
return (bool)$this->getRecord()->unlisted;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,6 +134,10 @@ class Post extends Postable
|
|||
return 'iphone';
|
||||
break;
|
||||
|
||||
case 'windows_phone':
|
||||
return 'wphone';
|
||||
break;
|
||||
|
||||
case 'vika_touch': // кика хохотач ахахахаххахахахахах
|
||||
case 'vk4me':
|
||||
return 'mobile';
|
||||
|
@ -176,6 +180,31 @@ class Post extends Postable
|
|||
];
|
||||
}
|
||||
|
||||
function getPostSourceInfo(): array
|
||||
{
|
||||
$post_source = ["type" => "vk"];
|
||||
if($this->getPlatform(true) !== NULL) {
|
||||
$post_source = [
|
||||
"type" => "api",
|
||||
"platform" => $this->getPlatform(true)
|
||||
];
|
||||
}
|
||||
|
||||
if($this->isUpdateAvatarMessage())
|
||||
$post_source['data'] = 'profile_photo';
|
||||
|
||||
return $post_source;
|
||||
}
|
||||
|
||||
function getVkApiType(): string
|
||||
{
|
||||
$type = 'post';
|
||||
if($this->getSuggestionType() != 0)
|
||||
$type = 'suggest';
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
function pin(): void
|
||||
{
|
||||
DB::i()
|
||||
|
|
|
@ -80,7 +80,7 @@ class Report extends RowModel
|
|||
|
||||
function getAuthor(): RowModel
|
||||
{
|
||||
return (new Posts)->get($this->getContentId())->getOwner();
|
||||
return $this->getContentObject()->getOwner();
|
||||
}
|
||||
|
||||
function getReportAuthor(): User
|
||||
|
|
|
@ -123,7 +123,7 @@ trait TRichText
|
|||
$text = preg_replace_callback("%([\n\r\s]|^)(\#([\p{L}_0-9][\p{L}_0-9\(\)\-\']+[\p{L}_0-9\(\)]|[\p{L}_0-9]{1,2}))%Xu", function($m) {
|
||||
$slug = rawurlencode($m[3]);
|
||||
|
||||
return "$m[1]<a href='/feed/hashtag/$slug'>$m[2]</a>";
|
||||
return "$m[1]<a href='/search?section=posts&q=%23$slug'>$m[2]</a>";
|
||||
}, $text);
|
||||
|
||||
$text = $this->formatEmojis($text);
|
||||
|
|
|
@ -39,4 +39,25 @@ trait TSubscribable
|
|||
$sub->delete();
|
||||
return false;
|
||||
}
|
||||
|
||||
function changeFlags(User $user, int $flags, bool $reverse): bool
|
||||
{
|
||||
$ctx = DatabaseConnection::i()->getContext();
|
||||
$data = [
|
||||
"follower" => $reverse ? $this->getId() : $user->getId(),
|
||||
"model" => static::class,
|
||||
"target" => $reverse ? $user->getId() : $this->getId(),
|
||||
];
|
||||
$sub = $ctx->table("subscriptions")->where($data);
|
||||
|
||||
bdump($data);
|
||||
|
||||
if (!$sub)
|
||||
return false;
|
||||
|
||||
$sub->update([
|
||||
'flags' => $flags
|
||||
]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -592,6 +592,16 @@ class User extends RowModel
|
|||
return $this->_abstractRelationCount("get-followers");
|
||||
}
|
||||
|
||||
function getRequests(int $page = 1, int $limit = 6): \Traversable
|
||||
{
|
||||
return $this->_abstractRelationGenerator("get-requests", $page, $limit);
|
||||
}
|
||||
|
||||
function getRequestsCount(): int
|
||||
{
|
||||
return $this->_abstractRelationCount("get-requests");
|
||||
}
|
||||
|
||||
function getSubscriptions(int $page = 1, int $limit = 6): \Traversable
|
||||
{
|
||||
return $this->_abstractRelationGenerator("get-subscriptions-user", $page, $limit);
|
||||
|
@ -1214,6 +1224,11 @@ class User extends RowModel
|
|||
return (bool) $this->getRecord()->activated;
|
||||
}
|
||||
|
||||
function isDead(): bool
|
||||
{
|
||||
return $this->onlineStatus() == 2;
|
||||
}
|
||||
|
||||
function getUnbanTime(): ?string
|
||||
{
|
||||
$ban = (new Bans)->get((int) $this->getRecord()->block_reason);
|
||||
|
@ -1306,17 +1321,22 @@ class User extends RowModel
|
|||
return true;
|
||||
}
|
||||
|
||||
function isClosed()
|
||||
function isClosed(): bool
|
||||
{
|
||||
return (bool) $this->getProfileType();
|
||||
}
|
||||
|
||||
function isHideFromGlobalFeedEnabled(): bool
|
||||
{
|
||||
return $this->isClosed();
|
||||
}
|
||||
|
||||
function getRealId()
|
||||
{
|
||||
return $this->getId();
|
||||
}
|
||||
|
||||
function toVkApiStruct(?User $user = NULL): object
|
||||
function toVkApiStruct(?User $user = NULL, string $fields = ''): object
|
||||
{
|
||||
$res = (object) [];
|
||||
|
||||
|
@ -1328,12 +1348,21 @@ class User extends RowModel
|
|||
$res->photo_100 = $this->getAvatarURL("tiny");
|
||||
$res->photo_200 = $this->getAvatarURL("normal");
|
||||
$res->photo_id = !is_null($this->getAvatarPhoto()) ? $this->getAvatarPhoto()->getPrettyId() : NULL;
|
||||
# TODO: Perenesti syuda vsyo ostalnoyie
|
||||
|
||||
$res->is_closed = $this->isClosed();
|
||||
|
||||
if(!is_null($user)) {
|
||||
if(!is_null($user))
|
||||
$res->can_access_closed = (bool)$this->canBeViewedBy($user);
|
||||
|
||||
if(!is_array($fields))
|
||||
$fields = explode(',', $fields);
|
||||
|
||||
foreach($fields as $field) {
|
||||
switch($field) {
|
||||
case 'is_dead':
|
||||
$res->is_dead = $user->isDead();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
|
|
|
@ -181,8 +181,8 @@ class Video extends Media
|
|||
{
|
||||
if(preg_match(file_get_contents(__DIR__ . "/../VideoDrivers/regex/youtube.txt"), $link, $matches)) {
|
||||
$pointer = "YouTube:$matches[1]";
|
||||
} else if(preg_match(file_get_contents(__DIR__ . "/../VideoDrivers/regex/vimeo.txt"), $link, $matches)) {
|
||||
$pointer = "Vimeo:$matches[1]";
|
||||
/*} else if(preg_match(file_get_contents(__DIR__ . "/../VideoDrivers/regex/vimeo.txt"), $link, $matches)) {
|
||||
$pointer = "Vimeo:$matches[1]";*/
|
||||
} else {
|
||||
throw new ISE("Invalid link");
|
||||
}
|
||||
|
|
|
@ -23,4 +23,13 @@ class APITokens extends Repository
|
|||
|
||||
return $token;
|
||||
}
|
||||
|
||||
function getStaleByUser(int $userId, string $platform, bool $withRevoked = false): ?APIToken
|
||||
{
|
||||
return $this->toEntity($this->table->where([
|
||||
'user' => $userId,
|
||||
'platform' => $platform,
|
||||
'deleted' => $withRevoked,
|
||||
])->fetch());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,11 +67,21 @@ class Applications
|
|||
return sizeof($this->appRels->where("user", $user->getId()));
|
||||
}
|
||||
|
||||
function find(string $query, array $pars = [], string $sort = "id"): Util\EntityStream
|
||||
function find(string $query = "", array $params = [], array $order = ['type' => 'id', 'invert' => false]): Util\EntityStream
|
||||
{
|
||||
$query = "%$query%";
|
||||
$result = $this->apps->where("CONCAT_WS(' ', name, description) LIKE ?", $query)->where("enabled", 1);
|
||||
$order_str = 'id';
|
||||
|
||||
return new Util\EntityStream("Application", $result->order("$sort"));
|
||||
switch($order['type']) {
|
||||
case 'id':
|
||||
$order_str = 'id ' . ($order['invert'] ? 'ASC' : 'DESC');
|
||||
break;
|
||||
}
|
||||
|
||||
if($order_str)
|
||||
$result->order($order_str);
|
||||
|
||||
return new Util\EntityStream("Application", $result);
|
||||
}
|
||||
}
|
|
@ -208,7 +208,7 @@ class Audios
|
|||
$search = $this->audios->where([
|
||||
"unlisted" => 0,
|
||||
"deleted" => 0,
|
||||
])->where("MATCH ($columns) AGAINST (? WITH QUERY EXPANSION)", $query)->order($order);
|
||||
])->where("MATCH ($columns) AGAINST (? IN BOOLEAN MODE)", "%$query%")->order($order);
|
||||
|
||||
if($withLyrics)
|
||||
$search = $search->where("lyrics IS NOT NULL");
|
||||
|
@ -219,6 +219,7 @@ class Audios
|
|||
function searchPlaylists(string $query): EntityStream
|
||||
{
|
||||
$search = $this->playlists->where([
|
||||
"unlisted" => 0,
|
||||
"deleted" => 0,
|
||||
])->where("MATCH (`name`, `description`) AGAINST (? IN BOOLEAN MODE)", $query);
|
||||
|
||||
|
@ -243,32 +244,24 @@ class Audios
|
|||
])->fetch());
|
||||
}
|
||||
|
||||
function find(string $query, array $pars = [], string $sort = "id DESC", int $page = 1, ?int $perPage = NULL): \Traversable
|
||||
function find(string $query, array $params = [], array $order = ['type' => 'id', 'invert' => false], int $page = 1, ?int $perPage = NULL): \Traversable
|
||||
{
|
||||
$query = "%$query%";
|
||||
$result = $this->audios->where([
|
||||
"unlisted" => 0,
|
||||
"deleted" => 0,
|
||||
]);
|
||||
$order_str = (in_array($order['type'], ['id', 'length', 'listens']) ? $order['type'] : 'id') . ' ' . ($order['invert'] ? 'ASC' : 'DESC');;
|
||||
|
||||
$notNullParams = [];
|
||||
|
||||
foreach($pars as $paramName => $paramValue)
|
||||
if($paramName != "before" && $paramName != "after" && $paramName != "only_performers")
|
||||
$paramValue != NULL ? $notNullParams+=["$paramName" => "%$paramValue%"] : NULL;
|
||||
else
|
||||
$paramValue != NULL ? $notNullParams+=["$paramName" => "$paramValue"] : NULL;
|
||||
|
||||
$nnparamsCount = sizeof($notNullParams);
|
||||
|
||||
if($notNullParams["only_performers"] == "1") {
|
||||
if($params["only_performers"] == "1") {
|
||||
$result->where("performer LIKE ?", $query);
|
||||
} else {
|
||||
$result->where("name LIKE ? OR performer LIKE ?", $query, $query);
|
||||
}
|
||||
|
||||
if($nnparamsCount > 0) {
|
||||
foreach($notNullParams as $paramName => $paramValue) {
|
||||
foreach($params as $paramName => $paramValue) {
|
||||
if(is_null($paramValue) || $paramValue == '') continue;
|
||||
|
||||
switch($paramName) {
|
||||
case "before":
|
||||
$result->where("created < ?", $paramValue);
|
||||
|
@ -279,17 +272,44 @@ class Audios
|
|||
case "with_lyrics":
|
||||
$result->where("lyrics IS NOT NULL");
|
||||
break;
|
||||
}
|
||||
case 'genre':
|
||||
if($paramValue == 'any') break;
|
||||
|
||||
$result->where("genre", $paramValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new Util\EntityStream("Audio", $result->order($sort));
|
||||
if($order_str)
|
||||
$result->order($order_str);
|
||||
|
||||
return new Util\EntityStream("Audio", $result);
|
||||
}
|
||||
|
||||
function findPlaylists(string $query, int $page = 1, ?int $perPage = NULL): \Traversable
|
||||
function findPlaylists(string $query, array $params = [], array $order = ['type' => 'id', 'invert' => false]): \Traversable
|
||||
{
|
||||
$query = "%$query%";
|
||||
$result = $this->playlists->where("name LIKE ?", $query);
|
||||
$result = $this->playlists->where([
|
||||
"deleted" => 0,
|
||||
])->where("CONCAT_WS(' ', name, description) LIKE ?", $query);
|
||||
$order_str = (in_array($order['type'], ['id', 'length', 'listens']) ? $order['type'] : 'id') . ' ' . ($order['invert'] ? 'ASC' : 'DESC');
|
||||
|
||||
if(is_null($params['from_me']) || empty($params['from_me']))
|
||||
$result->where(["unlisted" => 0]);
|
||||
|
||||
foreach($params as $paramName => $paramValue) {
|
||||
if(is_null($paramValue) || $paramValue == '') continue;
|
||||
|
||||
switch($paramName) {
|
||||
# БУДЬ МАКСИМАЛЬНО АККУРАТЕН С ДАННЫМ ПАРАМЕТРОМ
|
||||
case "from_me":
|
||||
$result->where("owner", $paramValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if($order_str)
|
||||
$result->order($order_str);
|
||||
|
||||
return new Util\EntityStream("Playlist", $result);
|
||||
}
|
||||
|
|
|
@ -43,17 +43,29 @@ class Clubs
|
|||
return $this->toClub($this->clubs->get($id));
|
||||
}
|
||||
|
||||
function find(string $query, array $pars = [], string $sort = "id DESC", int $page = 1, ?int $perPage = NULL): \Traversable
|
||||
function find(string $query, array $params = [], array $order = ['type' => 'id', 'invert' => false], int $page = 1, ?int $perPage = NULL): \Traversable
|
||||
{
|
||||
$query = "%$query%";
|
||||
$result = $this->clubs->where("name LIKE ? OR about LIKE ?", $query, $query);
|
||||
$result = $this->clubs;
|
||||
$order_str = 'id';
|
||||
|
||||
return new Util\EntityStream("Club", $result->order($sort));
|
||||
switch($order['type']) {
|
||||
case 'id':
|
||||
$order_str = 'id ' . ($order['invert'] ? 'ASC' : 'DESC');
|
||||
break;
|
||||
}
|
||||
|
||||
$result = $result->where("name LIKE ? OR about LIKE ?", $query, $query);
|
||||
|
||||
if($order_str)
|
||||
$result->order($order_str);
|
||||
|
||||
return new Util\EntityStream("Club", $result);
|
||||
}
|
||||
|
||||
function getCount(): int
|
||||
{
|
||||
return sizeof(clone $this->clubs);
|
||||
return (clone $this->clubs)->count('*');
|
||||
}
|
||||
|
||||
function getPopularClubs(): \Traversable
|
||||
|
|
|
@ -60,23 +60,18 @@ class Comments
|
|||
]));
|
||||
}
|
||||
|
||||
function find(string $query = "", array $pars = [], string $sort = "id"): Util\EntityStream
|
||||
function find(string $query, array $params = [], array $order = ['type' => 'id', 'invert' => false]): Util\EntityStream
|
||||
{
|
||||
$query = "%$query%";
|
||||
$result = $this->comments->where("content LIKE ?", "%$query%")->where("deleted", 0);
|
||||
$order_str = 'id';
|
||||
|
||||
$notNullParams = [];
|
||||
switch($order['type']) {
|
||||
case 'id':
|
||||
$order_str = 'created ' . ($order['invert'] ? 'ASC' : 'DESC');
|
||||
break;
|
||||
}
|
||||
|
||||
foreach($pars as $paramName => $paramValue)
|
||||
if($paramName != "before" && $paramName != "after")
|
||||
$paramValue != NULL ? $notNullParams+=["$paramName" => "%$paramValue%"] : NULL;
|
||||
else
|
||||
$paramValue != NULL ? $notNullParams+=["$paramName" => "$paramValue"] : NULL;
|
||||
|
||||
$result = $this->comments->where("content LIKE ?", $query)->where("deleted", 0);
|
||||
$nnparamsCount = sizeof($notNullParams);
|
||||
|
||||
if($nnparamsCount > 0) {
|
||||
foreach($notNullParams as $paramName => $paramValue) {
|
||||
foreach($params as $paramName => $paramValue) {
|
||||
switch($paramName) {
|
||||
case "before":
|
||||
$result->where("created < ?", $paramValue);
|
||||
|
@ -86,8 +81,10 @@ class Comments
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Util\EntityStream("Comment", $result->order("$sort"));
|
||||
if($order_str)
|
||||
$result->order($order_str);
|
||||
|
||||
return new Util\EntityStream("Comment", $result);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ class Notifications
|
|||
return (new $repoClassName)->get($id);
|
||||
}
|
||||
|
||||
private function getQuery(User $user, bool $count = false, int $offset, bool $archived = false, int $page = 1, ?int $perPage = NULL): string
|
||||
private function getQuery(User $user, bool $count, int $offset, bool $archived = false, int $page = 1, ?int $perPage = NULL): string
|
||||
{
|
||||
$query = "SELECT " . ($count ? "COUNT(*) AS cnt" : "*") . " FROM notifications WHERE recipientType=0 ";
|
||||
$query .= "AND timestamp " . ($archived ? "<" : ">") . "$offset AND recipientId=" . $user->getId();
|
||||
|
|
|
@ -154,23 +154,21 @@ class Posts
|
|||
|
||||
}
|
||||
|
||||
function find(string $query = "", array $pars = [], string $sort = "id"): Util\EntityStream
|
||||
function find(string $query = "", array $params = [], array $order = ['type' => 'id', 'invert' => false]): Util\EntityStream
|
||||
{
|
||||
$query = "%$query%";
|
||||
|
||||
$notNullParams = [];
|
||||
|
||||
foreach($pars as $paramName => $paramValue)
|
||||
if($paramName != "before" && $paramName != "after")
|
||||
$paramValue != NULL ? $notNullParams+=["$paramName" => "%$paramValue%"] : NULL;
|
||||
else
|
||||
$paramValue != NULL ? $notNullParams+=["$paramName" => "$paramValue"] : NULL;
|
||||
|
||||
$result = $this->posts->where("content LIKE ?", $query)->where("deleted", 0)->where("suggested", 0);
|
||||
$nnparamsCount = sizeof($notNullParams);
|
||||
$order_str = 'id';
|
||||
|
||||
switch($order['type']) {
|
||||
case 'id':
|
||||
$order_str = 'created ' . ($order['invert'] ? 'ASC' : 'DESC');
|
||||
break;
|
||||
}
|
||||
|
||||
foreach($params as $paramName => $paramValue) {
|
||||
if(is_null($paramValue) || $paramValue == '') continue;
|
||||
|
||||
if($nnparamsCount > 0) {
|
||||
foreach($notNullParams as $paramName => $paramValue) {
|
||||
switch($paramName) {
|
||||
case "before":
|
||||
$result->where("created < ?", $paramValue);
|
||||
|
@ -178,12 +176,23 @@ class Posts
|
|||
case "after":
|
||||
$result->where("created > ?", $paramValue);
|
||||
break;
|
||||
}
|
||||
/*case 'die_in_agony':
|
||||
$result->where("nsfw", 1);
|
||||
break;
|
||||
case 'ads':
|
||||
$result->where("ad", 1);
|
||||
break;*/
|
||||
# БУДЬ МАКСИМАЛЬНО АККУРАТЕН С ДАННЫМ ПАРАМЕТРОМ
|
||||
case 'from_me':
|
||||
$result->where("owner", $paramValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if($order_str)
|
||||
$result->order($order_str);
|
||||
|
||||
return new Util\EntityStream("Post", $result->order("$sort"));
|
||||
return new Util\EntityStream("Post", $result);
|
||||
}
|
||||
|
||||
function getPostCountOnUserWall(int $user): int
|
||||
|
@ -252,6 +261,6 @@ class Posts
|
|||
|
||||
function getCount(): int
|
||||
{
|
||||
return sizeof(clone $this->posts);
|
||||
return (clone $this->posts)->count('*');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,77 +44,62 @@ class Users
|
|||
return $alias->getUser();
|
||||
}
|
||||
|
||||
function getByChandlerUser(?ChandlerUser $user): ?User
|
||||
function getByChandlerUserId(string $cid): ?User
|
||||
{
|
||||
return $user ? $this->toUser($this->users->where("user", $user->getId())->fetch()) : NULL;
|
||||
return $this->toUser($this->users->where("user", $cid)->fetch());
|
||||
}
|
||||
|
||||
function find(string $query, array $pars = [], string $sort = "id DESC"): Util\EntityStream
|
||||
function getByChandlerUser(?ChandlerUser $user): ?User
|
||||
{
|
||||
return $user ? $this->getByChandlerUserId($user->getId()) : NULL;
|
||||
}
|
||||
|
||||
function find(string $query, array $params = [], array $order = ['type' => 'id', 'invert' => false]): Util\EntityStream
|
||||
{
|
||||
$query = "%$query%";
|
||||
$result = $this->users->where("CONCAT_WS(' ', first_name, last_name, pseudo, shortcode) LIKE ?", $query)->where("deleted", 0);
|
||||
$order_str = 'id';
|
||||
|
||||
$notNullParams = [];
|
||||
$nnparamsCount = 0;
|
||||
switch($order['type']) {
|
||||
case 'id':
|
||||
case 'reg_date':
|
||||
$order_str = 'id ' . ($order['invert'] ? 'ASC' : 'DESC');
|
||||
break;
|
||||
case 'rating':
|
||||
$order_str = 'rating DESC';
|
||||
break;
|
||||
}
|
||||
|
||||
foreach($pars as $paramName => $paramValue)
|
||||
if($paramName != "before" && $paramName != "after" && $paramName != "gender" && $paramName != "maritalstatus" && $paramName != "politViews" && $paramName != "doNotSearchMe")
|
||||
$paramValue != NULL ? $notNullParams += ["$paramName" => "%$paramValue%"] : NULL;
|
||||
else
|
||||
$paramValue != NULL ? $notNullParams += ["$paramName" => "$paramValue"] : NULL;
|
||||
foreach($params as $paramName => $paramValue) {
|
||||
if(is_null($paramValue) || $paramValue == '') continue;
|
||||
|
||||
$nnparamsCount = sizeof($notNullParams);
|
||||
|
||||
if($nnparamsCount > 0) {
|
||||
foreach($notNullParams as $paramName => $paramValue) {
|
||||
switch($paramName) {
|
||||
case "hometown":
|
||||
$result->where("hometown LIKE ?", $paramValue);
|
||||
$result->where("hometown LIKE ?", "%$paramValue%");
|
||||
break;
|
||||
case "city":
|
||||
$result->where("city LIKE ?", $paramValue);
|
||||
$result->where("city LIKE ?", "%$paramValue%");
|
||||
break;
|
||||
case "maritalstatus":
|
||||
case "marital_status":
|
||||
$result->where("marital_status ?", $paramValue);
|
||||
break;
|
||||
case "status":
|
||||
$result->where("status LIKE ?", $paramValue);
|
||||
break;
|
||||
case "politViews":
|
||||
case "polit_views":
|
||||
$result->where("polit_views ?", $paramValue);
|
||||
break;
|
||||
case "email":
|
||||
$result->where("email_contact LIKE ?", $paramValue);
|
||||
break;
|
||||
case "telegram":
|
||||
$result->where("telegram LIKE ?", $paramValue);
|
||||
break;
|
||||
case "site":
|
||||
$result->where("telegram LIKE ?", $paramValue);
|
||||
break;
|
||||
case "address":
|
||||
$result->where("address LIKE ?", $paramValue);
|
||||
break;
|
||||
case "is_online":
|
||||
$result->where("online >= ?", time() - 900);
|
||||
break;
|
||||
case "interests":
|
||||
$result->where("interests LIKE ?", $paramValue);
|
||||
break;
|
||||
case "fav_mus":
|
||||
$result->where("fav_music LIKE ?", $paramValue);
|
||||
$result->where("fav_music LIKE ?", "%$paramValue%");
|
||||
break;
|
||||
case "fav_films":
|
||||
$result->where("fav_films LIKE ?", $paramValue);
|
||||
$result->where("fav_films LIKE ?", "%$paramValue%");
|
||||
break;
|
||||
case "fav_shows":
|
||||
$result->where("fav_shows LIKE ?", $paramValue);
|
||||
$result->where("fav_shows LIKE ?", "%$paramValue%");
|
||||
break;
|
||||
case "fav_books":
|
||||
$result->where("fav_books LIKE ?", $paramValue);
|
||||
break;
|
||||
case "fav_quote":
|
||||
$result->where("fav_quote LIKE ?", $paramValue);
|
||||
$result->where("fav_books LIKE ?", "%$paramValue%");
|
||||
break;
|
||||
case "before":
|
||||
$result->where("UNIX_TIMESTAMP(since) < ?", $paramValue);
|
||||
|
@ -123,28 +108,30 @@ class Users
|
|||
$result->where("UNIX_TIMESTAMP(since) > ?", $paramValue);
|
||||
break;
|
||||
case "gender":
|
||||
$result->where("sex ?", $paramValue);
|
||||
if((int) $paramValue == 3) break;
|
||||
$result->where("sex ?", (int) $paramValue);
|
||||
break;
|
||||
case "doNotSearchMe":
|
||||
$result->where("id !=", $paramValue);
|
||||
case "ignore_id":
|
||||
$result->where("id != ?", $paramValue);
|
||||
break;
|
||||
case "doNotSearchPrivate":
|
||||
case "ignore_private":
|
||||
$result->where("profile_type", 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($order_str)
|
||||
$result->order($order_str);
|
||||
|
||||
return new Util\EntityStream("User", $result->order($sort));
|
||||
return new Util\EntityStream("User", $result);
|
||||
}
|
||||
|
||||
function getStatistics(): object
|
||||
{
|
||||
return (object) [
|
||||
"all" => sizeof(clone $this->users),
|
||||
"active" => sizeof((clone $this->users)->where("online > 0")),
|
||||
"online" => sizeof((clone $this->users)->where("online >= ?", time() - 900)),
|
||||
"all" => (clone $this->users)->count('*'),
|
||||
"active" => (clone $this->users)->where("online > 0")->count('*'),
|
||||
"online" => (clone $this->users)->where("online >= ?", time() - 900)->count('*'),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -46,23 +46,19 @@ class Videos
|
|||
return sizeof($this->videos->where("owner", $user->getId())->where(["deleted" => 0, "unlisted" => 0]));
|
||||
}
|
||||
|
||||
function find(string $query = "", array $pars = [], string $sort = "id"): Util\EntityStream
|
||||
function find(string $query = "", array $params = [], array $order = ['type' => 'id', 'invert' => false]): Util\EntityStream
|
||||
{
|
||||
$query = "%$query%";
|
||||
|
||||
$notNullParams = [];
|
||||
|
||||
foreach($pars as $paramName => $paramValue)
|
||||
if($paramName != "before" && $paramName != "after")
|
||||
$paramValue != NULL ? $notNullParams+=["$paramName" => "%$paramValue%"] : NULL;
|
||||
else
|
||||
$paramValue != NULL ? $notNullParams+=["$paramName" => "$paramValue"] : NULL;
|
||||
|
||||
$result = $this->videos->where("CONCAT_WS(' ', name, description) LIKE ?", $query)->where("deleted", 0);
|
||||
$nnparamsCount = sizeof($notNullParams);
|
||||
$order_str = 'id';
|
||||
|
||||
if($nnparamsCount > 0) {
|
||||
foreach($notNullParams as $paramName => $paramValue) {
|
||||
switch($order['type']) {
|
||||
case 'id':
|
||||
$order_str = 'id ' . ($order['invert'] ? 'ASC' : 'DESC');
|
||||
break;
|
||||
}
|
||||
|
||||
foreach($params as $paramName => $paramValue) {
|
||||
switch($paramName) {
|
||||
case "before":
|
||||
$result->where("created < ?", $paramValue);
|
||||
|
@ -70,12 +66,17 @@ class Videos
|
|||
case "after":
|
||||
$result->where("created > ?", $paramValue);
|
||||
break;
|
||||
}
|
||||
case 'only_youtube':
|
||||
if((int) $paramValue != 1) break;
|
||||
$result->where("link != ?", 'NULL');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if($order_str)
|
||||
$result->order($order_str);
|
||||
|
||||
return new Util\EntityStream("Video", $result->order("$sort"));
|
||||
return new Util\EntityStream("Video", $result);
|
||||
}
|
||||
|
||||
function getLastVideo(User $user)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
(SELECT DISTINCT(follower) AS __id FROM
|
||||
(SELECT follower FROM subscriptions WHERE target=? AND model="openvk\\Web\\Models\\Entities\\User") u0
|
||||
(SELECT follower, flags FROM subscriptions WHERE target=? AND model="openvk\\Web\\Models\\Entities\\User") u0
|
||||
LEFT JOIN
|
||||
(SELECT target FROM subscriptions WHERE follower=? AND model="openvk\\Web\\Models\\Entities\\User") u1
|
||||
ON u0.follower = u1.target WHERE u1.target IS NULL) u2
|
||||
|
|
6
Web/Models/sql/get-requests.tsql
Executable file
6
Web/Models/sql/get-requests.tsql
Executable file
|
@ -0,0 +1,6 @@
|
|||
(SELECT DISTINCT(follower) AS __id FROM
|
||||
(SELECT follower FROM subscriptions WHERE target=? AND flags=0 AND model="openvk\\Web\\Models\\Entities\\User") u0
|
||||
LEFT JOIN
|
||||
(SELECT target FROM subscriptions WHERE follower=? AND flags=0 AND model="openvk\\Web\\Models\\Entities\\User") u1
|
||||
ON u0.follower = u1.target WHERE u1.target IS NULL) u2
|
||||
INNER JOIN profiles ON profiles.id = u2.__id
|
|
@ -145,6 +145,6 @@ final class AboutPresenter extends OpenVKPresenter
|
|||
|
||||
function renderDev(): void
|
||||
{
|
||||
$this->redirect("https://docs.openvk.uk/");
|
||||
$this->redirect("https://docs.ovk.to/");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,13 @@ final class AdminPresenter extends OpenVKPresenter
|
|||
$this->flash("warn", tr("admin_commerce_disabled"), tr("admin_commerce_disabled_desc"));
|
||||
}
|
||||
|
||||
private function warnIfLongpoolBroken(): void
|
||||
{
|
||||
bdump(is_writable(CHANDLER_ROOT . '/tmp/events.bin'));
|
||||
if(file_exists(CHANDLER_ROOT . '/tmp/events.bin') == false || is_writable(CHANDLER_ROOT . '/tmp/events.bin') == false)
|
||||
$this->flash("warn", tr("admin_longpool_broken"), tr("admin_longpool_broken_desc", CHANDLER_ROOT . '/tmp/events.bin'));
|
||||
}
|
||||
|
||||
private function searchResults(object $repo, &$count)
|
||||
{
|
||||
$query = $this->queryParam("q") ?? "";
|
||||
|
@ -76,7 +83,7 @@ final class AdminPresenter extends OpenVKPresenter
|
|||
|
||||
function renderIndex(): void
|
||||
{
|
||||
|
||||
$this->warnIfLongpoolBroken();
|
||||
}
|
||||
|
||||
function renderUsers(): void
|
||||
|
@ -154,6 +161,7 @@ final class AdminPresenter extends OpenVKPresenter
|
|||
$club->setShortCode($this->postParam("shortcode"));
|
||||
$club->setVerified(empty($this->postParam("verify") ? 0 : 1));
|
||||
$club->setHide_From_Global_Feed(empty($this->postParam("hide_from_global_feed") ? 0 : 1));
|
||||
$club->setEnforce_Hiding_From_Global_Feed(empty($this->postParam("enforce_hiding_from_global_feed") ? 0 : 1));
|
||||
$club->save();
|
||||
break;
|
||||
case "ban":
|
||||
|
@ -681,7 +689,8 @@ final class AdminPresenter extends OpenVKPresenter
|
|||
$this->template->obj_type = $obj_type;
|
||||
}
|
||||
|
||||
$this->template->logs = (new Logs)->search($filter);
|
||||
$logs = iterator_to_array((new Logs)->search($filter));
|
||||
$this->template->logs = $logs;
|
||||
$this->template->object_types = (new Logs)->getTypes();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
if (!$entity || $entity->isBanned())
|
||||
$this->redirect("/playlists" . $this->user->id);
|
||||
|
||||
$playlists = $this->audios->getPlaylistsByClub($entity, $page, 10);
|
||||
$playlists = $this->audios->getPlaylistsByClub($entity, $page, OPENVK_DEFAULT_PER_PAGE);
|
||||
$playlistsCount = $this->audios->getClubPlaylistsCount($entity);
|
||||
} else {
|
||||
$entity = (new Users)->get($owner);
|
||||
|
@ -85,7 +85,7 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
if(!$entity->getPrivacyPermission("audios.read", $this->user->identity))
|
||||
$this->flashFail("err", tr("forbidden"), tr("forbidden_comment"));
|
||||
|
||||
$playlists = $this->audios->getPlaylistsByUser($entity, $page, 9);
|
||||
$playlists = $this->audios->getPlaylistsByUser($entity, $page, OPENVK_DEFAULT_PER_PAGE);
|
||||
$playlistsCount = $this->audios->getUserPlaylistsCount($entity);
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,7 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
$this->template->mode = $mode;
|
||||
$this->template->page = $page;
|
||||
|
||||
if(in_array($mode, ["list", "new", "popular"]) && $this->user->identity)
|
||||
if(in_array($mode, ["list", "new", "popular"]) && $this->user->identity && $page < 2)
|
||||
$this->template->friendsAudios = $this->user->identity->getBroadcastList("all", true);
|
||||
}
|
||||
|
||||
|
@ -142,7 +142,13 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
$this->assertUserLoggedIn();
|
||||
|
||||
$group = NULL;
|
||||
$playlist = NULL;
|
||||
$isAjax = $this->postParam("ajax", false) == 1;
|
||||
|
||||
if(!is_null($this->queryParam("gid")) && !is_null($this->queryParam("playlist"))) {
|
||||
$this->flashFail("err", tr("forbidden"), tr("not_enough_permissions_comment"), null, $isAjax);
|
||||
}
|
||||
|
||||
if(!is_null($this->queryParam("gid"))) {
|
||||
$gid = (int) $this->queryParam("gid");
|
||||
$group = (new Clubs)->get($gid);
|
||||
|
@ -153,6 +159,19 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
$this->flashFail("err", tr("forbidden"), tr("not_enough_permissions_comment"), null, $isAjax);
|
||||
}
|
||||
|
||||
if(!is_null($this->queryParam("playlist"))) {
|
||||
$playlist_id = (int)$this->queryParam("playlist");
|
||||
$playlist = (new Audios)->getPlaylist($playlist_id);
|
||||
if(!$playlist || $playlist->isDeleted())
|
||||
$this->flashFail("err", tr("forbidden"), tr("not_enough_permissions_comment"), null, $isAjax);
|
||||
|
||||
if(!$playlist->canBeModifiedBy($this->user->identity))
|
||||
$this->flashFail("err", tr("forbidden"), tr("not_enough_permissions_comment"), null, $isAjax);
|
||||
|
||||
$this->template->playlist = $playlist;
|
||||
$this->template->owner = $playlist->getOwner();
|
||||
}
|
||||
|
||||
$this->template->group = $group;
|
||||
|
||||
if($_SERVER["REQUEST_METHOD"] !== "POST")
|
||||
|
@ -196,6 +215,8 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
$lyrics = $this->postParam("lyrics");
|
||||
$genre = empty($this->postParam("genre")) ? "Other" : $this->postParam("genre");
|
||||
$nsfw = ($this->postParam("explicit") ?? "off") === "on";
|
||||
$is_unlisted = ($this->postParam("unlisted") ?? "off") === "on";
|
||||
|
||||
if(empty($performer) || empty($name) || iconv_strlen($performer . $name) > 128) # FQN of audio must not be more than 128 chars
|
||||
$this->flashFail("err", tr("error"), tr("error_insufficient_info"), null, $isAjax);
|
||||
|
||||
|
@ -206,6 +227,7 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
$audio->setLyrics(empty($lyrics) ? NULL : $lyrics);
|
||||
$audio->setGenre($genre);
|
||||
$audio->setExplicit($nsfw);
|
||||
$audio->setUnlisted($is_unlisted);
|
||||
|
||||
try {
|
||||
$audio->setFile($upload);
|
||||
|
@ -215,13 +237,18 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
} catch(\RuntimeException $ex) {
|
||||
$this->flashFail("err", tr("error"), tr("ffmpeg_timeout"), null, $isAjax);
|
||||
} catch(\BadMethodCallException $ex) {
|
||||
$this->flashFail("err", tr("error"), "Загрузка аудио под Linux на данный момент не реализована. Следите за обновлениями: <a href='https://github.com/openvk/openvk/pull/512/commits'>https://github.com/openvk/openvk/pull/512/commits</a>", null, $isAjax);
|
||||
$this->flashFail("err", tr("error"), "хз", null, $isAjax);
|
||||
} catch(\Exception $ex) {
|
||||
$this->flashFail("err", tr("error"), tr("ffmpeg_not_installed"), null, $isAjax);
|
||||
}
|
||||
|
||||
$audio->save();
|
||||
|
||||
if($playlist) {
|
||||
$playlist->add($audio);
|
||||
} else {
|
||||
$audio->add($group ?? $this->user->identity);
|
||||
}
|
||||
|
||||
if(!$isAjax)
|
||||
$this->redirect(is_null($group) ? "/audios" . $this->user->id : "/audios-" . $group->getId());
|
||||
|
@ -233,8 +260,8 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
else
|
||||
$redirectLink .= $this->user->id;
|
||||
|
||||
$pagesCount = (int)ceil((new Audios)->getCollectionSizeByEntityId(isset($group) ? $group->getRealId() : $this->user->id) / 10);
|
||||
$redirectLink .= "?p=".$pagesCount;
|
||||
if($playlist)
|
||||
$redirectLink = "/playlist" . $playlist->getPrettyId();
|
||||
|
||||
$this->returnJson([
|
||||
"success" => true,
|
||||
|
@ -279,7 +306,7 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
|
||||
function renderSearch(): void
|
||||
{
|
||||
$this->redirect("/search?type=audios");
|
||||
$this->redirect("/search?section=audios");
|
||||
}
|
||||
|
||||
function renderNewPlaylist(): void
|
||||
|
@ -304,6 +331,8 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
$title = $this->postParam("title");
|
||||
$description = $this->postParam("description");
|
||||
$is_unlisted = (int)$this->postParam('is_unlisted');
|
||||
|
||||
$audios = !empty($this->postParam("audios")) ? array_slice(explode(",", $this->postParam("audios")), 0, 1000) : [];
|
||||
|
||||
if(empty($title) || iconv_strlen($title) < 1)
|
||||
|
@ -313,6 +342,8 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
$playlist->setOwner($owner);
|
||||
$playlist->setName(substr($title, 0, 125));
|
||||
$playlist->setDescription(substr($description, 0, 2045));
|
||||
if($is_unlisted == 1)
|
||||
$playlist->setUnlisted(true);
|
||||
|
||||
if($_FILES["cover"]["error"] === UPLOAD_ERR_OK) {
|
||||
if(!str_starts_with($_FILES["cover"]["type"], "image"))
|
||||
|
@ -427,6 +458,7 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
|
||||
$title = $this->postParam("title");
|
||||
$description = $this->postParam("description");
|
||||
$is_unlisted = (int)$this->postParam('is_unlisted');
|
||||
$new_audios = !empty($this->postParam("audios")) ? explode(",", rtrim($this->postParam("audios"), ",")) : [];
|
||||
|
||||
if(empty($title) || iconv_strlen($title) < 1)
|
||||
|
@ -436,6 +468,7 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
$playlist->setDescription(ovk_proc_strtr($description, 2045));
|
||||
$playlist->setEdited(time());
|
||||
$playlist->resetLength();
|
||||
$playlist->setUnlisted((bool)$is_unlisted);
|
||||
|
||||
if($_FILES["new_cover"]["error"] === UPLOAD_ERR_OK) {
|
||||
if(!str_starts_with($_FILES["new_cover"]["type"], "image"))
|
||||
|
@ -475,12 +508,15 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
|
||||
$this->template->playlist = $playlist;
|
||||
$this->template->page = $page;
|
||||
$this->template->cover = $playlist->getCoverPhoto();
|
||||
$this->template->cover_url = $this->template->cover ? $this->template->cover->getURL() : "/assets/packages/static/openvk/img/song.jpg";
|
||||
$this->template->audios = iterator_to_array($playlist->fetch($page, 10));
|
||||
$this->template->ownerId = $owner_id;
|
||||
$this->template->owner = $playlist->getOwner();
|
||||
$this->template->isBookmarked = $this->user->identity && $playlist->isBookmarkedBy($this->user->identity);
|
||||
$this->template->isMy = $this->user->identity && $playlist->getOwner()->getId() === $this->user->id;
|
||||
$this->template->canEdit = $this->user->identity && $playlist->canBeModifiedBy($this->user->identity);
|
||||
$this->template->count = $playlist->size();
|
||||
}
|
||||
|
||||
function renderAction(int $audio_id): void
|
||||
|
@ -531,16 +567,65 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
|
||||
break;
|
||||
case "add_to_club":
|
||||
$club = (new Clubs)->get((int)$this->postParam("club"));
|
||||
$detailed = [];
|
||||
if($audio->isWithdrawn())
|
||||
$this->flashFail("err", "error", tr("invalid_audio"), null, true);
|
||||
|
||||
if(empty($this->postParam("clubs")))
|
||||
$this->flashFail("err", "error", 'clubs not passed', null, true);
|
||||
|
||||
$clubs_arr = explode(',', $this->postParam("clubs"));
|
||||
$count = sizeof($clubs_arr);
|
||||
if($count < 1 || $count > 10) {
|
||||
$this->flashFail("err", "error", tr('too_many_or_to_lack'), null, true);
|
||||
}
|
||||
|
||||
foreach($clubs_arr as $club_id) {
|
||||
$club = (new Clubs)->get((int)$club_id);
|
||||
if(!$club || !$club->canBeModifiedBy($this->user->identity))
|
||||
$this->flashFail("err", "error", tr("access_denied"), null, true);
|
||||
continue;
|
||||
|
||||
if(!$audio->isInLibraryOf($club))
|
||||
if(!$audio->isInLibraryOf($club)) {
|
||||
$detailed[$club_id] = true;
|
||||
$audio->add($club);
|
||||
else
|
||||
$this->flashFail("err", "error", tr("group_has_audio"), null, true);
|
||||
} else {
|
||||
$detailed[$club_id] = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$this->returnJson(["success" => true, 'detailed' => $detailed]);
|
||||
break;
|
||||
case "add_to_playlist":
|
||||
$detailed = [];
|
||||
if($audio->isWithdrawn())
|
||||
$this->flashFail("err", "error", tr("invalid_audio"), null, true);
|
||||
|
||||
if(empty($this->postParam("playlists")))
|
||||
$this->flashFail("err", "error", 'playlists not passed', null, true);
|
||||
|
||||
$playlists_arr = explode(',', $this->postParam("playlists"));
|
||||
$count = sizeof($playlists_arr);
|
||||
if($count < 1 || $count > 10) {
|
||||
$this->flashFail("err", "error", tr('too_many_or_to_lack'), null, true);
|
||||
}
|
||||
|
||||
foreach($playlists_arr as $playlist_id) {
|
||||
$pid = explode('_', $playlist_id);
|
||||
$playlist = (new Audios)->getPlaylistByOwnerAndVID((int)$pid[0], (int)$pid[1]);
|
||||
if(!$playlist || !$playlist->canBeModifiedBy($this->user->identity))
|
||||
continue;
|
||||
|
||||
if(!$playlist->hasAudio($audio)) {
|
||||
$playlist->add($audio);
|
||||
$detailed[$playlist_id] = true;
|
||||
} else {
|
||||
$detailed[$playlist_id] = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$this->returnJson(["success" => true, 'detailed' => $detailed]);
|
||||
break;
|
||||
case "delete":
|
||||
if($audio->canBeModifiedBy($this->user->identity))
|
||||
|
@ -653,6 +738,28 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
$audios = $stream->page($page, 10);
|
||||
$audiosCount = $stream->size();
|
||||
break;
|
||||
case "classic_search_context":
|
||||
$data = json_decode($this->postParam("context_entity"), true);
|
||||
|
||||
$params = [];
|
||||
$order = [
|
||||
"type" => $data['order'] ?? 'id',
|
||||
"invert" => (int)$data['invert'] == 1 ? true : false
|
||||
];
|
||||
|
||||
if($data['genre'] && $data['genre'] != 'any')
|
||||
$params['genre'] = $data['genre'];
|
||||
|
||||
if($data['only_performers'] && (int)$data['only_performers'] == 1)
|
||||
$params['only_performers'] = '1';
|
||||
|
||||
if($data['with_lyrics'] && (int)$data['with_lyrics'] == 1)
|
||||
$params['with_lyrics'] = '1';
|
||||
|
||||
$stream = $this->audios->find($data['query'], $params, $order);
|
||||
$audios = $stream->page($page, 10);
|
||||
$audiosCount = $stream->size();
|
||||
break;
|
||||
}
|
||||
|
||||
$pagesCount = ceil($audiosCount / $perPage);
|
||||
|
|
|
@ -233,7 +233,10 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
$club->setEveryone_Can_Create_Topics(empty($this->postParam("everyone_can_create_topics")) ? 0 : 1);
|
||||
$club->setDisplay_Topics_Above_Wall(empty($this->postParam("display_topics_above_wall")) ? 0 : 1);
|
||||
$club->setEveryone_can_upload_audios(empty($this->postParam("upload_audios")) ? 0 : 1);
|
||||
$club->setHide_From_Global_Feed(empty($this->postParam("hide_from_global_feed")) ? 0 : 1);
|
||||
|
||||
if (!$club->isHidingFromGlobalFeedEnforced()) {
|
||||
$club->setHide_From_Global_Feed(empty($this->postParam("hide_from_global_feed") ? 0 : 1));
|
||||
}
|
||||
|
||||
$website = $this->postParam("website") ?? "";
|
||||
if(empty($website))
|
||||
|
@ -279,48 +282,99 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
|
||||
function renderSetAvatar(int $id)
|
||||
{
|
||||
$photo = new Photo;
|
||||
$this->assertUserLoggedIn();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$club = $this->clubs->get($id);
|
||||
if ($club->isBanned()) $this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
if($_SERVER["REQUEST_METHOD"] === "POST" && $_FILES["ava"]["error"] === UPLOAD_ERR_OK) {
|
||||
|
||||
if(!$club || $club->isBanned() || !$club->canBeModifiedBy($this->user->identity))
|
||||
$this->flashFail("err", tr("error"), tr("forbidden"), NULL, true);
|
||||
|
||||
if($_SERVER["REQUEST_METHOD"] === "POST" && $_FILES["blob"]["error"] === UPLOAD_ERR_OK) {
|
||||
try {
|
||||
$photo = new Photo;
|
||||
|
||||
$anon = OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["anonymousPosting"]["enable"];
|
||||
if($anon && $this->user->id === $club->getOwner()->getId())
|
||||
$anon = $club->isOwnerHidden();
|
||||
else if($anon)
|
||||
$anon = $club->getManager($this->user->identity)->isHidden();
|
||||
|
||||
$photo->setOwner($this->user->id);
|
||||
$photo->setDescription("Club image");
|
||||
$photo->setFile($_FILES["ava"]);
|
||||
$photo->setFile($_FILES["blob"]);
|
||||
$photo->setCreated(time());
|
||||
$photo->setAnonymous($anon);
|
||||
$photo->save();
|
||||
|
||||
(new Albums)->getClubAvatarAlbum($club)->addPhoto($photo);
|
||||
|
||||
if($this->postParam("on_wall") == 1) {
|
||||
$post = new Post;
|
||||
|
||||
$post->setOwner($this->user->id);
|
||||
$post->setWall($club->getId() * -1);
|
||||
$post->setCreated(time());
|
||||
$post->setContent("");
|
||||
|
||||
$flags = 0;
|
||||
$flags |= 0b00010000;
|
||||
$flags |= 0b10000000;
|
||||
|
||||
$post = new Post;
|
||||
$post->setOwner($this->user->id);
|
||||
$post->setWall($club->getId()*-1);
|
||||
$post->setCreated(time());
|
||||
$post->setContent("");
|
||||
$post->setFlags($flags);
|
||||
$post->save();
|
||||
$post->attach($photo);
|
||||
|
||||
} catch(ISE $ex) {
|
||||
$name = $album->getName();
|
||||
$this->flashFail("err", tr("error"), tr("error_when_uploading_photo"));
|
||||
$post->attach($photo);
|
||||
}
|
||||
|
||||
} catch(\Throwable $ex) {
|
||||
$this->flashFail("err", tr("error"), tr("error_when_uploading_photo"), NULL, true);
|
||||
}
|
||||
|
||||
$this->returnJson([
|
||||
"success" => true,
|
||||
"new_photo" => $photo->getPrettyId(),
|
||||
"url" => $photo->getURL(),
|
||||
"id" => $photo->getPrettyId()
|
||||
]);
|
||||
} else {
|
||||
return " ";
|
||||
}
|
||||
}
|
||||
|
||||
function renderDeleteAvatar(int $id) {
|
||||
$this->assertUserLoggedIn();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$club = $this->clubs->get($id);
|
||||
|
||||
if(!$club || $club->isBanned() || !$club->canBeModifiedBy($this->user->identity))
|
||||
$this->flashFail("err", tr("error"), tr("forbidden"), NULL, true);
|
||||
|
||||
$avatar = $club->getAvatarPhoto();
|
||||
|
||||
if(!$avatar)
|
||||
$this->flashFail("succ", tr("error"), "no avatar bro", NULL, true);
|
||||
|
||||
$avatar->isolate();
|
||||
|
||||
$newAvatar = $club->getAvatarPhoto();
|
||||
|
||||
if(!$newAvatar)
|
||||
$this->returnJson([
|
||||
"success" => true,
|
||||
"has_new_photo" => false,
|
||||
"new_photo" => NULL,
|
||||
"url" => "/assets/packages/static/openvk/img/camera_200.png",
|
||||
]);
|
||||
else
|
||||
$this->returnJson([
|
||||
"success" => true,
|
||||
"has_new_photo" => true,
|
||||
"new_photo" => $newAvatar->getPrettyId(),
|
||||
"url" => $newAvatar->getURL(),
|
||||
]);
|
||||
}
|
||||
|
||||
function renderEditBackdrop(int $id): void
|
||||
{
|
||||
$this->assertUserLoggedIn();
|
||||
|
|
|
@ -274,7 +274,7 @@ abstract class OpenVKPresenter extends SimplePresenter
|
|||
setlocale(LC_TIME, ...(explode(";", tr("__locale"))));
|
||||
|
||||
if (!OPENVK_ROOT_CONF["openvk"]["preferences"]["maintenanceMode"]["all"]) {
|
||||
if (OPENVK_ROOT_CONF["openvk"]["preferences"]["maintenanceMode"][$this->presenterName]) {
|
||||
if ($this->presenterName && OPENVK_ROOT_CONF["openvk"]["preferences"]["maintenanceMode"][$this->presenterName]) {
|
||||
$this->pass("openvk!Maintenance->section", $this->presenterName);
|
||||
}
|
||||
} else {
|
||||
|
@ -307,7 +307,7 @@ abstract class OpenVKPresenter extends SimplePresenter
|
|||
$theme = Themepacks::i()[Session::i()->get("_sessionTheme", "ovk")];
|
||||
} else if($this->requestParam("themePreview")) {
|
||||
$theme = Themepacks::i()[$this->requestParam("themePreview")];
|
||||
} else if($this->user->identity !== NULL && $this->user->identity->getTheme()) {
|
||||
} else if($this->user !== NULL && $this->user->identity !== NULL && $this->user->identity->getTheme()) {
|
||||
$theme = $this->user->identity->getTheme();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\Web\Presenters;
|
||||
use openvk\Web\Models\Entities\{User, Club};
|
||||
use openvk\Web\Models\Repositories\{Users, Clubs, Posts, Comments, Videos, Applications, Notes, Audios};
|
||||
use openvk\Web\Models\Repositories\{Users, Clubs, Posts, Videos, Applications, Audios};
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
|
||||
final class SearchPresenter extends OpenVKPresenter
|
||||
|
@ -9,21 +9,17 @@ final class SearchPresenter extends OpenVKPresenter
|
|||
private $users;
|
||||
private $clubs;
|
||||
private $posts;
|
||||
private $comments;
|
||||
private $videos;
|
||||
private $apps;
|
||||
private $notes;
|
||||
private $audios;
|
||||
|
||||
function __construct(Users $users, Clubs $clubs)
|
||||
function __construct()
|
||||
{
|
||||
$this->users = $users;
|
||||
$this->clubs = $clubs;
|
||||
$this->users = new Users;
|
||||
$this->clubs = new Clubs;
|
||||
$this->posts = new Posts;
|
||||
$this->comments = new Comments;
|
||||
$this->videos = new Videos;
|
||||
$this->apps = new Applications;
|
||||
$this->notes = new Notes;
|
||||
$this->audios = new Audios;
|
||||
|
||||
parent::__construct();
|
||||
|
@ -33,85 +29,101 @@ final class SearchPresenter extends OpenVKPresenter
|
|||
{
|
||||
$this->assertUserLoggedIn();
|
||||
|
||||
$query = $this->queryParam("query") ?? "";
|
||||
$type = $this->queryParam("type") ?? "users";
|
||||
$sorter = $this->queryParam("sort") ?? "id";
|
||||
$invert = $this->queryParam("invert") == 1 ? "ASC" : "DESC";
|
||||
$query = $this->queryParam("q") ?? "";
|
||||
$section = $this->queryParam("section") ?? "users";
|
||||
$order = $this->queryParam("order") ?? "id";
|
||||
$invert = (int) ($this->queryParam("invert") ?? 0) == 1;
|
||||
$page = (int) ($this->queryParam("p") ?? 1);
|
||||
|
||||
# https://youtu.be/pSAWM5YuXx8
|
||||
# https://youtu.be/FfNZRhIn2Vk
|
||||
|
||||
$repos = [
|
||||
"groups" => "clubs",
|
||||
"users" => "users",
|
||||
"posts" => "posts",
|
||||
"comments" => "comments",
|
||||
"videos" => "videos",
|
||||
"audios" => "audios",
|
||||
"apps" => "apps",
|
||||
"notes" => "notes"
|
||||
"audios_playlists" => "audios"
|
||||
];
|
||||
$parameters = [
|
||||
"ignore_private" => true,
|
||||
];
|
||||
|
||||
switch($sorter) {
|
||||
foreach($_REQUEST as $param_name => $param_value) {
|
||||
if(is_null($param_value)) continue;
|
||||
|
||||
switch($param_name) {
|
||||
default:
|
||||
case "id":
|
||||
$sort = "id " . $invert;
|
||||
$parameters[$param_name] = $param_value;
|
||||
break;
|
||||
case "name":
|
||||
$sort = "first_name " . $invert;
|
||||
break;
|
||||
case "rating":
|
||||
$sort = "rating " . $invert;
|
||||
break;
|
||||
case "length":
|
||||
if($type != "audios") break;
|
||||
case 'marital_status':
|
||||
case 'polit_views':
|
||||
if((int) $param_value == 0) continue;
|
||||
$parameters[$param_name] = $param_value;
|
||||
|
||||
$sort = "length " . $invert;
|
||||
break;
|
||||
case "listens":
|
||||
if($type != "audios") break;
|
||||
case 'is_online':
|
||||
if((int) $param_value == 1)
|
||||
$parameters['is_online'] = 1;
|
||||
|
||||
$sort = "listens " . $invert;
|
||||
break;
|
||||
case 'only_performers':
|
||||
if((int) $param_value == 1 || $param_value == 'on')
|
||||
$parameters['only_performers'] = true;
|
||||
|
||||
break;
|
||||
case 'with_lyrics':
|
||||
if($param_value == 'on' || $param_value == '1')
|
||||
$parameters['with_lyrics'] = true;
|
||||
|
||||
break;
|
||||
# дай бог работал этот case
|
||||
case 'from_me':
|
||||
if((int) $param_value != 1) continue;
|
||||
$parameters['from_me'] = $this->user->id;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$repo = $repos[$section] or $this->throwError(400, "Bad Request", "Invalid search entity $section.");
|
||||
|
||||
$results = NULL;
|
||||
switch($section) {
|
||||
default:
|
||||
$results = $this->{$repo}->find($query, $parameters, ['type' => $order, 'invert' => $invert]);
|
||||
break;
|
||||
case 'audios_playlists':
|
||||
$results = $this->{$repo}->findPlaylists($query, $parameters, ['type' => $order, 'invert' => $invert]);
|
||||
break;
|
||||
}
|
||||
|
||||
$parameters = [
|
||||
"type" => $this->queryParam("type"),
|
||||
"city" => $this->queryParam("city") != "" ? $this->queryParam("city") : NULL,
|
||||
"maritalstatus" => $this->queryParam("maritalstatus") != 0 ? $this->queryParam("maritalstatus") : NULL,
|
||||
"with_photo" => $this->queryParam("with_photo"),
|
||||
"status" => $this->queryParam("status") != "" ? $this->queryParam("status") : NULL,
|
||||
"politViews" => $this->queryParam("politViews") != 0 ? $this->queryParam("politViews") : NULL,
|
||||
"email" => $this->queryParam("email"),
|
||||
"telegram" => $this->queryParam("telegram"),
|
||||
"site" => $this->queryParam("site") != "" ? "https://".$this->queryParam("site") : NULL,
|
||||
"address" => $this->queryParam("address"),
|
||||
"is_online" => $this->queryParam("is_online") == 1 ? 1 : NULL,
|
||||
"interests" => $this->queryParam("interests") != "" ? $this->queryParam("interests") : NULL,
|
||||
"fav_mus" => $this->queryParam("fav_mus") != "" ? $this->queryParam("fav_mus") : NULL,
|
||||
"fav_films" => $this->queryParam("fav_films") != "" ? $this->queryParam("fav_films") : NULL,
|
||||
"fav_shows" => $this->queryParam("fav_shows") != "" ? $this->queryParam("fav_shows") : NULL,
|
||||
"fav_books" => $this->queryParam("fav_books") != "" ? $this->queryParam("fav_books") : NULL,
|
||||
"fav_quote" => $this->queryParam("fav_quote") != "" ? $this->queryParam("fav_quote") : NULL,
|
||||
"hometown" => $this->queryParam("hometown") != "" ? $this->queryParam("hometown") : NULL,
|
||||
"before" => $this->queryParam("datebefore") != "" ? strtotime($this->queryParam("datebefore")) : NULL,
|
||||
"after" => $this->queryParam("dateafter") != "" ? strtotime($this->queryParam("dateafter")) : NULL,
|
||||
"gender" => $this->queryParam("gender") != "" && $this->queryParam("gender") != 2 ? $this->queryParam("gender") : NULL,
|
||||
"doNotSearchPrivate" => true,
|
||||
"only_performers" => $this->queryParam("only_performers") == "on" ? "1" : NULL,
|
||||
"with_lyrics" => $this->queryParam("with_lyrics") == "on" ? true : NULL,
|
||||
];
|
||||
|
||||
$repo = $repos[$type] or $this->throwError(400, "Bad Request", "Invalid search entity $type.");
|
||||
|
||||
$results = $this->{$repo}->find($query, $parameters, $sort);
|
||||
$iterator = $results->page($page, 14);
|
||||
$iterator = $results->page($page, OPENVK_DEFAULT_PER_PAGE);
|
||||
$count = $results->size();
|
||||
|
||||
$this->template->iterator = iterator_to_array($iterator);
|
||||
$this->template->order = $order;
|
||||
$this->template->invert = $invert;
|
||||
$this->template->data = $this->template->iterator = iterator_to_array($iterator);
|
||||
$this->template->count = $count;
|
||||
$this->template->type = $type;
|
||||
$this->template->section = $section;
|
||||
$this->template->page = $page;
|
||||
$this->template->perPage = 14;
|
||||
$this->template->perPage = OPENVK_DEFAULT_PER_PAGE;
|
||||
$this->template->query = $query;
|
||||
$this->template->atSearch = true;
|
||||
|
||||
$this->template->paginatorConf = (object) [
|
||||
"page" => $page,
|
||||
"count" => $count,
|
||||
"amount" => sizeof($this->template->data),
|
||||
"perPage" => $this->template->perPage,
|
||||
"atBottom" => false,
|
||||
"tidy" => true,
|
||||
"space" => 6,
|
||||
'pageCount' => ceil($count / $this->template->perPage),
|
||||
];
|
||||
$this->template->extendedPaginatorConf = clone $this->template->paginatorConf;
|
||||
$this->template->extendedPaginatorConf->space = 12;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -329,13 +329,15 @@ final class UserPresenter extends OpenVKPresenter
|
|||
$user = $this->users->get((int) $this->postParam("id"));
|
||||
if(!$user) exit("Invalid state");
|
||||
|
||||
if ($this->postParam("act") == "rej")
|
||||
$user->changeFlags($this->user->identity, 0b10000000, true);
|
||||
else
|
||||
$user->toggleSubscription($this->user->identity);
|
||||
|
||||
$this->redirect($user->getURL());
|
||||
$this->redirect($_SERVER['HTTP_REFERER']);
|
||||
}
|
||||
|
||||
function renderSetAvatar()
|
||||
{
|
||||
function renderSetAvatar() {
|
||||
$this->assertUserLoggedIn();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
|
@ -346,8 +348,8 @@ final class UserPresenter extends OpenVKPresenter
|
|||
$photo->setFile($_FILES["blob"]);
|
||||
$photo->setCreated(time());
|
||||
$photo->save();
|
||||
} catch(ISE $ex) {
|
||||
$this->flashFail("err", tr("error"), tr("error_upload_failed"));
|
||||
} catch(\Throwable $ex) {
|
||||
$this->flashFail("err", tr("error"), tr("error_upload_failed"), NULL, (int)$this->postParam("ajax", true) == 1);
|
||||
}
|
||||
|
||||
$album = (new Albums)->getUserAvatarAlbum($this->user->identity);
|
||||
|
@ -358,6 +360,7 @@ final class UserPresenter extends OpenVKPresenter
|
|||
$flags = 0;
|
||||
$flags |= 0b00010000;
|
||||
|
||||
if($this->postParam("on_wall") == 1) {
|
||||
$post = new Post;
|
||||
$post->setOwner($this->user->id);
|
||||
$post->setWall($this->user->id);
|
||||
|
@ -365,17 +368,50 @@ final class UserPresenter extends OpenVKPresenter
|
|||
$post->setContent("");
|
||||
$post->setFlags($flags);
|
||||
$post->save();
|
||||
|
||||
$post->attach($photo);
|
||||
if($this->postParam("ava", true) == (int)1) {
|
||||
}
|
||||
|
||||
if((int)$this->postParam("ajax", true) == 1) {
|
||||
$this->returnJson([
|
||||
"success" => true,
|
||||
"new_photo" => $photo->getPrettyId(),
|
||||
"url" => $photo->getURL(),
|
||||
"id" => $photo->getPrettyId()
|
||||
]);
|
||||
} else {
|
||||
$this->flashFail("succ", tr("photo_saved"), tr("photo_saved_comment"));
|
||||
}
|
||||
}
|
||||
|
||||
function renderDeleteAvatar() {
|
||||
$this->assertUserLoggedIn();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$avatar = $this->user->identity->getAvatarPhoto();
|
||||
|
||||
if(!$avatar)
|
||||
$this->flashFail("succ", tr("error"), "no avatar bro", NULL, true);
|
||||
|
||||
$avatar->isolate();
|
||||
|
||||
$newAvatar = $this->user->identity->getAvatarPhoto();
|
||||
|
||||
if(!$newAvatar)
|
||||
$this->returnJson([
|
||||
"success" => true,
|
||||
"has_new_photo" => false,
|
||||
"new_photo" => NULL,
|
||||
"url" => "/assets/packages/static/openvk/img/camera_200.png",
|
||||
]);
|
||||
else
|
||||
$this->returnJson([
|
||||
"success" => true,
|
||||
"has_new_photo" => true,
|
||||
"new_photo" => $newAvatar->getPrettyId(),
|
||||
"url" => $newAvatar->getURL(),
|
||||
]);
|
||||
}
|
||||
|
||||
function renderSettings(): void
|
||||
{
|
||||
$this->assertUserLoggedIn();
|
||||
|
|
|
@ -186,8 +186,12 @@ final class VKAPIPresenter extends OpenVKPresenter
|
|||
|
||||
function renderRoute(string $object, string $method): void
|
||||
{
|
||||
$callback = $this->queryParam("callback");
|
||||
$authMechanism = $this->queryParam("auth_mechanism") ?? "token";
|
||||
if($authMechanism === "roaming") {
|
||||
if($callback)
|
||||
$this->fail(-1, "User authorization failed: roaming mechanism is unavailable with jsonp.", $object, $method);
|
||||
|
||||
if(!$this->user->identity)
|
||||
$this->fail(5, "User authorization failed: roaming mechanism is selected, but user is not logged in.", $object, $method);
|
||||
else
|
||||
|
@ -234,8 +238,14 @@ final class VKAPIPresenter extends OpenVKPresenter
|
|||
}
|
||||
|
||||
try {
|
||||
// Проверка типа параметра
|
||||
$type = $parameter->getType();
|
||||
if (($type && !$type->isBuiltin()) || is_null($val)) {
|
||||
$params[] = $val;
|
||||
} else {
|
||||
settype($val, $parameter->getType()->getName());
|
||||
$params[] = $val;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// Just ignore the exception, since
|
||||
// some args are intended for internal use
|
||||
|
@ -254,9 +264,15 @@ final class VKAPIPresenter extends OpenVKPresenter
|
|||
"response" => $res,
|
||||
]);
|
||||
|
||||
$size = strlen($result);
|
||||
if($callback) {
|
||||
$result = $callback . '(' . $result . ')';
|
||||
header('Content-Type: application/javascript');
|
||||
} else
|
||||
header("Content-Type: application/json");
|
||||
|
||||
$size = strlen($result);
|
||||
header("Content-Length: $size");
|
||||
|
||||
exit($result);
|
||||
}
|
||||
|
||||
|
@ -286,17 +302,31 @@ final class VKAPIPresenter extends OpenVKPresenter
|
|||
$this->fail(28, "Invalid 2FA code", "internal", "acquireToken");
|
||||
}
|
||||
|
||||
$token = NULL;
|
||||
$tokenIsStale = true;
|
||||
$platform = $this->requestParam("client_name");
|
||||
$acceptsStale = $this->requestParam("accepts_stale");
|
||||
if($acceptsStale == "1") {
|
||||
if(is_null($platform))
|
||||
$this->fail(101, "accepts_stale can only be used with explicitly set client_name", "internal", "acquireToken");
|
||||
|
||||
$token = (new APITokens)->getStaleByUser($uId, $platform);
|
||||
}
|
||||
|
||||
if(is_null($token)) {
|
||||
$tokenIsStale = false;
|
||||
|
||||
$token = new APIToken;
|
||||
$token->setUser($user);
|
||||
$token->setPlatform($platform ?? (new WhichBrowser\Parser(getallheaders()))->toString());
|
||||
$token->save();
|
||||
}
|
||||
|
||||
$payload = json_encode([
|
||||
"access_token" => $token->getFormattedToken(),
|
||||
"expires_in" => 0,
|
||||
"user_id" => $uId,
|
||||
"is_stale" => $tokenIsStale,
|
||||
]);
|
||||
|
||||
$size = strlen($payload);
|
||||
|
@ -304,4 +334,42 @@ final class VKAPIPresenter extends OpenVKPresenter
|
|||
header("Content-Length: $size");
|
||||
exit($payload);
|
||||
}
|
||||
|
||||
function renderOAuthLogin() {
|
||||
$this->assertUserLoggedIn();
|
||||
|
||||
$client = $this->queryParam("client_name");
|
||||
$postmsg = $this->queryParam("prefers_postMessage") ?? '0';
|
||||
$stale = $this->queryParam("accepts_stale") ?? '0';
|
||||
$origin = NULL;
|
||||
$url = $this->queryParam("redirect_uri");
|
||||
if(is_null($url) || is_null($client))
|
||||
exit("<b>Error:</b> redirect_uri and client_name params are required.");
|
||||
|
||||
if($url != "about:blank") {
|
||||
if(!filter_var($url, FILTER_VALIDATE_URL))
|
||||
exit("<b>Error:</b> Invalid URL passed to redirect_uri.");
|
||||
|
||||
$parsedUrl = (object) parse_url($url);
|
||||
if($parsedUrl->scheme != 'https' && $parsedUrl->scheme != 'http')
|
||||
exit("<b>Error:</b> redirect_uri should either point to about:blank or to a web resource.");
|
||||
|
||||
$origin = "$parsedUrl->scheme://$parsedUrl->host";
|
||||
if(!is_null($parsedUrl->port ?? NULL))
|
||||
$origin .= ":$parsedUrl->port";
|
||||
|
||||
$url .= strpos($url, '?') === false ? '?' : '&';
|
||||
} else {
|
||||
$url .= "#";
|
||||
if($postmsg == '1') {
|
||||
exit("<b>Error:</b> prefers_postMessage can only be set if redirect_uri is not about:blank");
|
||||
}
|
||||
}
|
||||
|
||||
$this->template->clientName = $client;
|
||||
$this->template->usePostMessage = $postmsg == '1';
|
||||
$this->template->acceptsStale = $stale == '1';
|
||||
$this->template->origin = $origin;
|
||||
$this->template->redirectUri = $url;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,11 @@
|
|||
{script "js/l10n.js"}
|
||||
{script "js/openvk.cls.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"}
|
||||
|
||||
{css "js/node_modules/tippy.js/dist/backdrop.css"}
|
||||
{css "js/node_modules/cropperjs/dist/cropper.css"}
|
||||
{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"}
|
||||
|
@ -85,7 +87,7 @@
|
|||
|
||||
<div class="layout">
|
||||
<div id="xhead" class="dm"></div>
|
||||
<div class="page_header{if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME} page_custom_header{/if}">
|
||||
<div class="page_header{if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME} page_custom_header{/if}{if $atSearch} search_expanded search_expanded_at_all{/if}">
|
||||
<a href="/" class="home_button{if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME} home_button_custom{/if}" title="{$instance_name}">{if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME}{$instance_name}{/if}</a>
|
||||
<div n:if="isset($thisUser) ? (!$thisUser->isBanned() XOR !$thisUser->isActivated()) : true" class="header_navigation">
|
||||
{ifset $thisUser}
|
||||
|
@ -94,67 +96,45 @@
|
|||
<a href="/logout?hash={urlencode($csrfToken)}">{_header_log_out}</a>
|
||||
</div>
|
||||
{else}
|
||||
<div class="link dec">
|
||||
<div class="link">
|
||||
<a href="/">{_header_home}</a>
|
||||
</div>
|
||||
<div class="link dec">
|
||||
<a href="/search?type=groups">{_header_groups}</a>
|
||||
<div class="link">
|
||||
<a href="/search?section=groups">{_header_groups}</a>
|
||||
</div>
|
||||
<div class="link dec">
|
||||
<a href="/search">{_header_search}</a>
|
||||
<div class="link">
|
||||
<a href="/search?q=§ion=users&order=rating">{_header_search}</a>
|
||||
</div>
|
||||
<div class="link dec">
|
||||
<div class="link">
|
||||
<a href="/invite">{_header_invite}</a>
|
||||
</div>
|
||||
<div class="link dec">
|
||||
<div class="link">
|
||||
<a href="/support">{_header_help} <b n:if="$ticketAnsweredCount > 0">({$ticketAnsweredCount})</b></a>
|
||||
</div>
|
||||
<div class="link dec">
|
||||
<div class="link">
|
||||
<a href="/logout?hash={urlencode($csrfToken)}">{_header_log_out}</a>
|
||||
</div>
|
||||
{var $atSearch = str_contains($_SERVER['REQUEST_URI'], "/search")}
|
||||
<div id="srch" class="{if $atSearch}nodivider{else}link{/if}">
|
||||
|
||||
{if !$atSearch}
|
||||
<form action="/search" method="get" id="searcher" style="position:relative;">
|
||||
<input autocomplete="off" id="searchInput" oninput="checkSearchTips()" onfocus="expandSearch()" onblur="decreaseSearch()" class="sr" type="search" name="query" placeholder="{_header_search}" style="height: 20px;background: url('/assets/packages/static/openvk/img/search_icon.png') no-repeat 3px 4px; background-color: #fff; padding-left: 18px;width: 120px;" title="{_header_search} [Alt+Shift+F]" accesskey="f" />
|
||||
<select onchange="checkSearchTips()" id="typer" name="type" class="whatFind" style="display:none;top: 0px;">
|
||||
<option value="users">{_s_by_people}</option>
|
||||
<option value="groups">{_s_by_groups}</option>
|
||||
<option value="posts">{_s_by_posts}</option>
|
||||
<option value="comments">{_s_by_comments}</option>
|
||||
<option value="videos">{_s_by_videos}</option>
|
||||
<option value="apps">{_s_by_apps}</option>
|
||||
<option value="audios">{_s_by_audios}</option>
|
||||
<div id="search_box" class='header_divider_stick'>
|
||||
<div id="search_box_fr">
|
||||
<form id='search_form' action="/search" method="get">
|
||||
<div id='search_and_one_more_wrapper'>
|
||||
<input n:attr="value => $_REQUEST['q'] ? $_REQUEST['q'] : NULL" autocomplete="off" type="search" maxlength="79" name="q" placeholder="{_header_search}" title="{_header_search} [Alt+Shift+F]" accesskey="f" />
|
||||
<select name="section">
|
||||
<option n:attr="selected => $_REQUEST['section'] == 'users'" value="users">{_s_by_people}</option>
|
||||
<option n:attr="selected => $_REQUEST['section'] == 'groups'" value="groups">{_s_by_groups}</option>
|
||||
<option n:attr="selected => $_REQUEST['section'] == 'posts'" value="posts">{_s_by_posts}</option>
|
||||
<option n:attr="selected => $_REQUEST['section'] == 'videos'" value="videos">{_s_by_videos}</option>
|
||||
<option n:attr="selected => $_REQUEST['section'] == 'apps'" value="apps">{_s_by_apps}</option>
|
||||
<option n:attr="selected => $_REQUEST['section'] == 'audios'" value="audios">{_s_by_audios}</option>
|
||||
<option n:attr="selected => $_REQUEST['section'] == 'audios_playlists'" value="audios_playlists">{_s_by_audios_playlists}</option>
|
||||
</select>
|
||||
</form>
|
||||
<div class="searchTips" id="srcht" hidden>
|
||||
<table style="border:none;border-spacing: 0;">
|
||||
<tbody id="srchrr">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{else}
|
||||
<form action="/search" method="get" id="searcher" style="margin-top: -1px;position:relative;">
|
||||
<input id="searchInput" value="{$_GET['query'] ?? ''}" type="search" class="sr" name="query" placeholder="{_header_search}" style="height: 20px; background-color: #fff; padding-left: 6px;width: 555px;" title="{_header_search} [Alt+Shift+F]" accesskey="f" />
|
||||
<select name="type" class="whatFind">
|
||||
<option value="users" {if str_contains($_SERVER['REQUEST_URI'], "type=users")}selected{/if}>{_s_by_people}</option>
|
||||
<option value="groups" {if str_contains($_SERVER['REQUEST_URI'], "type=groups")}selected{/if}>{_s_by_groups}</option>
|
||||
<option value="posts" {if str_contains($_SERVER['REQUEST_URI'], "type=posts")}selected{/if}>{_s_by_posts}</option>
|
||||
<option value="comments" {if str_contains($_SERVER['REQUEST_URI'], "type=comments")}selected{/if}>{_s_by_comments}</option>
|
||||
<option value="videos" {if str_contains($_SERVER['REQUEST_URI'], "type=videos")}selected{/if}>{_s_by_videos}</option>
|
||||
<option value="apps" {if str_contains($_SERVER['REQUEST_URI'], "type=apps")}selected{/if}>{_s_by_apps}</option>
|
||||
<option value="audios" {if str_contains($_SERVER['REQUEST_URI'], "type=audios")}selected{/if}>{_s_by_audios}</option>
|
||||
</select>
|
||||
<button class="searchBtn"><span style="color:white;font-weight: 600;font-size:12px;">{_header_search}</span></button>
|
||||
<button class="search_box_button">
|
||||
<span>{_header_search}</span>
|
||||
</button>
|
||||
</form>
|
||||
<script>
|
||||
let els = document.querySelectorAll("div.dec")
|
||||
for(const element of els) {
|
||||
element.style.display = "none"
|
||||
}
|
||||
</script>
|
||||
{/if}
|
||||
</div>
|
||||
<div id="searchBoxFastTips"></div>
|
||||
</div>
|
||||
{/if}
|
||||
{else}
|
||||
|
@ -178,9 +158,9 @@
|
|||
<a href="/edit" class="link edit-button">{_edit_button}</a>
|
||||
<a href="{$thisUser->getURL()}" class="link" title="{_my_page} [Alt+Shift+.]" accesskey=".">{_my_page}</a>
|
||||
<a href="/friends{$thisUser->getId()}" class="link">{_my_friends}
|
||||
<object type="internal/link" n:if="$thisUser->getFollowersCount() > 0">
|
||||
<object type="internal/link" n:if="$thisUser->getRequestsCount() > 0">
|
||||
<a href="/friends{$thisUser->getId()}?act=incoming" class="linkunderline">
|
||||
(<b>{$thisUser->getFollowersCount()}</b>)
|
||||
(<b>{$thisUser->getRequestsCount()}</b>)
|
||||
</a>
|
||||
</object>
|
||||
</a>
|
||||
|
@ -196,9 +176,9 @@
|
|||
<a n:if="$thisUser->getLeftMenuItemStatus('groups')" href="/groups{$thisUser->getId()}" class="link">{_my_groups}</a>
|
||||
<a n:if="$thisUser->getLeftMenuItemStatus('news')" href="/feed" class="link" title="{_my_feed} [Alt+Shift+,]" accesskey=",">{_my_feed}</a>
|
||||
<a href="/notifications" class="link" title="{_my_feedback} [Alt+Shift+N]" accesskey="n">{_my_feedback}
|
||||
{if $thisUser->getNotificationsCount() > 0}
|
||||
<object type="internal/link" n:if="$thisUser->getNotificationsCount() > 0">
|
||||
(<b>{$thisUser->getNotificationsCount()}</b>)
|
||||
{/if}
|
||||
</object>
|
||||
</a>
|
||||
<a n:if="$thisUser->getLeftMenuItemStatus('apps')" href="/apps?act=installed" class="link">{_my_apps}</a>
|
||||
<a href="/settings" class="link">{_my_settings}</a>
|
||||
|
@ -398,19 +378,13 @@
|
|||
{script "js/al_mentions.js"}
|
||||
{script "js/al_polls.js"}
|
||||
{script "js/al_suggestions.js"}
|
||||
{script "js/al_navigation.js"}
|
||||
|
||||
{ifset $thisUser}
|
||||
{script "js/al_notifs.js"}
|
||||
{script "js/al_feed.js"}
|
||||
{/ifset}
|
||||
|
||||
{if OPENVK_ROOT_CONF['openvk']['preferences']['bellsAndWhistles']['fartscroll']}
|
||||
<script src="https://unpkg.com/fartscroll@1.0.0/fartscroll.js"></script>
|
||||
<script>
|
||||
fartscroll(400);
|
||||
</script>
|
||||
{/if}
|
||||
|
||||
<script>bsdnHydrate();</script>
|
||||
|
||||
<script n:if="OPENVK_ROOT_CONF['openvk']['telemetry']['plausible']['enable']" async defer data-domain="{php echo OPENVK_ROOT_CONF['openvk']['telemetry']['plausible']['domain']}" src="{php echo OPENVK_ROOT_CONF['openvk']['telemetry']['plausible']['server']}js/plausible.js"></script>
|
||||
|
@ -448,7 +422,8 @@
|
|||
|
||||
<script>
|
||||
window.openvk = {
|
||||
"audio_genres": {\openvk\Web\Models\Entities\Audio::genres}
|
||||
"audio_genres": {\openvk\Web\Models\Entities\Audio::genres},
|
||||
"at_search": {$atSearch ?? false},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
{include description, x => $dat}
|
||||
{/ifset}
|
||||
</td>
|
||||
<td n:ifset="actions" valign="top" class="action_links" style="width: 150px;">
|
||||
<td n:ifset="actions" valign="top" class="action_links" style="min-width: 150px;">
|
||||
{include actions, x => $dat}
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -255,17 +255,6 @@
|
|||
Disabled
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="e">
|
||||
Fartscroll
|
||||
</td>
|
||||
<td class="v">
|
||||
{php echo OPENVK_ROOT_CONF["openvk"]["preferences"]["bellsAndWhistles"]["fartscroll"] ? "Enabled" : "Disabled"}
|
||||
</td>
|
||||
<td class="v">
|
||||
Disabled
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="e">
|
||||
NDA Test Label
|
||||
|
@ -282,7 +271,7 @@
|
|||
Number verification
|
||||
</td>
|
||||
<td class="v">
|
||||
{php echo OPENVK_ROOT_CONF["openvk"]["credentials"]["zadarma"]["enable"] ? "SMS (Zadarma)" : "Disabled"}
|
||||
{php echo OPENVK_ROOT_CONF["openvk"]["credentials"]["smsc"]["enable"] ? "SMS" : "Disabled"}
|
||||
</td>
|
||||
<td class="v">
|
||||
Disabled
|
||||
|
@ -364,21 +353,21 @@
|
|||
Vladimir Barinov, Konstantin Kichulkin and Daniel Myslivets
|
||||
</td>
|
||||
</tr>
|
||||
<tr n:foreach="$themes as $theme">
|
||||
<tr n:foreach="$themes as $themeEntry">
|
||||
<td class="e">
|
||||
{$theme->getName()}
|
||||
{$themeEntry->getName()}
|
||||
</td>
|
||||
<td class="v">
|
||||
{$theme->isEnabled() ? "Enabled" : "Installed"}
|
||||
{$themeEntry->isEnabled() ? "Enabled" : "Installed"}
|
||||
</td>
|
||||
<td class="v">
|
||||
{$theme->getVersion()}
|
||||
{$themeEntry->getVersion()}
|
||||
</td>
|
||||
<td class="v">
|
||||
{$theme->getDescription()|truncate:20}
|
||||
{$themeEntry->getDescription()|truncate:20}
|
||||
</td>
|
||||
<td class="v">
|
||||
{$theme->getAuthor()}
|
||||
{$themeEntry->getAuthor()}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -58,13 +58,17 @@
|
|||
</div>
|
||||
<br/>
|
||||
<div class="group">
|
||||
<input class="toggle-large" type="checkbox" id="verify" name="verify" value="1" {if $club->isVerified()} checked {/if} />
|
||||
<input class="toggle-large" type="checkbox" id="verify" name="verify" value="1" n:attr="checked => $club->isVerified()" />
|
||||
<label for="verify">{_admin_verification}</label>
|
||||
</div>
|
||||
<div class="group">
|
||||
<input class="toggle-large" type="checkbox" id="hide_from_global_feed" name="hide_from_global_feed" value="1" {if $club->isHideFromGlobalFeedEnabled()} checked {/if} />
|
||||
<input class="toggle-large" type="checkbox" id="hide_from_global_feed" name="hide_from_global_feed" value="1" n:attr="checked => $club->isHideFromGlobalFeedEnabled()" />
|
||||
<label for="hide_from_global_feed">{_admin_club_excludeglobalfeed}</label>
|
||||
</div>
|
||||
<div class="group">
|
||||
<input class="toggle-large" type="checkbox" id="enforce_hiding_from_global_feed" name="enforce_hiding_from_global_feed" value="1" n:attr="checked => $club->isHidingFromGlobalFeedEnforced()" />
|
||||
<label for="enforce_hiding_from_global_feed">{_admin_club_enforceexcludeglobalfeed}</label>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="buttons-container">
|
||||
<div class="buttons">
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
|
||||
{block content}
|
||||
<center>
|
||||
<iframe id="appFrame" referrerpolicy="unsafe-url" sandbox="allow-scripts" frameBorder="0" src="{$url}" height="600" width="600"></iframe>
|
||||
<iframe id="appFrame" referrerpolicy="unsafe-url" frameBorder="0" src="{$url}" height="600" width="600"
|
||||
sandbox="allow-scripts allow-same-origin allow-pointer-lock allow-forms allow-downloads-without-user-activation"></iframe>
|
||||
</center>
|
||||
|
||||
<div n:if="!is_null($news)" id="news">
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
{block header}
|
||||
<a href="{$owner->getURL()}">{$owner->getCanonicalName()}</a>
|
||||
»
|
||||
<a href="/audios{$ownerId}">{_audios}</a>
|
||||
<a href="/playlists{$ownerId}">{_playlists}</a>
|
||||
»
|
||||
<a href="/playlist{$playlist->getPrettyId()}">{_playlist}</a>
|
||||
»
|
||||
|
@ -30,8 +30,13 @@
|
|||
</div>
|
||||
|
||||
<div class="moreInfo">
|
||||
<textarea name="description" maxlength="2045" style="margin-top: 11px;">{$playlist->getDescription()}</textarea>
|
||||
<textarea placeholder="{_description}" name="description" maxlength="2045" style="margin-top: 11px;">{$playlist->getDescription()}</textarea>
|
||||
</div>
|
||||
|
||||
<label>
|
||||
<input type='checkbox' name='is_unlisted' n:attr='checked => $playlist->isUnlisted()'>
|
||||
{_playlist_hide_from_search}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -56,6 +61,7 @@
|
|||
<form method="post" id="editPlaylistForm" data-id="{$playlist->getId()}" enctype="multipart/form-data">
|
||||
<input type="hidden" name="title" maxlength="128" />
|
||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||
<input type="hidden" name="is_unlisted" value="0" />
|
||||
<textarea style="display:none;" name="description" maxlength="2048" />
|
||||
<input type="hidden" name="audios">
|
||||
<input type="file" style="display:none;" name="new_cover" accept=".jpg,.png">
|
||||
|
@ -71,6 +77,7 @@
|
|||
u("#editPlaylistForm").on("submit", (e) => {
|
||||
document.querySelector("#editPlaylistForm input[name='title']").value = document.querySelector(".playlistInfo input[name='title']").value
|
||||
document.querySelector("#editPlaylistForm textarea[name='description']").value = document.querySelector(".playlistBlock textarea[name='description']").value
|
||||
document.querySelector("#editPlaylistForm input[name='is_unlisted']").value = document.querySelector("input[name='is_unlisted']").checked ? 1 : 0
|
||||
})
|
||||
|
||||
u("#editPlaylistForm input[name='new_cover']").on("change", (e) => {
|
||||
|
|
|
@ -59,11 +59,10 @@
|
|||
<input n:if="$mode == 'popular'" type="hidden" name="bigplayer_context" data-type="popular_audios" data-entity="0" data-page="1">
|
||||
<div class="bigPlayerDetector"></div>
|
||||
|
||||
<div style="width: 100%;display: flex;margin-bottom: -10px;" class="audiosDiv">
|
||||
<div style="width: 74%;" class="audiosContainer" n:if="$mode != 'playlists'">
|
||||
<div style="padding: 8px;">
|
||||
<div n:if="$audiosCount <= 0">
|
||||
{include "../components/error.xml", description => $ownerId > 0 ? ($ownerId == $thisUser->getId() ? tr("no_audios_thisuser") : tr("no_audios_user")) : tr("no_audios_club")}
|
||||
<div class="audiosDiv">
|
||||
<div style="width: 74%;" class="audiosContainer audiosPaddingContainer" n:if="$mode != 'playlists'">
|
||||
<div n:if="$audiosCount <= 0" style='height: 50%;'>
|
||||
{include "../components/content_error.xml", description => $ownerId > 0 ? ($ownerId == $thisUser->getId() ? tr("no_audios_thisuser") : tr("no_audios_user")) : tr("no_audios_club")}
|
||||
</div>
|
||||
<div n:if="$audiosCount > 0" class="infContainer">
|
||||
<div class="infObj" n:foreach="$audios as $audio">
|
||||
|
@ -81,33 +80,16 @@
|
|||
]}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="width: 74%;" n:if="$mode == 'playlists'">
|
||||
<div style="padding: 8px;">
|
||||
<div n:if="$playlistsCount <= 0">
|
||||
{include "../components/error.xml", description => $ownerId > 0 ? ($ownerId == $thisUser->getId() ? tr("no_playlists_thisuser") : tr("no_playlists_user")) : tr("no_playlists_club")}
|
||||
<div style="width: 71.8%;" class="audiosPaddingContainer audiosPaddingContainer" n:if="$mode == 'playlists'">
|
||||
<div n:if="$playlistsCount <= 0" style='height: 100%;'>
|
||||
{include "../components/content_error.xml", description => $ownerId > 0 ? ($ownerId == $thisUser->getId() ? tr("no_playlists_thisuser") : tr("no_playlists_user")) : tr("no_playlists_club")}
|
||||
</div>
|
||||
|
||||
<div class="infContainer playlistContainer" n:if="$playlistsCount > 0">
|
||||
<div class="infObj" n:foreach="$playlists as $playlist">
|
||||
<a href="/playlist{$playlist->getPrettyId()}">
|
||||
<div class="playlistCover">
|
||||
<img src="{$playlist->getCoverURL()}" alt="{_playlist_cover}">
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="playlistInfo">
|
||||
<a href="/playlist{$playlist->getPrettyId()}">
|
||||
<span style="font-size: 12px" class="playlistName">
|
||||
{ovk_proc_strtr($playlist->getName(), 15)}
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a href="{$playlist->getOwner()->getURL()}">{ovk_proc_strtr($playlist->getOwner()->getCanonicalName(), 20)}</a>
|
||||
</div>
|
||||
</div>
|
||||
{foreach $playlists as $playlist}
|
||||
{include 'playlistListView.xml', playlist => $playlist}
|
||||
{/foreach}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
@ -120,7 +102,6 @@
|
|||
]}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{include "tabs.xml"}
|
||||
</div>
|
||||
{/block}
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
{if !$_GET["gid"]}
|
||||
<a href="{$thisUser->getURL()}">{$thisUser->getCanonicalName()}</a>
|
||||
»
|
||||
<a href="/audios{$thisUser->getId()}">{_audios}</a>
|
||||
<a href="/playlists{$thisUser->getId()}">{_playlists}</a>
|
||||
{else}
|
||||
<a href="{$club->getURL()}">{$club->getCanonicalName()}</a>
|
||||
»
|
||||
<a href="/audios-{$club->getId()}">{_audios}</a>
|
||||
<a href="/playlists-{$club->getId()}">{_playlists}</a>
|
||||
{/if}
|
||||
»
|
||||
{_new_playlist}
|
||||
|
@ -44,6 +44,10 @@
|
|||
<div class="moreInfo" style="margin-top: 11px;">
|
||||
<textarea placeholder="{_description}" name="description" maxlength="2045" />
|
||||
</div>
|
||||
<label>
|
||||
<input type='checkbox' name='is_unlisted'>
|
||||
{_playlist_hide_from_search}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -68,6 +72,7 @@
|
|||
<form method="post" id="newPlaylistForm" enctype="multipart/form-data">
|
||||
<input type="hidden" name="title" maxlength="125" />
|
||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||
<input type="hidden" name="is_unlisted" value="0" />
|
||||
<textarea style="display:none;" name="description" maxlength="2045" />
|
||||
<input type="hidden" name="audios">
|
||||
<input type="file" style="display:none;" name="cover" accept=".jpg,.png">
|
||||
|
@ -83,6 +88,7 @@
|
|||
u("#newPlaylistForm").on("submit", (e) => {
|
||||
document.querySelector("#newPlaylistForm input[name='title']").value = document.querySelector(".plinfo input[name='title']").value
|
||||
document.querySelector("#newPlaylistForm textarea[name='description']").value = document.querySelector(".plinfo textarea[name='description']").value
|
||||
document.querySelector("#newPlaylistForm input[name='is_unlisted']").value = document.querySelector(".plinfo input[name='is_unlisted']").checked ? 1 : 0
|
||||
})
|
||||
|
||||
u("#newPlaylistForm input[name='cover']").on("change", (e) => {
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
{extends "../@layout.xml"}
|
||||
|
||||
{block title}{_playlist}{/block}
|
||||
{block title}
|
||||
{_playlist}
|
||||
{$playlist->getName()}
|
||||
{/block}
|
||||
|
||||
{block headIncludes}
|
||||
<meta property="og:type" content="music.album">
|
||||
<meta property="og:title" content="{$playlist->getName()}">
|
||||
<meta property="og:url" content="{$playlist->getURL()}">
|
||||
<meta property="og:description" content="{$playlist->getDescription()}">
|
||||
<meta property="og:image" content="{$playlist->getCoverURL()}">
|
||||
<meta property="og:image" content="{$cover_url}">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
|
@ -22,7 +25,7 @@
|
|||
{block header}
|
||||
<a href="{$owner->getURL()}">{$owner->getCanonicalName()}</a>
|
||||
»
|
||||
<a href="/audios{$ownerId}">{_audios}</a>
|
||||
<a href="/playlists{$ownerId}">{_playlists}</a>
|
||||
»
|
||||
{_playlist}
|
||||
{/block}
|
||||
|
@ -30,23 +33,28 @@
|
|||
{block content}
|
||||
{include "bigplayer.xml"}
|
||||
|
||||
{php $count = $playlist->size()}
|
||||
|
||||
<input type="hidden" name="bigplayer_context" data-type="playlist_context" data-entity="{$playlist->getId()}" data-page="{$page}">
|
||||
<div class="playlistBlock">
|
||||
<div class="playlistCover" style="float: left;">
|
||||
<a href="{$playlist->getCoverURL()}" target="_blank">
|
||||
<img src="{$playlist->getCoverURL('normal')}" alt="{_playlist_cover}">
|
||||
{if $cover}
|
||||
<a href="{$cover_url}" target="_blank">
|
||||
<img onclick="OpenMiniature(event, {$cover_url}, null, {$cover->getPrettyId()}, null)" src="{$cover_url}" alt="{_playlist_cover}">
|
||||
</a>
|
||||
{else}
|
||||
<a>
|
||||
<img src="{$cover_url}" alt="{_playlist_cover}">
|
||||
</a>
|
||||
{/if}
|
||||
|
||||
<div class="profile_links" style="width: 139px;" n:if="isset($thisUser)">
|
||||
<a class="profile_link" style="width: 98%;" href="/playlist{$playlist->getPrettyId()}/edit" n:if="$playlist->canBeModifiedBy($thisUser)">{_edit_playlist}</a>
|
||||
<a class="profile_link" style="width: 98%;" id="bookmarkPlaylist" data-id="{$playlist->getId()}" n:if="!$isBookmarked">{_bookmark}</a>
|
||||
<a class="profile_link" style="width: 98%;" id="unbookmarkPlaylist" data-id="{$playlist->getId()}" n:if="$isBookmarked">{_unbookmark}</a>
|
||||
<div class="profile_links" n:if="isset($thisUser)">
|
||||
<a class="profile_link" href="/player/upload?playlist={$playlist->getId()}" n:if="$canEdit">{_upload_audio}</a>
|
||||
<a class="profile_link" href="/playlist{$playlist->getPrettyId()}/edit" n:if="$canEdit">{_edit_playlist}</a>
|
||||
<a class="profile_link" id="bookmarkPlaylist" data-id="{$playlist->getId()}" n:if="!$isBookmarked">{_bookmark}</a>
|
||||
<a class="profile_link" id="unbookmarkPlaylist" data-id="{$playlist->getId()}" n:if="$isBookmarked">{_unbookmark}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="float: left;padding-left: 13px;width:75%">
|
||||
<div class='playlistWrapper'>
|
||||
<div class="playlistInfo">
|
||||
<h4 style="border-bottom:unset;">{$playlist->getName()}</h4>
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
{/block}
|
||||
|
||||
{block header}
|
||||
{if !$playlist}
|
||||
{if !is_null($group)}
|
||||
<a href="{$group->getURL()}">{$group->getCanonicalName()}</a>
|
||||
»
|
||||
|
@ -14,6 +15,13 @@
|
|||
»
|
||||
<a href="/audios{$thisUser->getId()}">{_audios}</a>
|
||||
{/if}
|
||||
{else}
|
||||
<a href="{$owner->getURL()}">{$owner->getCanonicalName()}</a>
|
||||
»
|
||||
<a href="/playlists{$ownerId}">{_playlists}</a>
|
||||
»
|
||||
<a href="/playlist{$playlist->getPrettyId()}">{_playlist}</a>
|
||||
{/if}
|
||||
|
||||
»
|
||||
{_upload_audio}
|
||||
|
@ -36,6 +44,7 @@
|
|||
<input type="hidden" name="lyrics" />
|
||||
<input type="hidden" name="genre" />
|
||||
<input type="hidden" name="explicit" />
|
||||
<input type="hidden" name="unlisted" />
|
||||
|
||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||
<input id="audio_input" type="file" name="blob" accept="audio/*" style="display:none" />
|
||||
|
@ -43,20 +52,20 @@
|
|||
</form>
|
||||
</div><br/>
|
||||
|
||||
<span>{_you_can_also_add_audio_using} <b><a href="/search?type=audios">{_search_audio_inst}</a></b>.<span>
|
||||
<span>{_you_can_also_add_audio_using} <b><a href="/search?section=audios">{_search_audio_inst}</a></b>.<span>
|
||||
</div>
|
||||
|
||||
<div id="lastStep" style="display:none;">
|
||||
<table cellspacing="7" cellpadding="0" border="0" align="center">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="120" valign="top"><span class="nobold">{_audio_name}:</span></td>
|
||||
<td><input type="text" name="name" autocomplete="off" maxlength="80" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="120" valign="top"><span class="nobold">{_performer}:</span></td>
|
||||
<td><input name="performer" type="text" autocomplete="off" maxlength="80" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="120" valign="top"><span class="nobold">{_audio_name}:</span></td>
|
||||
<td><input type="text" name="name" autocomplete="off" maxlength="80" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="120" valign="top"><span class="nobold">{_genre}:</span></td>
|
||||
<td>
|
||||
|
@ -74,7 +83,8 @@
|
|||
<tr>
|
||||
<td width="120" valign="top"></td>
|
||||
<td>
|
||||
<label><input type="checkbox" name="explicit">{_audios_explicit}</label>
|
||||
<label style='display:block'><input type="checkbox" name="explicit">{_audios_explicit}</label>
|
||||
<label><input type="checkbox" name="unlisted">{_audios_unlisted}</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -101,7 +111,23 @@
|
|||
document.querySelector("#firstStep").style.display = "none"
|
||||
document.querySelector("#lastStep").style.display = "block"
|
||||
|
||||
let tags = await id3.fromFile(files[0]);
|
||||
function fallback() {
|
||||
console.info('Tags not found, setting default values.')
|
||||
|
||||
document.querySelector("#lastStep input[name=name]").value = files[0].name
|
||||
document.querySelector("#lastStep select[name=genre]").value = "Other"
|
||||
document.querySelector("#lastStep input[name=performer]").value = tr("track_unknown");
|
||||
}
|
||||
|
||||
let tags = null
|
||||
|
||||
try {
|
||||
tags = await id3.fromFile(files[0]);
|
||||
} catch(e) {
|
||||
console.error(e)
|
||||
}
|
||||
|
||||
console.log(tags)
|
||||
if(tags != null) {
|
||||
console.log("ID" + tags.kind + " detected, setting values...");
|
||||
|
||||
|
@ -116,6 +142,16 @@
|
|||
document.querySelector("#lastStep input[name=performer]").value = tr("track_unknown");
|
||||
|
||||
if(tags.genre != null) {
|
||||
// if there are more than one genre
|
||||
if(tags.genre.split(', ').length > 1) {
|
||||
const genres = tags.genre.split(', ')
|
||||
|
||||
genres.forEach(genre => {
|
||||
if(document.querySelector("#lastStep select[name=genre] > option[value='" + genre + "']") != null) {
|
||||
document.querySelector("#lastStep select[name=genre]").value = genre;
|
||||
}
|
||||
})
|
||||
} else {
|
||||
if(document.querySelector("#lastStep select[name=genre] > option[value='" + tags.genre + "']") != null) {
|
||||
document.querySelector("#lastStep select[name=genre]").value = tags.genre;
|
||||
} else {
|
||||
|
@ -124,9 +160,13 @@
|
|||
}
|
||||
}
|
||||
} else {
|
||||
document.querySelector("#lastStep input[name=name]").value = files[0].name
|
||||
document.querySelector("#lastStep select[name=genre]").value = "Other"
|
||||
document.querySelector("#lastStep input[name=performer]").value = tr("track_unknown");
|
||||
}
|
||||
|
||||
if(tags.comments != null)
|
||||
document.querySelector("#lastStep textarea[name=lyrics]").value = tags.comments
|
||||
} else {
|
||||
fallback()
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -147,12 +187,14 @@
|
|||
var genre_ = document.querySelector("#audio_upload input[name=genre]");
|
||||
var lyrics_ = document.querySelector("#audio_upload input[name=lyrics]");
|
||||
var explicit_ = document.querySelector("#audio_upload input[name=explicit]");
|
||||
var unlisted_ = document.querySelector("#audio_upload input[name=unlisted]");
|
||||
|
||||
name_.value = document.querySelector("#lastStep input[name=name]").value
|
||||
perf_.value = document.querySelector("#lastStep input[name=performer]").value
|
||||
genre_.value = document.querySelector("#lastStep select[name=genre]").value
|
||||
lyrics_.value = document.querySelector("#lastStep textarea[name=lyrics]").value
|
||||
explicit_.value = document.querySelector("#lastStep input[name=explicit]").checked ? "on" : "off"
|
||||
unlisted_.value = document.querySelector("#lastStep input[name=unlisted]").checked ? "on" : "off"
|
||||
|
||||
$("#audio_upload > form").trigger("submit");
|
||||
})
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="bigPlayer">
|
||||
<div n:class="bigPlayer, $tidy ? tidy">
|
||||
<audio class="audio" />
|
||||
<div class="paddingLayer">
|
||||
<div class="playButtons">
|
||||
|
@ -18,21 +18,21 @@
|
|||
<div class="trackPanel">
|
||||
<div class="trackInfo">
|
||||
<div class="trackName">
|
||||
<b>{_track_unknown}</b> —
|
||||
<a>{_track_unknown}</a> —
|
||||
<span>{_track_noname}</span>
|
||||
</div>
|
||||
|
||||
<div class="timer" style="float:right">
|
||||
<span class="time">00:00</span>
|
||||
<span>/</span>
|
||||
<span class="elapsedTime" style="cursor:pointer">-00:00</span>
|
||||
<span class="elapsedTime">-00:00</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="track" style="margin-top: -2px;">
|
||||
<div class="bigPlayerTip">00:00</div>
|
||||
<div class="selectableTrack">
|
||||
<div style="width: 95%;position: relative;">
|
||||
<div id='bigPlayerLengthSliderWrapper'>
|
||||
<div class="slider"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -41,7 +41,7 @@
|
|||
|
||||
<div class="volumePanel">
|
||||
<div class="selectableTrack">
|
||||
<div style="position: relative;width:72%">
|
||||
<div id='bigPlayerVolumeSliderWrapper'>
|
||||
<div class="slider"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
{php $id = $audio->getId() . rand(0, 1000)}
|
||||
{php $isWithdrawn = $audio->isWithdrawn()}
|
||||
{php $isAvailable = $audio->isAvailable()}
|
||||
{php $editable = isset($thisUser) && $audio->canBeModifiedBy($thisUser)}
|
||||
<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 !$audio->isAvailable()}processed{/if} {if $isWithdrawn}withdrawn{/if}" data-length="{$audio->getLength()}" data-keys="{json_encode($audio->getKeys())}" data-url="{$audio->getURL()}">
|
||||
<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" style="min-height: 39px;">
|
||||
|
@ -11,29 +12,32 @@
|
|||
</div>
|
||||
|
||||
<div class="status" style="margin-top: 12px;">
|
||||
<div class="mediaInfo noOverflow" style="margin-bottom: -8px; cursor: pointer;display:flex;width: 85%;">
|
||||
<div class="mediaInfo noOverflow">
|
||||
<div class="info">
|
||||
<strong class="performer">
|
||||
<a href="/search?query=&type=audios&sort=id&only_performers=on&query={$audio->getPerformer()}">{$audio->getPerformer()}</a>
|
||||
<a href="/search?query=§ion=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>
|
||||
</div>
|
||||
|
||||
<div class="explicitMark" n:if="$audio->isExplicit()"></div>
|
||||
<svg n:if="$audio->isExplicit()" class="explicitMark" xmlns="http://www.w3.org/2000/svg" height="11" viewBox="0 0 11 11" width="11">
|
||||
<path d="m1 2.506v5.988a1.5 1.5 0 0 0 1.491 1.506h6.019c.827 0 1.49-.674 1.49-1.506v-5.988a1.5 1.5 0 0 0 -1.491-1.506h-6.019c-.827 0-1.49.674-1.49 1.506zm4 2.494v-1h2v-1h-3v5h3v-1h-2v-1h2v-1zm-5-2.494a2.496 2.496 0 0 1 2.491-2.506h6.019a2.5 2.5 0 0 1 2.49 2.506v5.988a2.496 2.496 0 0 1 -2.491 2.506h-6.019a2.5 2.5 0 0 1 -2.49-2.506z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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" style="margin-top: 8px;">
|
||||
<div class="buttons">
|
||||
{php $hasAudio = isset($thisUser) && $audio->isInLibraryOf($thisUser)}
|
||||
|
||||
{if !$hideButtons}
|
||||
<div class="remove-icon musicIcon" data-id="{$audio->getId()}" n:if="isset($thisUser) && $hasAudio" ></div>
|
||||
<div class="add-icon musicIcon hovermeicon" data-id="{$audio->getId()}" n:if="isset($thisUser) && !$hasAudio && !$isWithdrawn" ></div>
|
||||
<div class="remove-icon-group musicIcon" data-id="{$audio->getId()}" data-club="{$club->getId()}" n:if="isset($thisUser) && isset($club) && $club->canBeModifiedBy($thisUser)" ></div>
|
||||
<div class="add-icon-group musicIcon" data-id="{$audio->getId()}" n:if="isset($thisUser) && !$isWithdrawn" ></div>
|
||||
<div class="add-icon-group musicIcon hidden" data-id="{$audio->getId()}" n:if="isset($thisUser) && !$isWithdrawn" ></div>
|
||||
<a class="download-icon musicIcon" n:if='isset($thisUser) && !$isWithdrawn && $isAvailable && OPENVK_ROOT_CONF["openvk"]["preferences"]["music"]["exposeOriginalURLs"]' href="{$audio->getOriginalURL()}" download="{$audio->getDownloadName()}"></a>
|
||||
<div class="edit-icon musicIcon" data-lyrics="{$audio->getLyrics()}" data-title="{$audio->getTitle()}" data-performer="{$audio->getPerformer()}" data-explicit="{(int)$audio->isExplicit()}" data-searchable="{(int)!$audio->isUnlisted()}" n:if="isset($thisUser) && $editable && !$isWithdrawn" ></div>
|
||||
<div class="report-icon musicIcon" data-id="{$audio->getId()}" n:if="isset($thisUser) && !$editable && !$isWithdrawn" ></div>
|
||||
{/if}
|
||||
|
@ -41,20 +45,20 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="subTracks">
|
||||
<div style="width: 100%;">
|
||||
<div class="track lengthTrack" style="margin-top: 3px;display:none">
|
||||
<div class="selectableTrack" style="width: 100%;" n:attr="style => $isWithdrawn ? 'display: none;' : ''">
|
||||
<div style="position: relative;width: calc(100% - 18px);">
|
||||
<div class="lengthTrackWrapper">
|
||||
<div class="track lengthTrack">
|
||||
<div class="selectableTrack" n:attr="style => $isWithdrawn ? 'display: none;' : ''">
|
||||
<div class="selectableTrackSlider">
|
||||
<div class="slider"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="width: 81px;margin-left: 16px;">
|
||||
<div class="track volumeTrack" style="margin-top: 3px;display:none">
|
||||
<div class="selectableTrack" style="width: 100%;" n:attr="style => $isWithdrawn ? 'display: none;' : ''">
|
||||
<div style="position: relative;width: calc(100% - 18px);">
|
||||
<div class="volumeTrackWrapper">
|
||||
<div class="track volumeTrack">
|
||||
<div class="selectableTrack" n:attr="style => $isWithdrawn ? 'display: none;' : ''">
|
||||
<div class="selectableTrackSlider">
|
||||
<div class="slider"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
20
Web/Presenters/templates/Audio/playlistListView.xml
Normal file
20
Web/Presenters/templates/Audio/playlistListView.xml
Normal file
|
@ -0,0 +1,20 @@
|
|||
<a href="/playlist{$playlist->getPrettyId()}" class='playlistListView'>
|
||||
<div class="playlistCover">
|
||||
<img src="{$playlist->getCoverURL('normal')}" alt="{_playlist_cover}">
|
||||
</div>
|
||||
|
||||
<div class="playlistInfo">
|
||||
<div class="playlistInfoTopPart">
|
||||
<span class="playlistName noOverflow">
|
||||
{$playlist->getName()}
|
||||
</span>
|
||||
<span n:if='!empty($playlist->getDescription())' class="playlistDesc noOverflow">
|
||||
{$playlist->getDescription()}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<span class="playlistMeta">
|
||||
{$playlist->getMetaDescription()|noescape}
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
|
@ -1,10 +1,10 @@
|
|||
<div class="searchOptions newer">
|
||||
<div class="searchList" style="margin-top:10px">
|
||||
<a n:attr="id => $mode === 'list' && $isMy ? 'used' : 'ki'" href="/audios{$thisUser->getId()}" n:if="isset($thisUser)">{_my_music}</a>
|
||||
<a href="/player/upload{if $isMyClub}?gid={abs($ownerId)}{/if}" n:if="isset($thisUser)">{_upload_audio}</a>
|
||||
<a n:attr="id => $mode === 'new' ? 'used' : 'ki'" href="/audios/new">{_audio_new}</a>
|
||||
<a n:attr="id => $mode === 'popular' ? 'used' : 'ki'" href="/audios/popular">{_audio_popular}</a>
|
||||
<a href="/search?type=audios" n:if="isset($thisUser)">{_audio_search}</a>
|
||||
<div class='verticalGrayTabsWrapper'>
|
||||
<div class="verticalGrayTabs">
|
||||
<div class='with_padding'>
|
||||
<a n:if="isset($thisUser)" n:attr="id => $mode === 'list' && $isMy ? 'used' : 'ki'" href="/audios{$thisUser->getId()}">{_my_music}</a>
|
||||
<a n:if="isset($thisUser)" href="/player/upload{if $isMyClub}?gid={abs($ownerId)}{/if}">{_upload_audio}</a>
|
||||
<a n:if="isset($thisUser)" n:attr="id => $mode === 'new' ? 'used' : 'ki'" href="/search?section=audios">{_audio_new}</a>
|
||||
<a n:if="isset($thisUser)" n:attr="id => $mode === 'popular' ? 'used' : 'ki'" href="/search?section=audios&order=listens">{_audio_popular}</a>
|
||||
|
||||
<hr n:if="isset($thisUser)">
|
||||
|
||||
|
@ -20,16 +20,16 @@
|
|||
<a n:attr="id => $mode === 'playlists' && $ownerId != $thisUser->getId() ? 'used' : 'ki'" href="/playlists{$ownerId}" n:if="isset($thisUser) && isset($ownerId) && !$isMy">{if $ownerId > 0}{_playlists_user}{else}{_playlists_club}{/if}</a>
|
||||
<a href="/audios/newPlaylist{if $isMyClub}?gid={abs($ownerId)}{/if}" n:if="isset($thisUser) && $isMyClub">{_new_playlist}</a>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{if $friendsAudios}
|
||||
<div class="friendsAudiosList">
|
||||
<a href="/audios{$fr->getRealId()}" style="width: 94%;padding-left: 10px;" n:foreach="$friendsAudios as $fr">
|
||||
<a href="/audios{$fr->getRealId()}" n:foreach="$friendsAudios as $fr">
|
||||
<div class="elem">
|
||||
<img src="{$fr->getAvatarURL()}" />
|
||||
|
||||
<div class="additionalInfo">
|
||||
{php $audioStatus = $fr->getCurrentAudioStatus()}
|
||||
<span class="name">{$fr->getCanonicalName()}</span>
|
||||
<span class="name noOverflow">{$fr->getCanonicalName()}</span>
|
||||
<span class="desc">{$audioStatus ? $audioStatus->getName() : tr("audios_count", $fr->getAudiosCollectionSize())}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
{/block}
|
||||
|
||||
{block preview}
|
||||
<img src="{$x->getThumbnailURL()}" width="75" alt="{$x->getName(tr('__lang'))}" />
|
||||
<img src="{$x->getThumbnailURL()}" width="75" alt="{$x->getName(tr('__lang'))}" loading=lazy />
|
||||
{/block}
|
||||
|
||||
{block name}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
{block content}
|
||||
<div class="gift_grid">
|
||||
<div n:foreach="$gifts as $gift" n:class="gift_sel, !$gift->canUse($thisUser) ? disabled" data-gift="{$gift->getId()}">
|
||||
<img class="gift_pic" src="{$gift->getImage(2)}" alt="{_gift}" />
|
||||
<img class="gift_pic" src="{$gift->getImage(2)}" alt="{_gift}" loading=lazy />
|
||||
|
||||
<strong class="gift_price">
|
||||
{if $gift->isFree()}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
{/block}
|
||||
|
||||
{block preview}
|
||||
<img src="{$x->gift->getImage(2)}" width="75" alt="{_gift}" />
|
||||
<img src="{$x->gift->getImage(2)}" width="75" alt="{_gift}" loading=lazy />
|
||||
{/block}
|
||||
|
||||
{block name}
|
||||
|
|
|
@ -83,7 +83,7 @@
|
|||
<option value="0" n:attr="selected => $club->getWallType() == 0" /> {_group_closed_post}</option>
|
||||
<select>
|
||||
|
||||
<input type="checkbox" name="hide_from_global_feed" value="1" n:attr="checked => $club->isHideFromGlobalFeedEnabled()" /> {_group_hide_from_global_feed}
|
||||
<input type="checkbox" name="hide_from_global_feed" value="1" n:attr="checked => $club->isHideFromGlobalFeedEnabled(), disabled => $club->isHidingFromGlobalFeedEnforced()" /> {_group_hide_from_global_feed}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
|
@ -54,8 +54,8 @@
|
|||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="120" valign="top"><span class="nobold">{_gender}: </span></td>
|
||||
<td>{$user->isFemale() ? tr("female"): tr("male")}</td>
|
||||
<td width="120" valign="top"><span class="nobold">{_pronouns}: </span></td>
|
||||
<td>{$x->isFemale() ? tr("female") : ($x->isNeutral() ? tr("neutral") : tr("male"))}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="120" valign="top"><span class="nobold">{_registration_date}: </span></td>
|
||||
|
|
|
@ -127,25 +127,19 @@
|
|||
<div class="right_small_block">
|
||||
{var $avatarPhoto = $club->getAvatarPhoto()}
|
||||
{var $avatarLink = ((is_null($avatarPhoto) ? FALSE : $avatarPhoto->isAnonymous()) ? "/photo" . ("s/" . base_convert((string) $avatarPhoto->getId(), 10, 32)) : $club->getAvatarLink())}
|
||||
<div class="avatar_block" style="position:relative;">
|
||||
{var $hasAvatar = !str_contains($club->getAvatarUrl('miniscule'), "/assets/packages/static/openvk/img/camera_200.png")}
|
||||
{if !is_null($thisUser) && $hasAvatar == false && $club->canBeModifiedBy($thisUser)}
|
||||
<a href="javascript:addAvatarImage(true, {$club->getId()})" class="text_add_image">{_add_image_group}</a>
|
||||
{elseif !is_null($thisUser) && $hasAvatar == true && $club->canBeModifiedBy($thisUser)}
|
||||
<div class="avatar_controls">
|
||||
<div class="avatarDelete">
|
||||
<a id="upl" href="javascript:deleteAvatar('{$club->getAvatarPhoto()->getPrettyId()}')"><img src="/assets/packages/static/openvk/img/delete.png"/></a>
|
||||
</div>
|
||||
<div class="avatar_block" style="position:relative;" data-club="{$club->getId()}">
|
||||
{if $thisUser && $club->canBeModifiedBy($thisUser)}
|
||||
<a {if $avatarPhoto}style="display:none"{/if} class="add_image_text" id="add_image">{_add_image}</a>
|
||||
<div {if !$avatarPhoto}style="display:none"{/if} class="avatar_controls">
|
||||
<div class="avatarDelete hoverable"></div>
|
||||
<div class="avatar_variants">
|
||||
<div class="variant">
|
||||
<img src="/assets/packages/static/openvk/img/upload.png" style="margin-left:15px;height: 10px;">
|
||||
<a href="javascript:addAvatarImage(true, {$club->getId()})"><p>{_upload_new_picture}</p></a>
|
||||
</div>
|
||||
<a class="_add_image hoverable" id="add_image"><span>{_upload_new_picture}</span></a>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<a href="{$avatarLink|nocheck}">
|
||||
<img src="{$club->getAvatarUrl('normal')}" id="thisGroupAvatar" style="width: 100%; image-rendering: -webkit-optimize-contrast;" />
|
||||
<img src="{$club->getAvatarUrl('normal')}" id="bigAvatar" style="width: 100%; image-rendering: -webkit-optimize-contrast;" />
|
||||
</a>
|
||||
</div>
|
||||
<div n:ifset="$thisUser" id="profile_links">
|
||||
|
@ -292,7 +286,7 @@
|
|||
|
||||
<img
|
||||
src="{is_null($cover)?'/assets/packages/static/openvk/img/camera_200.png':$cover->getURL()}"
|
||||
style="max-width: 80px; max-height: 54pt;" />
|
||||
style="max-width: 80px; max-height: 54pt;" loading=lazy />
|
||||
</div>
|
||||
<div>
|
||||
<b><a href="/album{$album->getPrettyId()}">{$album->getName()}</a></b><br>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
<div class="crp-entry--image">
|
||||
<img src="{$recipient->getAvatarURL('miniscule')}"
|
||||
alt="Фотография пользователя" />
|
||||
alt="Фотография пользователя" loading=lazy />
|
||||
</div>
|
||||
<div class="crp-entry--info">
|
||||
<a href="{$recipient->getURL()}">{$recipient->getCanonicalName()}</a><br/>
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
</a>
|
||||
|
||||
<a href="/photo{$photo->getPrettyId()}?from=album{$album->getId()}">
|
||||
<img class="album-photo--image" src="{$photo->getURLBySizeId('tinier')}" alt="{$photo->getDescription()}" />
|
||||
<img class="album-photo--image" src="{$photo->getURLBySizeId('tinier')}" alt="{$photo->getDescription()}" loading=lazy />
|
||||
</a>
|
||||
</div>
|
||||
{/foreach}
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
{var $preview = is_null($cover) ? "/assets/packages/static/openvk/img/camera_200.png" : $cover->getURLBySizeId("normal")}
|
||||
|
||||
<a href="/album{$x->getPrettyId()}">
|
||||
<img src="{$preview}" alt="{$x->getName()}" style="height: 130px; width: 170px; object-fit: cover" />
|
||||
<img src="{$preview}" alt="{$x->getName()}" style="height: 130px; width: 170px; object-fit: cover" loading=lazy />
|
||||
</a>
|
||||
{/block}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
{/block}
|
||||
|
||||
{block preview}
|
||||
<img src="{$x->getAvatarUrl('miniscule')}" width="75" alt="Фотография пользователя" />
|
||||
<img src="{$x->getAvatarUrl('miniscule')}" width="75" alt="Фотография пользователя" loading=lazy />
|
||||
{/block}
|
||||
|
||||
{block name}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
<form n:if="$report->getContentType() != 'group'" action="/admin/reportAction{$report->getId()}" method="post">
|
||||
<input type="hidden" name="hash" value="{$csrfToken}"/>
|
||||
<input type="submit" name="ban" value="{_ban_user_action}" class="button">
|
||||
<input n:if="$report->getContentType() !== 'user'" type="submit" name="delete" value="{_delete}" class="button">
|
||||
<input n:if="$report->getContentType() !== 'user'" type="submit" name="delete" value="{_delete_content}" class="button">
|
||||
<input type="submit" name="ignore" value="{_ignore_report}" class="button">
|
||||
</form>
|
||||
<form n:if="$report->getContentType() == 'group'" action="/admin/reportAction{$report->getId()}" method="post">
|
||||
|
|
|
@ -1,378 +1,405 @@
|
|||
{extends "../@layout.xml"}
|
||||
|
||||
{block title}
|
||||
{tr("search_for_$type")}
|
||||
{if $_GET['query']}
|
||||
- {$_GET['query']}
|
||||
{tr("search_for_$section")}
|
||||
{if $_REQUEST['q']}
|
||||
- {$_REQUEST['q']}
|
||||
{/if}
|
||||
{/block}
|
||||
|
||||
{block header}
|
||||
{=OPENVK_ROOT_CONF["openvk"]["appearance"]["name"]} »
|
||||
{tr("search_for_$type")}
|
||||
{tr("search_for_$section")}
|
||||
{/block}
|
||||
|
||||
{* BEGIN ELEMENTS DESCRIPTION *}
|
||||
{block wrap}
|
||||
<div class="wrap2">
|
||||
<div class="wrap1">
|
||||
<div class="page_wrap">
|
||||
{if $section == 'audios' && $count > 1}
|
||||
{include "../Audio/bigplayer.xml", tidy => true}
|
||||
|
||||
{block link|strip|stripHtml}
|
||||
{if $type != "apps"}
|
||||
{$x->getURL()}
|
||||
{else}
|
||||
/app{$x->getId()}
|
||||
<input type="hidden" name="bigplayer_context" data-type="classic_search_context" data-entity='{"order":"{$order}","query":"{$query}","invert":{$invert ? 1 : 0},"only_performers":{$_REQUEST['only_performers'] ? 1 : 0},"genre":"{$_REQUEST['genre']}","with_lyrics":"{$_REQUEST['with_lyrics'] ? 1 : 0}"}' data-page="{$page}">
|
||||
{/if}
|
||||
{/block}
|
||||
|
||||
{block preview}
|
||||
<img src="{$x->getAvatarUrl('miniscule')}" width="75" alt="{_photo}" />
|
||||
{/block}
|
||||
|
||||
{block name}
|
||||
{if $type != "apps"}
|
||||
<text style="overflow: hidden;"> {$x->getCanonicalName()}
|
||||
{if $_GET['sort'] == "rating"}({$x->getRating()}%)
|
||||
{elseif $_GET['sort'] == "id"}(id{$x->getId()}){/if}</text>
|
||||
<img n:if="$x->isVerified()"
|
||||
class="name-checkmark"
|
||||
src="/assets/packages/static/openvk/img/checkmark.png"
|
||||
/>
|
||||
{else}
|
||||
{$x->getName()}
|
||||
{/if}
|
||||
{/block}
|
||||
|
||||
{block description}
|
||||
<table class="ugc-table">
|
||||
<tbody>
|
||||
{if $type === "users"}
|
||||
{if !is_null($_GET['status']) && $_GET['status'] != ""}
|
||||
<tr>
|
||||
<td><span class="nobold">{_status}:</span></td>
|
||||
<td>{$x->getStatus()}</td>
|
||||
</tr>
|
||||
{/if}
|
||||
{if !is_null($_GET['city']) && $_GET['city'] != "" && $x->getPrivacySetting("page.info.read") > 1}
|
||||
<tr>
|
||||
<td><span class="nobold">{_city}:</span></td>
|
||||
<td>{$x->getCity()}</td>
|
||||
</tr>
|
||||
{/if}
|
||||
{if !is_null($_GET['city']) && $_GET['hometown'] != "" && $x->getPrivacySetting("page.info.read") > 1}
|
||||
<tr>
|
||||
<td><span class="nobold">{_hometown}:</span></td>
|
||||
<td>{$x->getHometown()}</td>
|
||||
</tr>
|
||||
{/if}
|
||||
{if !is_null($_GET['politViews']) && $_GET['politViews'] != 0 && $x->getPrivacySetting("page.info.read") > 1}
|
||||
<tr>
|
||||
<td><span class="nobold">{_politViews}:</span></td>
|
||||
<td>{tr("politViews_".$x->getPoliticalViews())}</td>
|
||||
</tr>
|
||||
{/if}
|
||||
{if !is_null($_GET['email']) && $_GET['email'] != "" && $x->getPrivacySetting("page.info.read") > 1}
|
||||
<tr>
|
||||
<td><span class="nobold">{_email}:</span></td>
|
||||
<td>{$x->getContactEmail()}</td>
|
||||
</tr>
|
||||
{/if}
|
||||
{if !is_null($_GET['telegram']) && $_GET['telegram'] != "" && $x->getPrivacySetting("page.info.read") > 1}
|
||||
<tr>
|
||||
<td><span class="nobold">{_telegram}:</span></td>
|
||||
<td><a href="tg://resolve?domain={$x->getTelegram()}">@{$x->getTelegram()}</a></td>
|
||||
</tr>
|
||||
{/if}
|
||||
{if !is_null($_GET['site']) && $_GET['site'] != "" && $x->getPrivacySetting("page.info.read") > 1}
|
||||
<tr>
|
||||
<td><span class="nobold">{_personal_website}:</span></td>
|
||||
<td><a href="{$x->getWebsite()}">{$x->getWebsite()}</a></td>
|
||||
</tr>
|
||||
{/if}
|
||||
{if !is_null($_GET['address']) && $_GET['address'] != "" && $x->getPrivacySetting("page.info.read") > 1}
|
||||
<tr>
|
||||
<td><span class="nobold">{_address}:</span></td>
|
||||
<td>{$x->getPhysicalAddress()}</td>
|
||||
</tr>
|
||||
{/if}
|
||||
{if $x->getPrivacySetting("page.info.read") > 1}
|
||||
<tr>
|
||||
<td><span class="nobold">{_pronouns}: </span></td>
|
||||
<td>{$x->isFemale() ? tr("female") : ($x->isNeutral() ? tr("neutral") : tr("male"))}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="nobold">{_relationship}:</span></td>
|
||||
<td>{$x->getLocalizedMaritalStatus()}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="nobold">{_registration_date}: </span></td>
|
||||
<td>{$x->getRegistrationTime()}</td>
|
||||
</tr>
|
||||
{/if}
|
||||
{/if}
|
||||
<tr>
|
||||
{if !empty($x->getDescription())}
|
||||
{if $type != "apps"}
|
||||
<td>
|
||||
<span class="nobold">{_description}:</span>
|
||||
</td>
|
||||
{/if}
|
||||
<td {if $type == "apps"}style="width:400px"{/if}>
|
||||
{$x->getDescription() ?? '(' . tr("none") . ')'}
|
||||
</td>
|
||||
</tr>
|
||||
{/if}
|
||||
{if $type == "groups"}
|
||||
<td>
|
||||
<span class="nobold">{_size}:</span>
|
||||
</td>
|
||||
<td>
|
||||
{tr("participants", $x->getFollowersCount())}
|
||||
</td>
|
||||
{/if}
|
||||
</tbody>
|
||||
</table>
|
||||
{/block}
|
||||
|
||||
{block content}
|
||||
<style>
|
||||
.comment, .post-divider
|
||||
{
|
||||
border:none;
|
||||
}
|
||||
</style>
|
||||
<div style="margin-top:-7px">
|
||||
{var $data = is_array($iterator) ? $iterator : iterator_to_array($iterator)}
|
||||
|
||||
{include "../components/paginator.xml", conf => (object) [
|
||||
"page" => $page,
|
||||
"count" => $count,
|
||||
"amount" => sizeof($data),
|
||||
"perPage" => $perPage ?? OPENVK_DEFAULT_PER_PAGE,
|
||||
"atBottom" => false,
|
||||
]}
|
||||
<div class='summaryBar summaryBarFlex padding'>
|
||||
<div class='summary'>
|
||||
<b>{tr("results", $count)} {tr("showing_x_y", $page, $count)}</b>
|
||||
</div>
|
||||
<p style="margin-left: 15px; margin-top: 0;">
|
||||
<b>{tr("results", $count)}</b>
|
||||
</p>
|
||||
<div>
|
||||
{include searchOptions}
|
||||
|
||||
<div class="container_gray borderup" style="float:left;width:73.3%;">
|
||||
{if sizeof($data) > 0}
|
||||
{if $type == "users" || $type == "groups" || $type == "apps"}
|
||||
<div class="content" n:foreach="$data as $dat">
|
||||
{include "../components/paginator.xml", conf => $paginatorConf}
|
||||
</div>
|
||||
|
||||
<div class='page_wrap_content' id='search_page'>
|
||||
<div n:class='page_wrap_content_main, $section == "audios" && $count > 0 ? audios_padding'>
|
||||
{if $count > 0}
|
||||
{if $section === 'users'}
|
||||
<div class='search_content def_row_content' n:foreach="$data as $dat">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<a href="{include link, x => $dat}">
|
||||
{include preview, x => $dat}
|
||||
<a href="{$dat->getURL()}">
|
||||
<img src="{$dat->getAvatarUrl('miniscule')}" width="75" alt="{_photo}" loading='lazy' />
|
||||
</a>
|
||||
</td>
|
||||
<td valign="top" style="width: 100%">
|
||||
{ifset infotable}
|
||||
{include infotable, x => $dat}
|
||||
{else}
|
||||
<a href="{include link, x => $dat}">
|
||||
<a href="{$dat->getURL()}">
|
||||
<b>
|
||||
{include name, x => $dat}
|
||||
<text style="overflow: hidden;"> {$dat->getCanonicalName()}
|
||||
{if $order == "rating"}
|
||||
({$dat->getProfileCompletenessReport()->total}%)
|
||||
{/if}
|
||||
</text>
|
||||
<img n:if="$dat->isVerified()"
|
||||
class="name-checkmark"
|
||||
src="/assets/packages/static/openvk/img/checkmark.png"
|
||||
/>
|
||||
</b>
|
||||
{if $dat->getId() == $thisUser->getId()}
|
||||
({_s_it_is_you})
|
||||
{/if}
|
||||
</a>
|
||||
<br/>
|
||||
{include description, x => $dat}
|
||||
{/ifset}
|
||||
|
||||
<table class="ugc-table">
|
||||
<tbody>
|
||||
{if $_REQUEST["order"] == "id"}
|
||||
<tr>
|
||||
<td><span class="nobold">ID:</span></td>
|
||||
<td>{$dat->getId()}</td>
|
||||
</tr>
|
||||
{/if}
|
||||
{if $dat->getPrivacySetting("page.info.read") > 1}
|
||||
<tr>
|
||||
<td><span class="nobold">{_pronouns}: </span></td>
|
||||
<td>{$dat->isFemale() ? tr("female") : ($dat->isNeutral() ? tr("neutral") : tr("male"))}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="nobold">{_relationship}:</span></td>
|
||||
<td>{$dat->getLocalizedMaritalStatus()}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="nobold">{_registration_date}: </span></td>
|
||||
<td>{$dat->getRegistrationTime()}</td>
|
||||
</tr>
|
||||
{if !empty($dat->getDescription())}
|
||||
<tr>
|
||||
<td>
|
||||
<span class="nobold">{_description}:</span>
|
||||
</td>
|
||||
<td n:ifset="actions" valign="top" class="action_links" style="width: 150px;">
|
||||
{include actions, x => $dat}
|
||||
<td>
|
||||
{$dat->getDescription() ?? '(' . tr("none") . ')'}
|
||||
</td>
|
||||
</tr>
|
||||
{/if}
|
||||
{if !empty($_REQUEST["fav_mus"])}
|
||||
<tr>
|
||||
<td><span class="nobold">{_favorite_music}:</span></td>
|
||||
<td>{$dat->getFavoriteMusic()}</td>
|
||||
</tr>
|
||||
{/if}
|
||||
{if !empty($_REQUEST["fav_films"])}
|
||||
<tr>
|
||||
<td><span class="nobold">{_favorite_films}:</span></td>
|
||||
<td>{$dat->getFavoriteFilms()}</td>
|
||||
</tr>
|
||||
{/if}
|
||||
{if !empty($_REQUEST["fav_shows"])}
|
||||
<tr>
|
||||
<td><span class="nobold">{_favorite_shows}:</span></td>
|
||||
<td>{$dat->getFavoriteShows()}</td>
|
||||
</tr>
|
||||
{/if}
|
||||
{if !empty($_REQUEST["fav_books"])}
|
||||
<tr>
|
||||
<td><span class="nobold">{_favorite_books}:</span></td>
|
||||
<td>{$dat->getFavoriteBooks()}</td>
|
||||
</tr>
|
||||
{/if}
|
||||
{/if}
|
||||
</tbody>
|
||||
</table>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{elseif $type == "posts"}
|
||||
<div n:foreach="$data as $dat" class="content">
|
||||
{if !$dat || $dat->getTargetWall() < 0 && $dat->getWallOwner()->isHideFromGlobalFeedEnabled() || !$dat->canBeViewedBy($thisUser)}
|
||||
|
||||
<script n:if='$count > 0 && !empty($query)'>
|
||||
highlightText({$query}, '.page_wrap_content_main', ['text'])
|
||||
</script>
|
||||
{elseif $section === 'groups'}
|
||||
<div class='search_content def_row_content' n:foreach="$data as $dat">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<a href="{$dat->getURL()}">
|
||||
<img src="{$dat->getAvatarUrl('miniscule')}" width="75" alt="{_photo}" loading='lazy' />
|
||||
</a>
|
||||
</td>
|
||||
<td valign="top" style="width: 100%">
|
||||
<a href="{$dat->getURL()}">
|
||||
<b>
|
||||
<text style="overflow: hidden;"> {$dat->getCanonicalName()}
|
||||
{if $order == "id"}
|
||||
(id{$dat->getId()})
|
||||
{/if}
|
||||
</text>
|
||||
<img n:if="$dat->isVerified()"
|
||||
class="name-checkmark"
|
||||
src="/assets/packages/static/openvk/img/checkmark.png"
|
||||
/>
|
||||
</b>
|
||||
</a>
|
||||
|
||||
<table class="ugc-table">
|
||||
<tbody>
|
||||
{if !empty($dat->getDescription())}
|
||||
<tr>
|
||||
<td>
|
||||
<span class="nobold">{_description}:</span>
|
||||
</td>
|
||||
<td data-highlight='_clubDesc'>
|
||||
{$dat->getDescription() ?? '(' . tr("none") . ')'}
|
||||
</td>
|
||||
</tr>
|
||||
{/if}
|
||||
<td>
|
||||
<span class="nobold">{_size}:</span>
|
||||
</td>
|
||||
<td>
|
||||
{tr("participants", $dat->getFollowersCount())}
|
||||
</td>
|
||||
</tbody>
|
||||
</table>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<script n:if='$count > 0 && !empty($query)'>
|
||||
highlightText({$query}, '.page_wrap_content_main', ['text', "td[data-highlight='_clubDesc']"])
|
||||
</script>
|
||||
{elseif $section === 'apps'}
|
||||
<div class='search_content def_row_content' n:foreach="$data as $dat">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<a href="/app{$dat->getId()}">
|
||||
<img src="{$dat->getAvatarUrl('miniscule')}" width="75" alt="{_photo}" loading='lazy' />
|
||||
</a>
|
||||
</td>
|
||||
<td valign="top" style="width: 100%">
|
||||
<a href="/app{$dat->getId()}">
|
||||
<b>
|
||||
<text style="overflow: hidden;">
|
||||
{$dat->getName()}
|
||||
</text>
|
||||
</b>
|
||||
</a><br/>
|
||||
<span style='margin-left: 2px;' data-highlight='_appDesc'>
|
||||
{$dat->getDescription() ?? '(' . tr("none") . ')'}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<script n:if='$count > 0 && !empty($query)'>
|
||||
highlightText({$query}, '.page_wrap_content_main', ['text', "span[data-highlight='_appDesc']"])
|
||||
</script>
|
||||
{elseif $section === 'posts'}
|
||||
<div class='search_content' n:foreach="$data as $dat">
|
||||
{if !$dat || $dat->getWallOwner()->isHideFromGlobalFeedEnabled()}
|
||||
{_closed_group_post}.
|
||||
{else}
|
||||
{include "../components/post.xml", post => $dat, commentSection => true, onWallOf => true}
|
||||
{/if}
|
||||
</div>
|
||||
{elseif $type == "comments"}
|
||||
<div n:foreach="$data as $dat" class="content">
|
||||
{if !$dat->getTarget() || $dat->getTarget()->isDeleted()}
|
||||
{_deleted_target_comment}.
|
||||
{else}
|
||||
{include "../components/comment.xml", comment => $dat, linkW => true}
|
||||
{/if}
|
||||
</div>
|
||||
{elseif $type == "videos"}
|
||||
{foreach $data as $dat}
|
||||
<div class="content">
|
||||
|
||||
<script n:if='$count > 0 && !empty($query)'>
|
||||
highlightText({$query}, '.page_wrap_content_main', [".post:not(.comment) > tbody > tr > td > .post-content > .text .really_text"])
|
||||
</script>
|
||||
{elseif $section === 'videos'}
|
||||
<div class='search_content' n:foreach="$data as $dat">
|
||||
{include "../components/video.xml", video => $dat}
|
||||
</div>
|
||||
{/foreach}
|
||||
{elseif $type == "audios"}
|
||||
{foreach $data as $dat}
|
||||
|
||||
<script n:if='$count > 0 && !empty($query)'>
|
||||
highlightText({$query}, '.page_wrap_content_main', [".video_name", ".video_description"])
|
||||
</script>
|
||||
{elseif $section === 'audios'}
|
||||
<div class='search_content' n:foreach="$data as $dat">
|
||||
{include "../Audio/player.xml", audio => $dat}
|
||||
{/foreach}
|
||||
</div>
|
||||
|
||||
<script n:if="$count > 0 && !empty($query) && empty($_REQUEST['only_performers'])">
|
||||
highlightText({$query}, '.page_wrap_content_main', [".mediaInfo .performer a", ".mediaInfo .title"])
|
||||
</script>
|
||||
{elseif $section === 'audios_playlists'}
|
||||
<div class='search_content' n:foreach="$data as $dat">
|
||||
{include "../Audio/playlistListView.xml", playlist => $dat}
|
||||
</div>
|
||||
|
||||
<script n:if="$count > 0 && !empty($query) && empty($_REQUEST['only_performers'])">
|
||||
highlightText({$query}, '.page_wrap_content_main', [".playlistName", ".playlistDesc"])
|
||||
</script>
|
||||
{/if}
|
||||
{else}
|
||||
{ifset customErrorMessage}
|
||||
{include customErrorMessage}
|
||||
{else}
|
||||
{include "../components/nothing.xml"}
|
||||
{/ifset}
|
||||
{include "../components/content_error.xml", description => tr("no_results_by_this_query")}
|
||||
{/if}
|
||||
</div>
|
||||
<script>
|
||||
window.addEventListener("load", (event) => {
|
||||
document.getElementsByClassName("container_gray")[0].style.minHeight = document.getElementsByClassName("searchOptions")[0].clientHeight+"px";
|
||||
document.getElementsByClassName("searchOptions")[0].style.minHeight = document.getElementsByClassName("container_gray")[0].clientHeight-3+"px";
|
||||
})
|
||||
</script>
|
||||
<div class='page_wrap_content_options verticalGrayTabsWrapper'>
|
||||
<div class="page_wrap_content_options_list verticalGrayTabs with_padding">
|
||||
<a n:attr="id => $section === 'users' ? 'used'" href="/search?section=users&q={urlencode($query)}"> {_s_people}</a>
|
||||
<a n:attr="id => $section === 'groups' ? 'used'" href="/search?section=groups&q={urlencode($query)}"> {_s_groups}</a>
|
||||
<a n:attr="id => $section === 'posts' ? 'used'" href="/search?section=posts&q={urlencode($query)}"> {_s_posts}</a>
|
||||
<a n:attr="id => $section === 'videos' ? 'used'" href="/search?section=videos&q={urlencode($query)}"> {_s_videos}</a>
|
||||
<a n:attr="id => $section === 'apps' ? 'used'" href="/search?section=apps&q={urlencode($query)}"> {_s_apps}</a>
|
||||
<a n:attr="id => $section === 'audios' ? 'used'" href="/search?section=audios&q={urlencode($query)}"> {_s_audios}</a>
|
||||
<a n:attr="id => $section === 'audios_playlists' ? 'used'" href="/search?section=audios_playlists&q={urlencode($query)}">{_s_audios_playlists}</a>
|
||||
</div>
|
||||
|
||||
<div class='page_search_options'>
|
||||
{include searchOptions}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div n:if='$paginatorConf->pageCount > 1' class='page_content_paginator_bottom'>
|
||||
{include "../components/paginator.xml", conf => $extendedPaginatorConf}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
|
||||
{block searchOptions}
|
||||
<div class="searchOptions">
|
||||
<ul class="searchList">
|
||||
<a {if $type === "users"} id="used"{/if} href="/search?type=users{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id"> {_s_people} {if $type === "users"} ({$count}){/if}</a>
|
||||
<a {if $type === "groups"} id="used"{/if} href="/search?type=groups{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id"> {_s_groups} {if $type === "groups"} ({$count}){/if}</a>
|
||||
<a {if $type === "comments"}id="used"{/if} href="/search?type=comments{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id">{_s_comments} {if $type === "comments"}({$count}){/if}</a>
|
||||
<a {if $type === "posts"} id="used"{/if} href="/search?type=posts{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id"> {_s_posts} {if $type === "posts"} ({$count}){/if}</a>
|
||||
<a {if $type === "videos"} id="used"{/if} href="/search?type=videos{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id"> {_s_videos} {if $type === "videos"} ({$count}){/if}</a>
|
||||
<a {if $type === "apps"} id="used"{/if} href="/search?type=apps{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id"> {_s_apps} {if $type === "apps"} ({$count}){/if}</a>
|
||||
<a {if $type === "audios"} id="used"{/if} href="/search?type=audios{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id"> {_s_audios} {if $type === "audios"} ({$count}){/if}</a>
|
||||
</ul>
|
||||
<div class="search_option">
|
||||
<div class="search_option_name">
|
||||
<div class='search_option_name_ico'></div>
|
||||
{_s_order_by}
|
||||
</div>
|
||||
<div class="search_option_content">
|
||||
<select name="order" form="search_form" data-default='id'>
|
||||
{if $section == "users"}
|
||||
<option value="id" n:attr="selected => $order == 'id'">{_s_order_by_reg_date}</option>
|
||||
|
||||
<div class="searchOption">
|
||||
<div class="searchOptionName" id="n_sort" onclick="hideParams('sort')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_s_order_by}</div>
|
||||
<div class="searchOptionBlock" id="s_sort">
|
||||
<select name="sort" form="searcher" id="sortyor">
|
||||
<option value="id" {if $_GET["sort"] == "name"}selected{/if}>{_s_order_by_id}</option>
|
||||
{if $type == "users"}
|
||||
<option value="name" {if $_GET["sort"] == "name"}selected{/if}>{_s_order_by_name}</option>
|
||||
{if OPENVK_ROOT_CONF["openvk"]["preferences"]["commerce"]}
|
||||
<option value="rating" {if $_GET["sort"] == "rating"}selected{/if}>{_s_order_by_rating}</option>
|
||||
<option value="rating" n:attr="selected => $order == 'rating'">{_s_order_by_rating}</option>
|
||||
{/if}
|
||||
{elseif $section == "posts"}
|
||||
<option value="id" n:attr="selected => $order == 'id'">{_s_order_by_publishing_date}</option>
|
||||
{elseif $section == "audios"}
|
||||
<option value="id" n:attr="selected => $order == 'id'">{_s_order_by_upload_date}</option>
|
||||
{else}
|
||||
<option value="id" n:attr="selected => $order == 'id'">{_s_order_by_creation_date}</option>
|
||||
{/if}
|
||||
|
||||
{if $type == "audios"}
|
||||
<option value="length" n:attr="selected => $_GET['sort'] == 'length'">{_s_order_by_length}</option>
|
||||
<option value="listens" n:attr="selected => $_GET['sort'] == 'listens'">{_s_order_by_listens}</option>
|
||||
{if $section == "audios" || $section == "audios_playlists"}
|
||||
<option value="length" n:attr="selected => $order == 'length'">{_s_order_by_length}</option>
|
||||
<option value="listens" n:attr="selected => $order == 'listens'">{_s_order_by_listens}</option>
|
||||
{/if}
|
||||
</select>
|
||||
<div id="invertor">
|
||||
<input type="checkbox" name="invert" value="1" form="searcher" {if !is_null($_GET['invert']) && $_GET['invert'] == "1"}checked{/if}>{_s_order_invert}
|
||||
</div>
|
||||
|
||||
<label n:if="$order != 'rating'">
|
||||
<input type="checkbox" name="invert" value="1" form="search_form" n:attr="checked => $_REQUEST['invert'] == '1'">
|
||||
{_s_order_invert}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{if $type !== "groups" && $type !== "apps"} {* В OpenVK не сохраняется дата создания групп и приложений *}
|
||||
<div class="searchOption">
|
||||
<div class="searchOptionName" id="n_dates" onclick="hideParams('dates')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_s_by_date}</div>
|
||||
<div class="searchOptionBlock" id="s_dates">
|
||||
{if $type != "users"}
|
||||
<p id="bydate">{_s_date_before}:<br>
|
||||
{else}
|
||||
<p id="bydate">{_s_registered_before}:<br>
|
||||
{/if}
|
||||
<input type="date" name="datebefore"
|
||||
form="searcher"
|
||||
id="bydate"
|
||||
style="width:100%"
|
||||
value="{if !is_null($_GET['datebefore'])}{$_GET['datebefore']}{/if}"
|
||||
min="2019-11-19"
|
||||
max={date('Y-m-d')}></p>
|
||||
{if $type != "users"}
|
||||
<p id="bydate">{_s_date_after}:<br>
|
||||
{else}
|
||||
<p id="bydate">{_s_registered_after}:<br>
|
||||
{/if}
|
||||
<input type="date" name="dateafter"
|
||||
form="searcher"
|
||||
style="width:100%"
|
||||
id="bydate"
|
||||
value="{if !is_null($_GET['dateafter'])}{$_GET['dateafter']}{/if}"
|
||||
min="2019-11-18"
|
||||
max={date('Y-m-d')}></p>
|
||||
<div n:if="$section == 'users'" class="search_option">
|
||||
<div class="search_option_name">
|
||||
<div class='search_option_name_ico'></div>
|
||||
{_main}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="search_option_content">
|
||||
<input type="text" n:attr="value => $_REQUEST['city']" form="search_form" placeholder="{_city}" name="city">
|
||||
<input type="text" n:attr="value => $_REQUEST['hometown']" form="search_form" placeholder="{_hometown}" name="hometown">
|
||||
|
||||
{if $type === "users"}
|
||||
<div class="searchOption">
|
||||
<div class="searchOptionName" id="n_main" onclick="hideParams('main')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_main}</div>
|
||||
<div class="searchOptionBlock" id="s_main">
|
||||
<input type="text" value="{if !is_null($_GET['status'])}{$_GET['status']}{/if}" form="searcher" placeholder="{_status}" name="status">
|
||||
<input type="text" value="{if !is_null($_GET['city'])}{$_GET['city']}{/if}" form="searcher" placeholder="{_city}" name="city">
|
||||
<input type="text" value="{if !is_null($_GET['hometown'])}{$_GET['hometown']}{/if}" form="searcher" placeholder="{_hometown}" name="hometown">
|
||||
<input name="is_online" type="checkbox" {if !is_null($_GET['is_online']) && $_GET['is_online'] == "1"}checked{/if} form="searcher" value="1">{_s_now_on_site}
|
||||
<label>
|
||||
<input name="is_online" type="checkbox" n:attr="checked => $_REQUEST['is_online'] == '1'" form="search_form" value="1">
|
||||
{_s_now_on_site}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="searchOption">
|
||||
<div class="searchOptionName" id="n_gender" onclick="hideParams('gender')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_gender}</div>
|
||||
<div class="searchOptionBlock" id="s_gender">
|
||||
<p><input type="radio" form="searcher" id="gend" {if $_GET['gender'] == 0}checked{/if} name="gender" value="0">{_male}</p>
|
||||
<p><input type="radio" form="searcher" id="gend1"{if $_GET['gender'] == 1}checked{/if} name="gender" value="1">{_female}</p>
|
||||
<p><input type="radio" form="searcher" id="gend2"{if $_GET['gender'] == 2 || is_null($_GET['gender'])}checked{/if} name="gender" value="2">{_s_any}</p>
|
||||
<div n:if="$section == 'users'" class="search_option">
|
||||
<div class="search_option_name">
|
||||
<div class='search_option_name_ico'></div>
|
||||
{_pronouns}
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<div class="searchOption">
|
||||
<div class="searchOptionName" id="n_relationship" onclick="hideParams('relationship')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{ovk_proc_strtr(tr("relationship"), 14)}</div>
|
||||
<div class="searchOptionBlock" id="s_relationship">
|
||||
<select name="maritalstatus" form="searcher">
|
||||
<option n:foreach="range(0, 8) as $i" value="{$i}" {if $_GET['maritalstatus'] == $i}selected{/if} form="searcher">
|
||||
{tr("relationship_".$i)}
|
||||
</option>
|
||||
</select>
|
||||
<div class="search_option_content">
|
||||
<label><input type="radio" form="search_form" n:attr="checked => $_REQUEST['gender'] == 0" name="gender" value="0">{_male}</label>
|
||||
<label><input type="radio" form="search_form" n:attr="checked => $_REQUEST['gender'] == 1" name="gender" value="1">{_female}</label>
|
||||
<label><input type="radio" form="search_form" n:attr="checked => $_REQUEST['gender'] == 2" name="gender" value="2">{_neutral}</label>
|
||||
<label><input type="radio" form="search_form" n:attr="checked => is_null($_REQUEST['gender']) || $_REQUEST['gender'] == 3" name="gender" data-default='1' value="3">{_s_any}</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="searchOption">
|
||||
<div class="searchOptionName" id="n_politViews" onclick="hideParams('politViews')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_politViews}</div>
|
||||
<div class="searchOptionBlock" id="s_politViews">
|
||||
<select name="politViews" form="searcher">
|
||||
<option n:foreach="range(0, 9) as $i" value="{$i}" {if $_GET['politViews'] == $i}selected{/if} form="searcher">
|
||||
<div n:if="$section == 'users'" n:class="search_option, !isset($_REQUEST['polit_views']) && !isset($_REQUEST['marital_status']) ? search_option_hidden">
|
||||
<div class="search_option_name">
|
||||
<div class='search_option_name_ico'></div>
|
||||
{_s_additional}
|
||||
</div>
|
||||
<div class="search_option_content">
|
||||
<label>
|
||||
{_politViews}
|
||||
<select name="polit_views" form="search_form" data-default='0'>
|
||||
<option n:foreach="range(0, 9) as $i" value="{$i}" n:attr="selected => $_REQUEST['polit_views'] == $i">
|
||||
{tr("politViews_".$i)}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
{_relationship}
|
||||
<select name="marital_status" form="search_form" data-default='0'>
|
||||
<option n:foreach="range(0, 8) as $i" value="{$i}" n:attr="selected => $_REQUEST['marital_status'] == $i">
|
||||
{tr("relationship_".$i)}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div n:if="$section == 'videos'" class="search_option">
|
||||
<div class="search_option_name">
|
||||
<div class='search_option_name_ico'></div>
|
||||
{_s_main}
|
||||
</div>
|
||||
<div class="search_option_content">
|
||||
<label>
|
||||
<input type="checkbox" value='1' name="only_youtube" n:attr="checked => !empty($_REQUEST['only_youtube'])" form="search_form">{_s_only_youtube}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div n:if="$section == 'audios'" class="search_option">
|
||||
<div class="search_option_name">
|
||||
<div class='search_option_name_ico'></div>
|
||||
{_s_main}
|
||||
</div>
|
||||
<div class="search_option_content">
|
||||
<label>
|
||||
<input type="checkbox" name="only_performers" n:attr="checked => !empty($_REQUEST['only_performers'])" form="search_form">{_s_only_performers}
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" name="with_lyrics" n:attr="checked => !empty($_REQUEST['with_lyrics'])" form="search_form">{_s_with_lyrics}
|
||||
</label>
|
||||
<label>
|
||||
{_genre}
|
||||
<select name='genre' form="search_form" data-default='any'>
|
||||
<option n:attr="selected: empty($_REQUEST['genre'])" value="any">{_s_any_single}</option>
|
||||
<option n:foreach='\openvk\Web\Models\Entities\Audio::genres as $genre' n:attr="selected: $_REQUEST['genre'] == $genre" value="{$genre}">
|
||||
{$genre}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="searchOption">
|
||||
<div class="searchOptionName" id="n_contacts" onclick="hideParams('contacts')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_contacts}</div>
|
||||
<div class="searchOptionBlock" id="s_contacts">
|
||||
<input type="text" name="email" value="{if !is_null($_GET['email'])}{$_GET['email']}{/if}" form="searcher" placeholder="{_email}">
|
||||
<input type="text" name="telegram" value="{if !is_null($_GET['telegram'])}{$_GET['telegram']}{/if}" form="searcher" placeholder="{_telegram}"><br id="contacts">
|
||||
<input type="text" name="site" value="{if !is_null($_GET['site'])}{$_GET['site']}{/if}" form="searcher" placeholder="{_personal_website}"><br id="contacts">
|
||||
<input type="text" name="address" value="{if !is_null($_GET['address'])}{$_GET['address']}{/if}" form="searcher" placeholder="{_address}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="searchOption">
|
||||
<div class="searchOptionName" id="n_interests" onclick="hideParams('interests')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_interests}</div>
|
||||
<div class="searchOptionBlock" id="s_interests">
|
||||
<input type="text" value="{if !is_null($_GET['interests'])}{$_GET['interests']}{/if}" form="searcher" placeholder="{_interests}" name="interests">
|
||||
<input type="text" value="{if !is_null($_GET['fav_mus'])}{$_GET['fav_mus']}{/if}" form="searcher" placeholder="{_favorite_music}" name="fav_mus">
|
||||
<input type="text" value="{if !is_null($_GET['fav_films'])}{$_GET['fav_films']}{/if}" form="searcher" placeholder="{_favorite_films}" name="fav_films">
|
||||
<input type="text" value="{if !is_null($_GET['fav_shows'])}{$_GET['fav_shows']}{/if}" form="searcher" placeholder="{_favorite_shows}" name="fav_shows">
|
||||
<input type="text" value="{if !is_null($_GET['fav_books'])}{$_GET['fav_books']}{/if}" form="searcher" placeholder="{_favorite_books}" name="fav_books">
|
||||
<input type="text" value="{if !is_null($_GET['fav_quote'])}{$_GET['fav_quote']}{/if}" form="searcher" placeholder="{_favorite_quotes}" name="fav_quote">
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{if $type == "audios"}
|
||||
<div class="searchOption">
|
||||
<div class="searchOptionName" id="n_main_audio" onclick="hideParams('main_audio')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_s_main}</div>
|
||||
<div class="searchOptionBlock" id="s_main_audio">
|
||||
<label><input type="checkbox" name="only_performers" n:attr="checked => !empty($_GET['only_performers'])" form="searcher">{_s_only_performers}</label><br>
|
||||
<label><input type="checkbox" name="with_lyrics" n:attr="checked => !empty($_GET['with_lyrics'])" form="searcher">{_s_with_lyrics}</label>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<input class="button" type="button" id="dnt" value="{_reset}" onclick="resetSearch()">
|
||||
</div>
|
||||
|
||||
<input class="button" id="search_reset" type="button" value="{_reset}">
|
||||
{/block}
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
<input type="text" name="pseudo" value="{$user->getPseudo()}" />
|
||||
</td>
|
||||
</tr>
|
||||
{if OPENVK_ROOT_CONF['openvk']['credentials']['zadarma']['enable']}
|
||||
{if OPENVK_ROOT_CONF['openvk']['credentials']['smsc']['enable']}
|
||||
<tr>
|
||||
<td width="120" valign="top">
|
||||
<span class="nobold">{_phone}: </span>
|
||||
|
|
|
@ -4,11 +4,14 @@
|
|||
{var $act = $_GET["act"] ?? "friends"}
|
||||
|
||||
{if $act == "incoming"}
|
||||
{var $iterator = iterator_to_array($user->getFollowers($page))}
|
||||
{var $count = $user->getFollowersCount()}
|
||||
{var $iterator = iterator_to_array($user->getRequests($page))}
|
||||
{var $count = $user->getRequestsCount()}
|
||||
{elseif $act == "outcoming"}
|
||||
{var $iterator = iterator_to_array($user->getSubscriptions($page))}
|
||||
{var $count = $user->getSubscriptionsCount()}
|
||||
{elseif $act == "followers"}
|
||||
{var $iterator = iterator_to_array($user->getFollowers($page))}
|
||||
{var $count = $user->getFollowersCount()}
|
||||
{elseif $act == "online"}
|
||||
{var $iterator = iterator_to_array($user->getFriendsOnline($page))}
|
||||
{var $count = $user->getFriendsOnlineCount()}
|
||||
|
@ -22,6 +25,8 @@
|
|||
{_incoming_req}
|
||||
{elseif $act == "outcoming"}
|
||||
{_outcoming_req}
|
||||
{elseif $act == "followers"}
|
||||
{_followers}
|
||||
{elseif $act == "online"}
|
||||
{_friends_online}
|
||||
{else}
|
||||
|
@ -38,6 +43,8 @@
|
|||
{_incoming_req}
|
||||
{elseif $act == "outcoming"}
|
||||
{_outcoming_req}
|
||||
{elseif $act == "followers"}
|
||||
{_followers}
|
||||
{elseif $act == "online"}
|
||||
{_friends_online}
|
||||
{else}
|
||||
|
@ -53,18 +60,23 @@
|
|||
<div n:attr="id => ($act === 'online' ? 'activetabs' : 'ki')" class="tab">
|
||||
<a n:attr="id => ($act === 'online' ? 'act_tab_a' : 'ki')" href="?act=online">{_online}</a>
|
||||
</div>
|
||||
<div n:if="!is_null($thisUser) && $user->getId() === $thisUser->getId()" n:attr="id => ($act === 'incoming' || $act === 'outcoming' ? 'activetabs' : 'ki')" class="tab">
|
||||
<a n:attr="id => ($act === 'incoming' || $act === 'outcoming' ? 'act_tab_a' : 'ki')" href="?act=incoming">{_req}</a>
|
||||
<div n:if="!is_null($thisUser) && $user->getId() === $thisUser->getId()" n:attr="id => ($act === 'incoming' || $act === 'followers' || $act === 'outcoming' ? 'activetabs' : 'ki')" class="tab">
|
||||
<a n:attr="id => ($act === 'incoming' || $act === 'followers' || $act === 'outcoming' ? 'act_tab_a' : 'ki')" href="?act=incoming">{_req}</a>
|
||||
</div>
|
||||
{/block}
|
||||
|
||||
{block size}
|
||||
<div n:if="$act === 'incoming' || $act === 'outcoming'" class="mb_tabs">
|
||||
<div n:if="$act === 'incoming' || $act === 'followers' || $act === 'outcoming'" class="mb_tabs">
|
||||
<div n:attr="id => ($act === 'incoming' ? 'active' : 'ki')" class="mb_tab">
|
||||
<div>
|
||||
<a href="?act=incoming">{_incoming_req}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div n:attr="id => ($act === 'followers' ? 'active' : 'ki')" class="mb_tab">
|
||||
<div>
|
||||
<a href="?act=followers">{_followers}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div n:attr="id => ($act === 'outcoming' ? 'active' : 'ki')" class="mb_tab">
|
||||
<div>
|
||||
<a href="?act=outcoming">{_outcoming_req}</a>
|
||||
|
@ -78,6 +90,8 @@
|
|||
{tr("req", $count)}
|
||||
{elseif $act == "outcoming"}
|
||||
{tr("req", $count)}
|
||||
{elseif $act == "followers"}
|
||||
{tr("followers", $count)}
|
||||
{elseif $act == "online"}
|
||||
{tr("friends_list_online", $count)}
|
||||
{else}
|
||||
|
@ -97,7 +111,7 @@
|
|||
{/block}
|
||||
|
||||
{block preview}
|
||||
<img src="{$x->getAvatarUrl('miniscule')}" width="75" alt="Фотография пользователя" />
|
||||
<img src="{$x->getAvatarUrl('miniscule')}" width="75" alt="Фотография пользователя" loading=lazy />
|
||||
{/block}
|
||||
|
||||
{block name}
|
||||
|
@ -112,8 +126,8 @@
|
|||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="120" valign="top"><span class="nobold">{_gender}: </span></td>
|
||||
<td>{$x->isFemale() ? tr("female") : tr("male")}</td>
|
||||
<td width="120" valign="top"><span class="nobold">{_pronouns}: </span></td>
|
||||
<td>{$x->isFemale() ? tr("female") : ($x->isNeutral() ? tr("neutral") : tr("male"))}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="120" valign="top"><span class="nobold">{_relationship}:</span></td>
|
||||
|
@ -131,21 +145,29 @@
|
|||
{if ($x->getId() !== $thisUser->getId()) && ($thisUser->getId() === $user->getId())}
|
||||
{var $subStatus = $x->getSubscriptionStatus($thisUser)}
|
||||
{if $subStatus === 0}
|
||||
<form action="/setSub/user" method="post" class="profile_link_form">
|
||||
<form action="/setSub/user" method="post" class="profile_link_form" id="_submitUserSubscriptionAction">
|
||||
<input type="hidden" name="act" value="add" />
|
||||
<input type="hidden" name="id" value="{$x->getId()}" />
|
||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||
<input type="submit" class="profile_link" value="{_friends_add}" />
|
||||
</form>
|
||||
{elseif $subStatus === 1}
|
||||
<form action="/setSub/user" method="post" class="profile_link_form">
|
||||
<form action="/setSub/user" method="post" class="profile_link_form" id="_submitUserSubscriptionAction">
|
||||
<input type="hidden" name="act" value="add" />
|
||||
<input type="hidden" name="id" value="{$x->getId()}" />
|
||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||
<input type="submit" class="profile_link" value="{_friends_accept}" />
|
||||
</form>
|
||||
{if $act !== 'followers'}
|
||||
<form action="/setSub/user" method="post" class="profile_link_form" id="_submitUserSubscriptionAction">
|
||||
<input type="hidden" name="act" value="rej" />
|
||||
<input type="hidden" name="id" value="{$x->getId()}" />
|
||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||
<input type="submit" class="profile_link" value="{_friends_leave_in_flw}" />
|
||||
</form>
|
||||
{/if}
|
||||
{elseif $subStatus === 2}
|
||||
<form action="/setSub/user" method="post" class="profile_link_form">
|
||||
<form action="/setSub/user" method="post" class="profile_link_form" id="_submitUserSubscriptionAction">
|
||||
<input type="hidden" name="act" value="rem" />
|
||||
<input type="hidden" name="id" value="{$x->getId()}" />
|
||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||
|
@ -153,7 +175,7 @@
|
|||
</form>
|
||||
{elseif $subStatus === 3}
|
||||
<a href="/im?sel={$x->getId()}" class="profile_link">{_send_message}</a>
|
||||
<form action="/setSub/user" method="post" class="profile_link_form">
|
||||
<form action="/setSub/user" method="post" class="profile_link_form" id="_submitUserSubscriptionAction">
|
||||
<input type="hidden" name="act" value="rem" />
|
||||
<input type="hidden" name="id" value="{$x->getId()}" />
|
||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
{/block}
|
||||
|
||||
{block preview}
|
||||
<img src="{$x->getAvatarUrl('miniscule')}" width="75" alt="Фотография группы" />
|
||||
<img src="{$x->getAvatarUrl('miniscule')}" width="75" alt="Фотография группы" loading=lazy />
|
||||
{/block}
|
||||
|
||||
{block name}{/block}
|
||||
|
|
|
@ -69,27 +69,22 @@
|
|||
{else}
|
||||
|
||||
<div class="left_small_block">
|
||||
<div style="margin-left: auto;margin-right: auto;display: table;position:relative;" class="avatar_block" id="av">
|
||||
<div class="avatar_block">
|
||||
{var $hasAvatar = !str_contains($user->getAvatarUrl('miniscule'), "/assets/packages/static/openvk/img/camera_200.png")}
|
||||
{if !is_null($thisUser) && $hasAvatar == false && $user->getId() == $thisUser->getId()}
|
||||
<a href="javascript:addAvatarImage(false)" class="text_add_image">{_add_image}</a>
|
||||
{elseif !is_null($thisUser) && $user && $hasAvatar == true && $user->getId() == $thisUser->getId()}
|
||||
<div class="avatar_controls">
|
||||
<div class="avatarDelete">
|
||||
<a id="upl" href="javascript:deleteAvatar('{$user->getAvatarPhoto()->getPrettyId()}')"><img src="/assets/packages/static/openvk/img/delete.png"/></a>
|
||||
</div>
|
||||
|
||||
{if $thisUser && $user->getId() == $thisUser->getId()}
|
||||
<a {if $hasAvatar}style="display:none"{/if} class="add_image_text" id="add_image">{_add_image}</a>
|
||||
<div {if !$hasAvatar}style="display:none"{/if} class="avatar_controls">
|
||||
<div class="avatarDelete hoverable"></div>
|
||||
<div class="avatar_variants">
|
||||
<div class="variant">
|
||||
<img src="/assets/packages/static/openvk/img/upload.png" style="margin-left:15px;height: 10px;">
|
||||
<a href="javascript:addAvatarImage(false)"><p>{_upload_new_picture}</p></a>
|
||||
</div>
|
||||
<a class="_add_image hoverable" id="add_image"><span>{_upload_new_picture}</span></a>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<a href="{$user->getAvatarLink()|nocheck}">
|
||||
<img src="{$user->getAvatarUrl('normal')}"
|
||||
alt="{$user->getCanonicalName()}"
|
||||
id="thisUserAvatar"
|
||||
id="bigAvatar"
|
||||
style="width: 100%; image-rendering: -webkit-optimize-contrast;" />
|
||||
</a>
|
||||
</div>
|
||||
|
@ -307,7 +302,7 @@
|
|||
|
||||
<img
|
||||
src="{is_null($cover)?'/assets/packages/static/openvk/img/camera_200.png':$cover->getURLBySizeId('small')}"
|
||||
style="max-width: 80px; max-height: 54pt;" />
|
||||
style="max-width: 80px; max-height: 54pt;" loading=lazy />
|
||||
</div>
|
||||
<div style="overflow: hidden; overflow-wrap: break-word;">
|
||||
<b><a href="/album{$album->getPrettyId()}">{$album->getName()}</a></b><br>
|
||||
|
@ -475,11 +470,11 @@
|
|||
</tr>
|
||||
<tr n:if="!is_null($user->getHometown())">
|
||||
<td class="label"><span class="nobold">{_hometown}:</span></td>
|
||||
<td class="data"><a href="/search?type=users&query=&hometown={urlencode($user->getHometown())}">{$user->getHometown()}</a></td>
|
||||
<td class="data"><a href="/search?section=users&q=&hometown={urlencode($user->getHometown())}">{$user->getHometown()}</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="label"><span class="nobold">{_politViews}:</span></td>
|
||||
<td class="data"><a {if $user->getPoliticalViews() != 0}href="/search?type=users&query=&politViews={$user->getPoliticalViews()}"{/if}>{var $pviews = $user->getPoliticalViews()}{_"politViews_$pviews"}</a></td>
|
||||
<td class="data">{var $pviews = $user->getPoliticalViews()}{_"politViews_$pviews"}</td>
|
||||
</tr>
|
||||
<tr n:if="!is_null($user->getBirthday())">
|
||||
<td class="label"><span class="nobold">{_birth_date}:</span></td>
|
||||
|
@ -525,7 +520,7 @@
|
|||
</tr>
|
||||
<tr n:if="!is_null($user->getCity())">
|
||||
<td class="label"><span class="nobold">{_city}:</span></td>
|
||||
<td class="data"><a href="/search?type=users&query=&city={$user->getCity()}">{$user->getCity()}</a></td>
|
||||
<td class="data"><a href="/search?type=section&q=&city={$user->getCity()}">{$user->getCity()}</a></td>
|
||||
</tr>
|
||||
<tr n:if="!is_null($user->getPhysicalAddress())">
|
||||
<td class="label"><span class="nobold">{_address}:</span></td>
|
||||
|
@ -543,7 +538,7 @@
|
|||
{var $interests = explode(", ", $user->getInterests())}
|
||||
|
||||
{foreach $interests as $interest}
|
||||
<a href="/search?type=users&query=&interests={urlencode($interest)}">{$interest}</a>{if $interest != end($interests)},{/if}
|
||||
<span>{$interest}</span>{if $interest != end($interests)},{/if}
|
||||
{/foreach}
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -554,7 +549,7 @@
|
|||
{var $musics = explode(", ", $user->getFavoriteMusic())}
|
||||
|
||||
{foreach $musics as $music}
|
||||
<a href="/search?type=audios&query={urlencode($music)}">{$music}</a>{if $music != end($musics)},{/if}
|
||||
<a href="/search?section=audios&q={urlencode($music)}">{$music}</a>{if $music != end($musics)},{/if}
|
||||
{/foreach}
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -564,7 +559,7 @@
|
|||
{var $films = explode(", ", $user->getFavoriteFilms())}
|
||||
|
||||
{foreach $films as $film}
|
||||
<a href="/search?type=users&query=&fav_films={urlencode($film)}">{$film}</a>{if $film != end($films)},{/if}
|
||||
<a href="/search?section=users&q=&fav_films={urlencode($film)}">{$film}</a>{if $film != end($films)},{/if}
|
||||
{/foreach}
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -574,7 +569,7 @@
|
|||
{var $shows = explode(", ", $user->getFavoriteShows())}
|
||||
|
||||
{foreach $shows as $show}
|
||||
<a href="/search?type=users&query=&fav_shows={urlencode($show)}">{$show}</a>{if $show != end($shows)},{/if}
|
||||
<a href="/search?section=users&q=&fav_shows={urlencode($show)}">{$show}</a>{if $show != end($shows)},{/if}
|
||||
{/foreach}
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -584,7 +579,7 @@
|
|||
{var $books = explode(", ", $user->getFavoriteBooks())}
|
||||
|
||||
{foreach $books as $book}
|
||||
<a href="/search?type=users&query=&fav_books={urlencode($book)}">{$book}</a>{if $book != end($books)},{/if}
|
||||
<a href="/search?section=users&q=&fav_books={urlencode($book)}">{$book}</a>{if $book != end($books)},{/if}
|
||||
{/foreach}
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -659,7 +654,7 @@
|
|||
<img style="width: 70px; max-height: 70px;"
|
||||
src="{$giftDescriptor->gift->getImage(2)}"
|
||||
alt="{$hideInfo ? tr('gift') : ($giftDescriptor->caption ?? tr('gift'))}"
|
||||
title="{$hideInfo ? tr('gift') : ($giftDescriptor->caption ?? tr('gift'))}" />
|
||||
title="{$hideInfo ? tr('gift') : ($giftDescriptor->caption ?? tr('gift'))}" loading=lazy />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -769,8 +764,6 @@
|
|||
<script n:if="isset($thisUser) && $user->getId() == $thisUser->getId()" n:syntax="off">
|
||||
function setStatusEditorShown(shown) {
|
||||
document.getElementById("status_editor").style.display = shown ? "block" : "none";
|
||||
if(!document.status_popup_form.submit.style.width)
|
||||
document.status_popup_form.submit.style.width = document.status_popup_form.submit.offsetWidth + 4 + "px"
|
||||
}
|
||||
|
||||
document.addEventListener("click", event => {
|
||||
|
|
193
Web/Presenters/templates/VKAPI/OAuthLogin.xml
Normal file
193
Web/Presenters/templates/VKAPI/OAuthLogin.xml
Normal file
|
@ -0,0 +1,193 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Получение доступа | OpenVK</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: sans-serif;
|
||||
background-color: #ebedf0;
|
||||
}
|
||||
|
||||
header {
|
||||
background-color: #fff;
|
||||
box-shadow: 0 0 10px #d4d6d8;
|
||||
padding: 13px 0;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
header > div {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
max-width: 620px;
|
||||
margin: auto;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#ovkUser a:not(#pfpLink) {
|
||||
color: #000;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
#ovkUser img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 100%;
|
||||
vertical-align: middle;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
#ovkLogo a {
|
||||
display: flex;
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
background: #606060;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 21px;
|
||||
font-weight: 600;
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
body > div {
|
||||
width: 100%;
|
||||
max-width: 620px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
main {
|
||||
border: 1px solid #e1e3e6;
|
||||
background-color: #fff;
|
||||
padding: 16px;
|
||||
border-radius: 18px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
#authHeading, #authExplainer {
|
||||
color: #818c99;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
:is(#authHeading, #authExplainer) b {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
#authButtons {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#authButtons a {
|
||||
color: #818c99;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#authButtons a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#authButtons button {
|
||||
cursor: pointer;
|
||||
appearance: none;
|
||||
border: none;
|
||||
background-color: #606060;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
padding: 7px;
|
||||
border-radius: 7px;
|
||||
font-size: 15px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div>
|
||||
<div style="width: 85px;">
|
||||
</div>
|
||||
<div id="ovkLogo">
|
||||
<a href="/" target="_blank">O</a>
|
||||
</div>
|
||||
<div id="ovkUser">
|
||||
<a href="/logout?hash={rawurlencode($csrfToken)}">{_header_log_out}</a>
|
||||
<a id="pfpLink" href="/id0" target="_blank">
|
||||
<img src="{$thisUser->getAvatarUrl('miniscule')}" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div>
|
||||
<main>
|
||||
<div id="authHeading">
|
||||
{_app},
|
||||
<b>
|
||||
{if is_null($origin)}
|
||||
{tr("identifies_itself_as", $clientName)}{else}
|
||||
{tr("located_at_url", $origin)}{/if}</b>, {_wants_your_token}.
|
||||
</div>
|
||||
|
||||
<div id="authExplainer">
|
||||
<b>{_app_will_have_access_to}</b><br/>
|
||||
{_oauth_scope_all|noescape}.
|
||||
</div>
|
||||
|
||||
<div id="authButtons">
|
||||
<button id="authAllow">{_oauth_grant}</button>
|
||||
<a id="authDeny" href="javascript:void(0)">{_oauth_deny}</a>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
{script "js/node_modules/msgpack-lite/dist/msgpack.min.js"}
|
||||
{script "js/al_api.js"}
|
||||
<script>
|
||||
//<![CDATA[
|
||||
let clientName = {$clientName};
|
||||
let usePostMessage = {$usePostMessage} && window.opener != null;
|
||||
let acceptsStale = {$acceptsStale};
|
||||
let origin = {$origin};
|
||||
let redirectUri = {$redirectUri};
|
||||
|
||||
document.querySelector("#authDeny").addEventListener("click", () => {
|
||||
if (usePostMessage) {
|
||||
window.opener.postMessage({
|
||||
error: 'access_denied',
|
||||
error_reason: 'user_denied',
|
||||
error_description: 'User denied your request'
|
||||
}, origin);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
window.location.href = redirectUri + 'error=access_denied&error_reason=user_denied&error_description=User%20denied%20your%20request';
|
||||
});
|
||||
|
||||
document.querySelector("#authAllow").addEventListener("click", async () => {
|
||||
let response = await API.Apps.getRegularToken(clientName, acceptsStale);
|
||||
let ret = {
|
||||
access_token: response.token,
|
||||
expires_in: 0,
|
||||
user_id: {$thisUser->getId()},
|
||||
is_stale: response.is_stale
|
||||
};
|
||||
|
||||
if (usePostMessage) {
|
||||
window.opener.postMessage(ret, origin);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
window.location.href = redirectUri + (new URLSearchParams(ret)).toString();
|
||||
});
|
||||
//]]>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -33,7 +33,7 @@
|
|||
{/block}
|
||||
|
||||
{block preview}
|
||||
<div class="video-preview" id="videoOpen" data-id="{$x->getId()}">
|
||||
<div class="video-preview" data-id="{$x->getId()}">
|
||||
<img src="{$x->getThumbnailURL()}"
|
||||
alt="{$x->getName()}"
|
||||
style="max-width: 170px; max-height: 127px; margin: auto;" />
|
||||
|
@ -41,7 +41,7 @@
|
|||
{/block}
|
||||
|
||||
{block name}
|
||||
<span id="videoOpen" data-id="{$x->getId()}" style="color:unset;">{$x->getName()}</span>
|
||||
<span data-id="{$x->getId()}" style="color:unset;">{$x->getName()}</span>
|
||||
{/block}
|
||||
|
||||
{block description}
|
||||
|
@ -51,7 +51,7 @@
|
|||
<span style="color: grey;">{_video_uploaded} {$x->getPublicationTime()}</span><br/>
|
||||
<span style="color: grey;">{_video_updated} {$x->getEditTime() ?? $x->getPublicationTime()}</span>
|
||||
<p>
|
||||
<a href="/video{$x->getPrettyId()}" id="videoOpen" data-id="{$x->getId()}">{_view_video}</a>
|
||||
<a href="/video{$x->getPrettyId()}" data-id="{$x->getId()}">{_view_video}</a>
|
||||
{if $x->getCommentsCount() > 0}| <a href="/video{$x->getPrettyId()}#comments">{_comments} ({$x->getCommentsCount()})</a>{/if}
|
||||
</p>
|
||||
{/block}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
{css "css/bsdn.css"}
|
||||
{css "css/dialog.css"}
|
||||
{css "css/notifications.css"}
|
||||
{css "css/avataredit.css"}
|
||||
{css "css/avatar-edit.css"}
|
||||
{css "css/audios.css"}
|
||||
|
||||
{if $isXmas}
|
||||
|
@ -27,7 +27,7 @@
|
|||
{css "css/bsdn.css"}
|
||||
{css "css/dialog.css"}
|
||||
{css "css/notifications.css"}
|
||||
{css "css/avataredit.css"}
|
||||
{css "css/avatar-edit.css"}
|
||||
{css "css/audios.css"}
|
||||
|
||||
{if $isXmas}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
{if !$attachment->isDeleted()}
|
||||
{var $link = "/photo" . ($attachment->isAnonymous() ? ("s/" . base_convert((string) $attachment->getId(), 10, 32)) : $attachment->getPrettyId())}
|
||||
<a href="{$link}" onclick="OpenMiniature(event, {$attachment->getURLBySizeId('normal')}, {$parent->getPrettyId()}, {$attachment->getPrettyId()}, {$parentType})">
|
||||
<img class="media media_makima" src="{$attachment->getURLBySizeId('normal')}" alt="{$attachment->getDescription()}" />
|
||||
<img class="media media_makima" src="{$attachment->getURLBySizeId('normal')}" alt="{$attachment->getDescription()}" loading=lazy />
|
||||
</a>
|
||||
{else}
|
||||
<a href="javascript:alert('{_attach_no_longer_available}');">
|
||||
|
|
|
@ -36,21 +36,26 @@
|
|||
</div>
|
||||
</div>
|
||||
<div n:if="isset($thisUser) &&! ($compact ?? false)" class="post-menu">
|
||||
<a href="#_comment{$comment->getId()}" class="date">{$comment->getPublicationTime()}
|
||||
<a href="{if $correctLink}{$comment->getTargetURL()}{/if}#_comment{$comment->getId()}" class="date">{$comment->getPublicationTime()}
|
||||
<span n:if="$comment->getEditTime()" class="edited editedMark">({_edited_short})</span>
|
||||
</a>
|
||||
{if !$timeOnly}
|
||||
|
|
||||
{if $comment->canBeDeletedBy($thisUser)}
|
||||
<a href="/comment{$comment->getId()}/delete">{_delete}</a> |
|
||||
<a href="/comment{$comment->getId()}/delete">{_delete}</a>
|
||||
{/if}
|
||||
{if $comment->canBeEditedBy($thisUser)}
|
||||
<a id="editPost" data-id="{$comment->getId()}">{_edit}</a> |
|
||||
|
|
||||
<a id="editPost" data-id="{$comment->getId()}">{_edit}</a>
|
||||
{/if}
|
||||
{if !$no_reply_button}
|
||||
|
|
||||
<a class="comment-reply">{_reply}</a>
|
||||
{if $thisUser->getId() != $comment->getOwner()->getId()}
|
||||
{/if}
|
||||
{if $thisUser->getId() != $author->getRealId()}
|
||||
|
|
||||
{var $canReport = true}
|
||||
| <a href="javascript:reportComment()">{_report}</a>
|
||||
<a href="javascript:reportComment()">{_report}</a>
|
||||
{/if}
|
||||
<div style="float: right; font-size: .7rem;">
|
||||
<a class="post-like-button" href="/comment{$comment->getId()}/like?hash={rawurlencode($csrfToken)}">
|
||||
|
@ -59,29 +64,11 @@
|
|||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
{var $target = "wall"}
|
||||
|
||||
{if get_class($comment->getTarget()) == "openvk\Web\Models\Entities\Note"}
|
||||
{php $target = "note"}
|
||||
{elseif get_class($comment->getTarget()) == "openvk\Web\Models\Entities\Post"}
|
||||
{php $target = "wall"}
|
||||
{elseif get_class($comment->getTarget()) == "openvk\Web\Models\Entities\Photo"}
|
||||
{php $target = "photo"}
|
||||
{elseif get_class($comment->getTarget()) == "openvk\Web\Models\Entities\Video"}
|
||||
{php $target = "video"}
|
||||
{elseif get_class($comment->getTarget()) == "openvk\Web\Models\Entities\Topic"}
|
||||
{php $target = "topic"}
|
||||
{/if}
|
||||
|
||||
|
||||
<span n:if="$compact ?? false">
|
||||
|
||||
| <a
|
||||
{if is_null($linkW)}
|
||||
href="#_comment{$comment->getId()}"
|
||||
{else}
|
||||
href="{$target}{!is_null($comment->getTarget()) ? $comment->getTarget()->getPrettyId() : $comment->getOwner()->getId()}#_comment{$comment->getId()}"
|
||||
{/if}
|
||||
class="date"
|
||||
>{$comment->getPublicationTime()}</a>
|
||||
|
||||
|
|
6
Web/Presenters/templates/components/content_error.xml
Normal file
6
Web/Presenters/templates/components/content_error.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<div class='content_page_error'>
|
||||
<span>
|
||||
<b n:if="!empty($title)">{$title}<br><br></b>
|
||||
{$description}
|
||||
</span>
|
||||
</div>
|
|
@ -1,8 +1,8 @@
|
|||
{var $space = 3}
|
||||
{var $space = $conf->space ?? 3}
|
||||
{var $pageCount = ceil($conf->count / $conf->perPage)}
|
||||
|
||||
<div n:if="!($conf->page === 1 && $conf->count <= $conf->perPage)" style="padding: 8px;">
|
||||
<div n:class="paginator, ($conf->atBottom ?? false) ? paginator-at-bottom">
|
||||
<div n:if="!($conf->page === 1 && $conf->count <= $conf->perPage)" n:attr="style => (!$conf->tidy ? 'padding: 8px;')">
|
||||
<div n:class="paginator, ($conf->atBottom ?? false) ? paginator-at-bottom, ($conf->tidy ? 'tidy')">
|
||||
<a n:if="$conf->page > $space" n:attr="class => ($conf->page === 1 ? 'active')" href="?{http_build_query(array_merge($_GET, ['p' => 1]), 'k', '&', PHP_QUERY_RFC3986)}">«</a>
|
||||
{for $j = $conf->page - ($space-1); $j <= $conf->page + ($space-1); $j++}
|
||||
<a n:if="$j > 0 && $j <= $pageCount" n:attr="class => ($conf->page === $j ? 'active')" href="?{http_build_query(array_merge($_GET, ['p' => $j]), 'k', '&', PHP_QUERY_RFC3986)}">{$j}</a>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
<tr>
|
||||
<td width="54" valign="top">
|
||||
<a href="{$author->getURL()}">
|
||||
<img src="{$author->getAvatarURL('miniscule')}" class="post-avatar" width="50" />
|
||||
<img src="{$author->getAvatarURL('miniscule')}" class="post-avatar" width="50" loading=lazy />
|
||||
<span n:if="!$post->isPostedOnBehalfOfGroup() && !($compact ?? false) && $author->isOnline()" class="post-online">{_online}</span>
|
||||
</a>
|
||||
</td>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<tr>
|
||||
<td valign="top">
|
||||
<div class="video-preview">
|
||||
<a href="/video{$video->getPrettyId()}" id="videoOpen" data-id="{$video->getId()}">
|
||||
<a href="/video{$video->getPrettyId()}" {$videoModal ? "id='videoOpen'" : ''} data-id="{$video->getId()}">
|
||||
<img src="{$video->getThumbnailURL()}"
|
||||
style="max-width: 170px; max-height: 127px; margin: auto;" >
|
||||
</a>
|
||||
|
@ -15,18 +15,18 @@
|
|||
{include infotable, x => $dat}
|
||||
{else}
|
||||
<a href="/video{$video->getPrettyId()}">
|
||||
<b id="videoOpen" data-id="{$video->getId()}">
|
||||
<b class='video_name' {$videoModal ? "id='videoOpen'" : ''} data-id="{$video->getId()}">
|
||||
{$video->getName()}
|
||||
</b>
|
||||
</a>
|
||||
<br/>
|
||||
<p>
|
||||
<span>{$video->getDescription() ?? ""}</span>
|
||||
<span class='video_description'>{$video->getDescription() ?? ""}</span>
|
||||
</p>
|
||||
<span style="color: grey;">{_video_uploaded} {$video->getPublicationTime()}</span><br/>
|
||||
|
||||
<p>
|
||||
<a href="/video{$video->getPrettyId()}" id="videoOpen" data-id="{$video->getId()}">{_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}
|
||||
|
|
|
@ -62,7 +62,7 @@ class Themepacks implements \ArrayAccess
|
|||
return $offset === Themepacks::DEFAULT_THEME_ID ? false : isset($this->loadedThemepacks[$offset]);
|
||||
}
|
||||
|
||||
function offsetGet($offset)
|
||||
function offsetGet($offset) : mixed
|
||||
{
|
||||
return $this->loadedThemepacks[$offset];
|
||||
}
|
||||
|
|
|
@ -22,21 +22,21 @@ class DateTime
|
|||
$now = date_create();
|
||||
$diff = date_diff($now, $then);
|
||||
if($diff->invert === 0)
|
||||
return ovk_strftime_safe("%e %B %Y ", $this->timestamp) . tr("time_at_sp") . ovk_strftime_safe(" %R %p", $this->timestamp);
|
||||
return ovk_strftime_safe("%e %B %Y ", $this->timestamp) . tr("time_at_sp") . ovk_strftime_safe(" %R", $this->timestamp);
|
||||
|
||||
if($this->timestamp >= strtotime("midnight")) { # Today
|
||||
if($diff->h >= 1)
|
||||
return tr("time_today") . tr("time_at_sp") . ovk_strftime_safe(" %R %p", $this->timestamp);
|
||||
return tr("time_today") . tr("time_at_sp") . ovk_strftime_safe(" %R", $this->timestamp);
|
||||
else if($diff->i < 2)
|
||||
return tr("time_just_now");
|
||||
else
|
||||
return $diff->i === 5 ? tr("time_exactly_five_minutes_ago") : tr("time_minutes_ago", $diff->i);
|
||||
} else if($this->timestamp >= strtotime("-1day midnight")) { # Yesterday
|
||||
return tr("time_yesterday") . tr("time_at_sp") . ovk_strftime_safe(" %R %p", $this->timestamp);
|
||||
return tr("time_yesterday") . tr("time_at_sp") . ovk_strftime_safe(" %R", $this->timestamp);
|
||||
} else if(ovk_strftime_safe("%Y", $this->timestamp) === ovk_strftime_safe("%Y", time())) { # In this year
|
||||
return ovk_strftime_safe("%e %h ", $this->timestamp) . tr("time_at_sp") . ovk_strftime_safe(" %R %p", $this->timestamp);
|
||||
return ovk_strftime_safe("%e %h ", $this->timestamp) . tr("time_at_sp") . ovk_strftime_safe(" %R", $this->timestamp);
|
||||
} else {
|
||||
return ovk_strftime_safe("%e %B %Y ", $this->timestamp) . tr("time_at_sp") . ovk_strftime_safe(" %R %p", $this->timestamp);
|
||||
return ovk_strftime_safe("%e %B %Y ", $this->timestamp) . tr("time_at_sp") . ovk_strftime_safe(" %R", $this->timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -162,7 +162,7 @@ class Makima
|
|||
$result->tiles = [
|
||||
new ThumbTile(1, 3, $wCover, $maxHeight), new ThumbTile(1, 1, $w, $h0),
|
||||
new ThumbTile(1, 1, $w, $h1),
|
||||
new ThumbTile(1, 1, $w, $h1),
|
||||
new ThumbTile(1, 1, $w, $h2),
|
||||
];
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -183,6 +183,8 @@ routes:
|
|||
handler: "Photos->deletePhoto"
|
||||
- url: "/al_avatars"
|
||||
handler: "User->setAvatar"
|
||||
- url: "/delete_avatar"
|
||||
handler: "User->deleteAvatar"
|
||||
- url: "/videos{num}"
|
||||
handler: "Videos->list"
|
||||
- url: "/videos/upload"
|
||||
|
@ -231,6 +233,8 @@ routes:
|
|||
handler: "Group->edit"
|
||||
- url: "/club{num}/al_avatar"
|
||||
handler: "Group->setAvatar"
|
||||
- url: "/club{num}/delete_avatar"
|
||||
handler: "Group->deleteAvatar"
|
||||
- url: "/club{num}/backdrop"
|
||||
handler: "Group->editBackdrop"
|
||||
- url: "/club{num}/stats"
|
||||
|
@ -375,6 +379,8 @@ routes:
|
|||
handler: "VKAPI->route"
|
||||
- url: "/token"
|
||||
handler: "VKAPI->tokenLogin"
|
||||
- url: "/authorize"
|
||||
handler: "VKAPI->OAuthLogin"
|
||||
- url: "/admin/sandbox"
|
||||
handler: "About->sandbox"
|
||||
- url: "/admin/chandler/groups"
|
||||
|
|
|
@ -4,9 +4,8 @@
|
|||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.overflowedName {
|
||||
position: absolute;
|
||||
z-index: 99;
|
||||
.audiosPaddingContainer {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.musicIcon {
|
||||
|
@ -15,10 +14,6 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.musicIcon:hover {
|
||||
filter: brightness(99%);
|
||||
}
|
||||
|
||||
.musicIcon.pressed {
|
||||
filter: brightness(150%);
|
||||
}
|
||||
|
@ -31,7 +26,15 @@
|
|||
height: 46px;
|
||||
border-bottom: 1px solid #d8d8d8;
|
||||
box-shadow: 1px 0px 8px 0px rgba(34, 60, 80, 0.2);
|
||||
position: relative;
|
||||
position: sticky;
|
||||
top: 0px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.bigPlayer.tidy {
|
||||
width: 100%;
|
||||
margin-left: unset;
|
||||
margin-top: unset;
|
||||
}
|
||||
|
||||
.bigPlayer.floating {
|
||||
|
@ -171,11 +174,16 @@
|
|||
font-size: 10px;
|
||||
}
|
||||
|
||||
.bigPlayer .paddingLayer .trackInfo .timer .elapsedTime {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.bigPlayer .paddingLayer .trackInfo .trackName {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
width: 81%;
|
||||
height: 13px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
|
@ -183,11 +191,26 @@
|
|||
font-size: 10px;
|
||||
}
|
||||
|
||||
.bigPlayer .paddingLayer .trackInfo b:hover {
|
||||
.bigPlayer .paddingLayer .trackInfo a {
|
||||
font-weight: bold;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.bigPlayer .paddingLayer .trackInfo a:hover {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.bigPlayer .paddingLayer .trackPanel .track .selectableTrack > div {
|
||||
width: 95%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.bigPlayer .paddingLayer .volumePanel .selectableTrack > div {
|
||||
position: relative;
|
||||
width:72%
|
||||
}
|
||||
|
||||
.audioEmbed .track > .selectableTrack, .bigPlayer .selectableTrack {
|
||||
margin-top: 3px;
|
||||
width: calc(100% - 8px);
|
||||
|
@ -214,7 +237,7 @@
|
|||
|
||||
.audioEntry.nowPlaying {
|
||||
background: #606060;
|
||||
border: 1px solid #4f4f4f;
|
||||
outline: 1px solid #4f4f4f;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
@ -224,6 +247,7 @@
|
|||
|
||||
.audioEntry.nowPlaying:hover {
|
||||
background: #4e4e4e !important;
|
||||
border-radius: inherit !important;
|
||||
}
|
||||
|
||||
.audioEntry.nowPlaying .performer a {
|
||||
|
@ -246,8 +270,32 @@
|
|||
color: white !important;
|
||||
}
|
||||
|
||||
.audioEntry.nowPlaying .buttons .musicIcon, .audioEntry.nowPlaying .explicitMark {
|
||||
filter: brightness(187%) opacity(72%);
|
||||
.audioEntry.nowPlaying .explicitMark path {
|
||||
fill: #ffffff;
|
||||
}
|
||||
|
||||
.audioEntry.nowPlaying .buttons .musicIcon.edit-icon {
|
||||
background-position: -152px -51px;
|
||||
}
|
||||
|
||||
.audioEntry.nowPlaying .buttons .musicIcon.download-icon {
|
||||
background-position: -151px -67px;
|
||||
}
|
||||
|
||||
.audioEntry.nowPlaying .buttons .musicIcon.add-icon {
|
||||
background-position: -94px -52px;
|
||||
}
|
||||
|
||||
.audioEntry.nowPlaying .buttons .musicIcon.report-icon {
|
||||
background-position: -66px -67px;
|
||||
}
|
||||
|
||||
.audioEntry.nowPlaying .buttons .musicIcon.remove-icon-group {
|
||||
background-position: -122px -67px;
|
||||
}
|
||||
|
||||
.audioEntry.nowPlaying .buttons .musicIcon.remove-icon {
|
||||
background-position: -108px -67px;
|
||||
}
|
||||
|
||||
.audioEntry {
|
||||
|
@ -264,12 +312,16 @@
|
|||
}
|
||||
|
||||
.audioEntry .subTracks {
|
||||
display: flex;
|
||||
display: none;
|
||||
padding-bottom: 5px;
|
||||
padding-left: 8px;
|
||||
padding-right: 12px;
|
||||
}
|
||||
|
||||
.audioEntry .subTracks.shown {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.audioEntry .playerButton .playIcon {
|
||||
background-image: url('/assets/packages/static/openvk/img/play_buttons.gif');
|
||||
cursor: pointer;
|
||||
|
@ -290,16 +342,45 @@
|
|||
height: 23px;
|
||||
}
|
||||
|
||||
.audioEntry .status .mediaInfo {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.overflowedName {
|
||||
position: absolute;
|
||||
z-index: 99;
|
||||
width: 80% !important;
|
||||
}
|
||||
|
||||
.audioEntry .status strong {
|
||||
color: #4C4C4C;
|
||||
}
|
||||
|
||||
.audioEmbed .track {
|
||||
display: none;
|
||||
padding: 4px 0;
|
||||
padding: 0px 0;
|
||||
}
|
||||
|
||||
.audioEmbed .track, .audioEmbed.playing .track {
|
||||
.audioEmbed .track .selectableTrack {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.audioEmbed .track .selectableTrack .selectableTrackSlider {
|
||||
position: relative;
|
||||
width: calc(100% - 18px);
|
||||
}
|
||||
|
||||
.audioEmbed .subTracks .lengthTrackWrapper {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.audioEmbed .subTracks .volumeTrackWrapper {
|
||||
width: 81px;
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
.audioEmbed.playing .track {
|
||||
display: unset;
|
||||
}
|
||||
|
||||
|
@ -309,7 +390,7 @@
|
|||
}
|
||||
|
||||
.audioEntry:hover .buttons {
|
||||
display: block;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.audioEntry:hover .volume .hideOnHover {
|
||||
|
@ -318,11 +399,16 @@
|
|||
|
||||
.audioEntry .buttons {
|
||||
display: none;
|
||||
flex-direction: row-reverse;
|
||||
gap: 5px;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
width: 62px;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
right: 3%;
|
||||
top: 2px;
|
||||
margin-top: 7px;
|
||||
/* чтоб избежать заедания во время ховера кнопки добавления */
|
||||
clip-path: inset(0 0 0 0);
|
||||
}
|
||||
|
@ -331,18 +417,21 @@
|
|||
width: 11px;
|
||||
height: 11px;
|
||||
float: right;
|
||||
margin-right: 4px;
|
||||
margin-top: 3px;
|
||||
background-position: -137px -51px;
|
||||
}
|
||||
|
||||
.audioEntry .buttons .download-icon {
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
float: right;
|
||||
background-position: -136px -67px;
|
||||
}
|
||||
|
||||
.audioEntry .buttons .add-icon {
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
float: right;
|
||||
background-position: -80px -52px;
|
||||
margin-top: 3px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.audioEntry .buttons .add-icon-group {
|
||||
|
@ -350,7 +439,6 @@
|
|||
height: 11px;
|
||||
float: right;
|
||||
background-position: -94px -52px;
|
||||
margin-top: 3px;
|
||||
transition: margin-right 0.1s ease-out, opacity 0.1s ease-out;
|
||||
}
|
||||
|
||||
|
@ -358,9 +446,7 @@
|
|||
width: 12px;
|
||||
height: 11px;
|
||||
float: right;
|
||||
background-position: -67px -51px;
|
||||
margin-top: 3px;
|
||||
margin-right: 3px;
|
||||
background-position: -50px -67px;
|
||||
}
|
||||
|
||||
.add-icon-noaction {
|
||||
|
@ -374,22 +460,17 @@
|
|||
}
|
||||
|
||||
.audioEntry .buttons .remove-icon {
|
||||
margin-top: 3px;
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
margin-left: 2px;
|
||||
float: right;
|
||||
background-position: -108px -52px;
|
||||
}
|
||||
|
||||
.audioEntry .buttons .remove-icon-group {
|
||||
margin-top: 3px;
|
||||
width: 13px;
|
||||
height: 11px;
|
||||
float: right;
|
||||
background-position: -122px -52px;
|
||||
margin-left: 3px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.audioEmbed .lyrics {
|
||||
|
@ -410,12 +491,12 @@
|
|||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.audioEmbed.withdrawn .status > *, .audioEmbed.processed .status > *, .audioEmbed.withdrawn .playerButton > *, .audioEmbed.processed .playerButton > * {
|
||||
.audioEmbed.withdrawn .status > *, .audioEmbed.processed .playerButton > *, .audioEmbed.withdrawn .playerButton > * {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.audioEmbed.withdrawn {
|
||||
filter: opacity(0.8);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.playlistCover img {
|
||||
|
@ -427,25 +508,55 @@
|
|||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.playlistContainer {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 146px);
|
||||
gap: 18px 10px;
|
||||
.playlistBlock .playlistWrapper {
|
||||
float: left;
|
||||
padding-left: 13px;
|
||||
width:75%
|
||||
}
|
||||
|
||||
.playlistContainer .playlistCover {
|
||||
width: 111px;
|
||||
height: 111px;
|
||||
.playlistCover .profile_links .profile_link {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* playlist listview */
|
||||
|
||||
.playlistListView {
|
||||
display: flex;
|
||||
background: #c4c4c4;
|
||||
padding: 7px;
|
||||
gap: 9px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.playlistContainer .playlistCover img {
|
||||
max-width: 111px;
|
||||
max-height: 111px;
|
||||
margin: auto;
|
||||
.playlistListView:hover, .playlistListView .playlistCover {
|
||||
background: #ebebeb;
|
||||
}
|
||||
|
||||
.playlistListView .playlistCover img {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.playlistListView .playlistInfo, .playlistListView .playlistInfo .playlistInfoTopPart {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.playlistListView .playlistInfo {
|
||||
gap: 2px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.playlistListView .playlistInfo .playlistName {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.playlistListView .playlistInfo .playlistMeta, .playlistListView .playlistInfo .playlistMeta span {
|
||||
color: #676767;
|
||||
}
|
||||
|
||||
/* other */
|
||||
|
||||
.ovk-diag-body .searchBox {
|
||||
background: #e6e6e6;
|
||||
padding-top: 10px;
|
||||
|
@ -490,17 +601,16 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.playlistCover img {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.explicitMark {
|
||||
margin-top: 2px;
|
||||
margin-left: 3px;
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
background: url('/assets/packages/static/openvk/img/explicit.svg');
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.explicitMark path {
|
||||
fill: #828a99;
|
||||
fill-opacity: .7;
|
||||
}
|
||||
|
||||
.audioStatus span {
|
||||
|
@ -517,8 +627,14 @@
|
|||
padding-bottom: 3px;
|
||||
}
|
||||
|
||||
.audiosDiv {
|
||||
width: 103.1%;
|
||||
display: flex;
|
||||
margin: 0px 0px -10px -12px;
|
||||
}
|
||||
|
||||
/* <center> 🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣*/
|
||||
.audiosDiv center span {
|
||||
.audiosDiv center span, .error_full_wrapper center span {
|
||||
color: #707070;
|
||||
margin: 120px 0px !important;
|
||||
display: block;
|
||||
|
@ -528,15 +644,6 @@
|
|||
margin-left: -10px;
|
||||
}
|
||||
|
||||
.playlistInfo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.playlistInfo .playlistName {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.searchList.floating {
|
||||
position: fixed;
|
||||
z-index: 199;
|
||||
|
@ -583,10 +690,13 @@
|
|||
}
|
||||
|
||||
.friendsAudiosList {
|
||||
margin-left: -7px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.friendsAudiosList > a {
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.friendsAudiosList .elem {
|
||||
display: flex;
|
||||
padding: 1px 1px;
|
||||
|
@ -659,3 +769,27 @@
|
|||
.addToPlaylist {
|
||||
width: 22%;
|
||||
}
|
||||
|
||||
#_addAudioAdditional {
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
#_addAudioAdditional #_tabs {
|
||||
margin: 0px -6px;
|
||||
}
|
||||
|
||||
#_addAudioAdditional #_tabs .mb_tabs {
|
||||
background-color: unset;
|
||||
border-bottom: unset;
|
||||
padding: 0px 5px;
|
||||
}
|
||||
|
||||
#_addAudioAdditional #_tip {
|
||||
margin: 5px 0px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#_addAudioAdditional #_content {
|
||||
margin-top: 6px;
|
||||
padding: 1px;
|
||||
}
|
||||
|
|
182
Web/static/css/avatar-edit.css
Normal file
182
Web/static/css/avatar-edit.css
Normal file
|
@ -0,0 +1,182 @@
|
|||
.avatar_block {
|
||||
position: relative;
|
||||
clip-path: inset(0 0 0.7% 0);
|
||||
}
|
||||
|
||||
.avatar_block .add_image_text {
|
||||
position: absolute;
|
||||
font-size: 12px;
|
||||
color: #2B587A;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
left: 0px;
|
||||
bottom: 30px;
|
||||
}
|
||||
|
||||
.avatar_block .add_image_text:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#temp_uploadPic {
|
||||
width: 40%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.hoverable {
|
||||
transition: all 200ms ease-in-out;
|
||||
opacity: 0.6;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.hoverable:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.avatar_block *, .avatar_block .avatarDelete::before {
|
||||
-webkit-transition: all 200ms ease-in-out;
|
||||
-moz-transition: all 200ms ease-in-out;
|
||||
-o-transition: all 200ms ease-in-out;
|
||||
transition: all 200ms ease-in-out;
|
||||
}
|
||||
|
||||
._add_image::before {
|
||||
margin-top: 2px;
|
||||
content: ' ';
|
||||
background: url('/assets/packages/static/openvk/img/upload.png');
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
display: inline-block;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.avatarDelete {
|
||||
position: absolute;
|
||||
right: 0%;
|
||||
background-color: rgba(0, 0, 0, 0.75);
|
||||
padding: 1px 0px 4px 3px;
|
||||
border-radius: 0px 0px 0px 5px;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
width: 15px;
|
||||
height: 13px;
|
||||
}
|
||||
|
||||
.avatarDelete::before {
|
||||
content: ' ';
|
||||
background: url('/assets/packages/static/openvk/img/upload.png');
|
||||
background-position: -10px 2px;
|
||||
background-repeat: no-repeat;
|
||||
width: 12px;
|
||||
height: 14px;
|
||||
display: inline-block;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
div.avatar_block:hover .avatarDelete {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
div.avatar_block:hover .avatar_variants {
|
||||
opacity: 1 !important;
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
|
||||
.avatar_controls .avatar_variants {
|
||||
opacity:0;
|
||||
position:absolute;
|
||||
background-color: rgba(0, 0, 0, 0.75);
|
||||
width:100%;
|
||||
bottom:0;
|
||||
margin-bottom:-8px;
|
||||
color:white;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.avatar_controls .avatar_variants a {
|
||||
opacity: 60%;
|
||||
display: flex;
|
||||
user-select: none;
|
||||
padding: 5px 0px;
|
||||
}
|
||||
|
||||
.avatar_controls .avatar_variants span {
|
||||
color: white;
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
.avatar_controls .avatar_variants a:hover, .avatarDelete:hover::before {
|
||||
opacity: 100%;
|
||||
}
|
||||
|
||||
.cropper-container.moving .cropper-point {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.cropper-modal {
|
||||
opacity: 0.7;
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.cropper-point {
|
||||
transition: opacity 200ms ease-in-out;
|
||||
background-color: #fff !important;
|
||||
height: 7px !important;
|
||||
width: 9px !important;
|
||||
opacity: 0.6;
|
||||
box-shadow: black 0px 0px 2px;
|
||||
}
|
||||
|
||||
.cropper-line {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.cropper-container {
|
||||
width: 421px;
|
||||
height: 279px;
|
||||
}
|
||||
|
||||
.cropper-view-box {
|
||||
outline: none;
|
||||
outline-color: unset;
|
||||
}
|
||||
|
||||
.cropper-image-cont {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.cropper-image-cont img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.cropper-image-cont .rotateButtons {
|
||||
height: 20px;
|
||||
margin-top: -31px;
|
||||
margin-right: 5px;
|
||||
width: 45px;
|
||||
float: right;
|
||||
position: relative;
|
||||
display: flex;
|
||||
padding: 3px 5px 3px 2px;
|
||||
background: rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
.cropper-image-cont .rotateButtons div {
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.cropper-image-cont .rotateButtons ._rotateLeft {
|
||||
background: url(/assets/packages/static/openvk/img/upload.png);
|
||||
height: 20px;
|
||||
width: 23px;
|
||||
background-position: -23px 0px;
|
||||
}
|
||||
|
||||
.cropper-image-cont .rotateButtons ._rotateRight {
|
||||
background: url(/assets/packages/static/openvk/img/upload.png);
|
||||
height: 18px;
|
||||
width: 22px;
|
||||
background-position: -46px 0px;
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
.text_add_image
|
||||
{
|
||||
position:absolute;
|
||||
font-size:12px;
|
||||
color: #2B587A;
|
||||
text-align:center;
|
||||
width: 100%;
|
||||
left: 0px;
|
||||
bottom:30px;
|
||||
}
|
||||
.text_add_image:hover
|
||||
{
|
||||
color:rgb(48, 41, 141);
|
||||
}
|
||||
.text_add_image, .avatarDelete img, .avatarDelete, .avatar_variants, .variant {
|
||||
-webkit-transition: all 200ms ease-in-out;
|
||||
-moz-transition: all 200ms ease-in-out;
|
||||
-o-transition: all 200ms ease-in-out;
|
||||
transition: all 200ms ease-in-out;
|
||||
}
|
||||
.avatarDelete
|
||||
{
|
||||
position:absolute;
|
||||
right:0%;
|
||||
background-color: rgba(0, 0, 0, 0.75);
|
||||
padding: 1px 0px 4px 3px;
|
||||
border-radius: 0px 0px 0px 5px;
|
||||
opacity:0;
|
||||
cursor:pointer;
|
||||
}
|
||||
.avatarDelete img
|
||||
{
|
||||
width:77%;
|
||||
opacity:60%;
|
||||
vertical-align:middle;
|
||||
}
|
||||
.avatarDelete img:hover
|
||||
{
|
||||
opacity:100%
|
||||
}
|
||||
|
||||
div.avatar_block:hover .avatarDelete
|
||||
{
|
||||
opacity:1 !important;
|
||||
}
|
||||
|
||||
div.avatar_block:hover .avatar_variants
|
||||
{
|
||||
opacity:1 !important;
|
||||
margin-bottom:1px;
|
||||
}
|
||||
|
||||
.avatar_variants
|
||||
{
|
||||
opacity:0;
|
||||
position:absolute;
|
||||
background-color: rgba(0, 0, 0, 0.75);
|
||||
width:100%;
|
||||
bottom:0;
|
||||
margin-bottom:-8px;
|
||||
color:white;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.variant
|
||||
{
|
||||
opacity:60%;
|
||||
display:flex;
|
||||
user-select:none;
|
||||
}
|
||||
|
||||
.variant p
|
||||
{
|
||||
color:white;
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
.variant img
|
||||
{
|
||||
color:white;
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
.variant:hover
|
||||
{
|
||||
opacity:100%;
|
||||
}
|
|
@ -97,16 +97,15 @@ h1 {
|
|||
display: inline-block;
|
||||
height: 29px;
|
||||
padding: 11px 4px 0 7px;
|
||||
}
|
||||
|
||||
.header_navigation .link, .header_navigation .header_divider_stick {
|
||||
background: url('../img/divider.png') no-repeat;
|
||||
background-size: 1.5px 41px;
|
||||
}
|
||||
|
||||
.header_navigation .nodivider {
|
||||
display: inline-block;
|
||||
height: 29px;
|
||||
padding: 11px 4px 0 7px;
|
||||
background: none;
|
||||
background-size: 1.5px 41px;
|
||||
.page_header.search_expanded .header_navigation .header_divider_stick {
|
||||
background: unset;
|
||||
}
|
||||
|
||||
.header_navigation .link a {
|
||||
|
@ -427,6 +426,22 @@ h1 {
|
|||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
.action_links.disable>a,
|
||||
.action_links.disable>form>input,
|
||||
.action_links.disable {
|
||||
cursor: not-allowed;
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.action_links.loading::after {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
background-image: url('/assets/packages/static/openvk/img/loading_mini.gif');
|
||||
width: 30px;
|
||||
height: 7px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.profile_link.disable>a,
|
||||
.profile_link.disable {
|
||||
cursor: not-allowed;
|
||||
|
@ -587,6 +602,11 @@ input[type=radio]:hover {
|
|||
background-position: 0 -28px;
|
||||
}
|
||||
|
||||
input[type=checkbox]:disabled {
|
||||
background-position: 0 -28px;
|
||||
cursor: initial;
|
||||
}
|
||||
|
||||
input[type=checkbox]:checked,
|
||||
input[type=radio]:checked {
|
||||
background-position: 0 -14px;
|
||||
|
@ -597,6 +617,10 @@ input[type=radio]:checked:hover {
|
|||
background-position: 0 -42px;
|
||||
}
|
||||
|
||||
input[type=checkbox]:checked:disabled {
|
||||
background-position: 0 -42px;
|
||||
}
|
||||
|
||||
#auth {
|
||||
padding: 10px;
|
||||
}
|
||||
|
@ -1827,6 +1851,10 @@ body.scrolled .toTop:hover {
|
|||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.paginator.tidy {
|
||||
float: unset;
|
||||
}
|
||||
|
||||
.paginator-at-bottom {
|
||||
margin-top: -6px;
|
||||
}
|
||||
|
@ -1970,6 +1998,18 @@ body.scrolled .toTop:hover {
|
|||
line-height: normal;
|
||||
}
|
||||
|
||||
.summaryBar.summaryBarFlex {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.summaryBar.padding {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 8px;
|
||||
height: 23px;
|
||||
}
|
||||
|
||||
.summaryBar .summary {
|
||||
color: #45688E;
|
||||
font-weight: bold;
|
||||
|
@ -2059,18 +2099,16 @@ table td[width="120"] {
|
|||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
display: inline-block;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.mb_tab div {
|
||||
padding: 3px 7px;
|
||||
.mb_tab div, .mb_tab > a {
|
||||
padding: 5px 9px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.mb_tab#active {
|
||||
background-color: #898989;
|
||||
}
|
||||
|
||||
.mb_tab#active div {
|
||||
border: 2px solid #5f5f5f;
|
||||
background-color: #606060;
|
||||
}
|
||||
|
||||
.mb_tab#active a {
|
||||
|
@ -2476,159 +2514,332 @@ a.poll-retract-vote {
|
|||
display: none;
|
||||
}
|
||||
|
||||
.searchOptions {
|
||||
overflow: hidden;
|
||||
width:25.5%;
|
||||
border-top:1px solid #E5E7E6;
|
||||
float:right;
|
||||
scrollbar-width: none;
|
||||
font-size:12px;
|
||||
background-color:#f7f7f7;
|
||||
margin-right: -7px;
|
||||
/* Da search */
|
||||
|
||||
/* Header part */
|
||||
|
||||
.header_navigation #search_box {
|
||||
display: inline-block;
|
||||
height: 29px;
|
||||
padding: 11px 4px 0 7px;
|
||||
}
|
||||
|
||||
.searchBtn {
|
||||
.header_navigation #search_box input[type='search'] {
|
||||
height: 20px;
|
||||
background: url('/assets/packages/static/openvk/img/search_icon.png') no-repeat 3px 4px;
|
||||
background-color: #fff;
|
||||
padding-left: 18px;
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
.header_navigation #search_box input[type='search']::-webkit-search-cancel-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.header_navigation #search_box #search_box_fr form, .header_navigation #search_box #search_box_fr #search_and_one_more_wrapper {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.header_navigation #search_box #searchBoxFastTips {
|
||||
display: none;
|
||||
position: absolute;
|
||||
background: #fff;
|
||||
border: 1px solid #d8d8d8;
|
||||
border-top: unset;
|
||||
margin-top: -1px;
|
||||
box-shadow: 2px 3px 4px -1px rgba(34, 60, 80, 0.2);
|
||||
}
|
||||
|
||||
.header_navigation #search_box #searchBoxFastTips a {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 6px;
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.header_navigation #search_box #searchBoxFastTips a b, .header_navigation #search_box #searchBoxFastTips a span {
|
||||
display: block;
|
||||
text-transform: initial;
|
||||
line-height: 12px;
|
||||
}
|
||||
|
||||
.header_navigation #search_box #searchBoxFastTips a:hover, .header_navigation #search_box #searchBoxFastTips a:focus {
|
||||
background: #f3f3f3;
|
||||
}
|
||||
|
||||
.header_navigation #search_box #searchBoxFastTips a .search_tip_info_block {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
align-items: baseline;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.header_navigation #search_box #searchBoxFastTips a img {
|
||||
width: 33px;
|
||||
height: 33px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.page_header.search_expanded .header_navigation #search_box #searchBoxFastTips.shown {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.page_header.search_expanded .link {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.page_header.search_expanded #search_and_one_more_wrapper {
|
||||
width: 627px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* не говновёрстка, а пиксель-пёрфект) */
|
||||
.page_header.search_expanded.search_expanded_at_all #search_and_one_more_wrapper {
|
||||
width: 547px;
|
||||
}
|
||||
|
||||
.page_header.search_expanded #search_box input[type='search'] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.header_navigation #search_box select[name='section'], .header_navigation #search_box .search_box_button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.page_header.search_expanded select[name='section'] {
|
||||
display: inline-block !important;
|
||||
}
|
||||
|
||||
.page_header.search_expanded_at_all .search_box_button {
|
||||
display: inline-block !important;
|
||||
}
|
||||
|
||||
.page_header select[name='section'] {
|
||||
width: auto;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
padding: 0px 0px;
|
||||
right: 0;
|
||||
text-align: right;
|
||||
border-left: 0px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.header_navigation #search_box .search_box_button {
|
||||
border: solid 1px #575757;
|
||||
background-color: #696969;
|
||||
color:white;
|
||||
margin-left: -11px;
|
||||
padding-bottom:2px;
|
||||
width:80px;
|
||||
color: #ffffff;
|
||||
padding: 1px 0px 1px 0px;
|
||||
width: 80px;
|
||||
cursor: pointer;
|
||||
box-shadow: 0px 2px 0px 0px rgba(255, 255, 255, 0.18) inset;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.searchBtn:active {
|
||||
.header_navigation #search_box .search_box_button span {
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.header_navigation #search_box .search_box_button:active {
|
||||
border: solid 1px #666666;
|
||||
background-color: #696969;
|
||||
color:white;
|
||||
box-shadow: 0px -2px 0px 0px rgba(255, 255, 255, 0.18) inset;
|
||||
}
|
||||
|
||||
.searchList {
|
||||
list-style: none;
|
||||
user-select: none;
|
||||
padding-left:0px;
|
||||
}
|
||||
|
||||
.searchList #used {
|
||||
margin-left:0px;
|
||||
color: white !important;
|
||||
padding:2px;
|
||||
padding-top:5px;
|
||||
padding-bottom:5px;
|
||||
border: solid 0.125rem #4F4F4F;
|
||||
background: #606060;
|
||||
margin-bottom:2px;
|
||||
padding-left:9px;
|
||||
width:87%;
|
||||
}
|
||||
|
||||
.searchList #used a {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.sr:focus {
|
||||
outline:none;
|
||||
}
|
||||
|
||||
.searchHide {
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.searchList li, .searchList a
|
||||
{
|
||||
/* Search layout */
|
||||
#search_page {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.page_content_paginator_bottom {
|
||||
background: #f7f7f7;
|
||||
border-top: 1px solid #d8d8d8;
|
||||
padding: 8px 8px;
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
}
|
||||
|
||||
.page_wrap_content_main {
|
||||
padding: 3px 3px;
|
||||
width: 74%;
|
||||
}
|
||||
|
||||
.page_wrap_content_main.audios_padding {
|
||||
padding: 8px 8px;
|
||||
}
|
||||
|
||||
.page_wrap_content_main .def_row_content {
|
||||
border-bottom: #ECECEC solid 1px;
|
||||
padding: 3px 1px;
|
||||
}
|
||||
|
||||
.page_wrap_content_main .def_row_content:first-of-type {
|
||||
padding: 0px 1px 3px 1px;
|
||||
}
|
||||
|
||||
.page_wrap_content_main .search_content:first-of-type .post {
|
||||
border-top: unset;
|
||||
padding-top: unset;
|
||||
}
|
||||
|
||||
.page_wrap_content_main .search_content:last-of-type .post, .page_wrap_content_main .def_row_content:last-of-type {
|
||||
border-bottom: unset;
|
||||
padding-bottom: unset;
|
||||
}
|
||||
|
||||
.verticalGrayTabsWrapper {
|
||||
width: 158px;
|
||||
border-top: 1px solid #E5E7E6;
|
||||
border-left: 1px solid #d8d8d8;
|
||||
scrollbar-width: none;
|
||||
font-size: 12px;
|
||||
background-color:#f7f7f7;
|
||||
}
|
||||
|
||||
.searchList, .verticalGrayTabs {
|
||||
list-style: none;
|
||||
user-select: none;
|
||||
padding-left: 0px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1px;
|
||||
}
|
||||
|
||||
.searchList hr, .verticalGrayTabs hr {
|
||||
width: 153px;
|
||||
margin-left: 0px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.verticalGrayTabs.with_padding, .verticalGrayTabs > .with_padding {
|
||||
padding: 4px 4px 4px 4px;
|
||||
}
|
||||
|
||||
.searchList #used, .verticalGrayTabs #used {
|
||||
color: #ffffff !important;
|
||||
padding: 5px 9px 5px 9px;
|
||||
border: solid 0.125rem #4F4F4F;
|
||||
background: #606060;
|
||||
}
|
||||
|
||||
.searchList #used a, .verticalGrayTabs #used a {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.searchList li, .searchList a, .verticalGrayTabs a {
|
||||
display: block;
|
||||
margin-left:0px;
|
||||
font-size: 12px;
|
||||
color: #2B587A !important;
|
||||
cursor:pointer;
|
||||
padding:2px;
|
||||
padding-top:5px;
|
||||
padding-bottom:5px;
|
||||
margin-bottom:2px;
|
||||
padding-left:9px;
|
||||
cursor: pointer;
|
||||
padding: 5px 9px 5px 9px;
|
||||
}
|
||||
|
||||
.searchList li a {
|
||||
min-width:100%;
|
||||
}
|
||||
|
||||
.searchList a {
|
||||
min-width: 88%;
|
||||
}
|
||||
|
||||
.searchList a:hover {
|
||||
.searchList a:hover, .verticalGrayTabs a:hover {
|
||||
margin-left: 0px;
|
||||
color: #2B587A !important;
|
||||
background: #ebebeb;
|
||||
padding: 2px;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
margin-bottom: 2px;
|
||||
padding-left: 9px;
|
||||
width: 89.9%;
|
||||
}
|
||||
|
||||
.whatFind {
|
||||
color:rgb(128, 128, 128);
|
||||
background:none;
|
||||
border:none;
|
||||
position:absolute;
|
||||
width:150px;
|
||||
cursor:pointer;
|
||||
right:80px;
|
||||
text-align:right;
|
||||
margin-top: 0.5px;
|
||||
.highlight {
|
||||
background: #ffea6d;
|
||||
border-bottom: 1px solid #c7c727;
|
||||
font-weight: bolder;
|
||||
padding: 0px 1px;
|
||||
}
|
||||
|
||||
.searchOptionName {
|
||||
cursor:pointer;
|
||||
background-color: #EAEAEA;
|
||||
padding-left:5px;
|
||||
padding-top:5px;
|
||||
padding-bottom:5px;
|
||||
width: 90%;
|
||||
font-weight: 600;
|
||||
color: #585858;
|
||||
border-bottom: 2px solid #E4E4E4;
|
||||
/* Options */
|
||||
|
||||
.page_wrap_content .page_search_options {
|
||||
padding: 0px 4px 4px 4px;
|
||||
}
|
||||
|
||||
.searchOption {
|
||||
.page_wrap_content .page_search_options .search_option {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.searchOptionBlock
|
||||
{
|
||||
.page_wrap_content .page_search_options .search_option .search_option_name_ico {
|
||||
width: 9px;
|
||||
height: 8px;
|
||||
display: inline-block;
|
||||
background-repeat: no-repeat;
|
||||
background: url('/assets/packages/static/openvk/img/arrows.png');
|
||||
}
|
||||
|
||||
.page_wrap_content .page_search_options .search_option.search_option_hidden .search_option_name_ico {
|
||||
background-position: -9px 0px;
|
||||
}
|
||||
|
||||
.page_wrap_content .page_search_options .search_option.search_option_hidden .search_option_content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.page_wrap_content .page_search_options .search_option .search_option_name {
|
||||
cursor: pointer;
|
||||
background-color: #EAEAEA;
|
||||
padding: 5px 5px 5px 5px;
|
||||
font-weight: 600;
|
||||
color: #585858;
|
||||
border-bottom: 2px solid #E4E4E4;
|
||||
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.page_wrap_content .page_search_options .search_option .search_option_content {
|
||||
margin-top: -5px;
|
||||
padding-top:10px;
|
||||
max-width:92%;
|
||||
padding-bottom:6px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
.searchOptionBlock select
|
||||
{
|
||||
padding-left:7px;
|
||||
padding-top:3px;
|
||||
padding-bottom:3px;
|
||||
cursor:pointer;
|
||||
.page_wrap_content .page_search_options .search_option .search_option_content label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.searchOptionBlock input[type=text], input[type=date]
|
||||
{
|
||||
margin-bottom:5px;
|
||||
.page_wrap_content .page_search_options .search_option .search_option_content select {
|
||||
padding-left: 3px;
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.borderup
|
||||
{
|
||||
border-top:1px solid #E5E7E6;
|
||||
.page_wrap_content .page_search_options #search_reset {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
#searchInput
|
||||
{
|
||||
transition: .3s linear;
|
||||
.page_wrap_content .page_search_options .search_option .search_option_content input[type=text], .page_wrap_content .page_search_options .search_option .search_option_content input[type=date] {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.content_page_error {
|
||||
background: white;
|
||||
border: #DEDEDE solid 1px;
|
||||
height: 100%;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.content_page_error span {
|
||||
color: #707070;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Da search end. */
|
||||
|
||||
#standaloneCommentBox {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
|
@ -2646,52 +2857,6 @@ a.poll-retract-vote {
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
.searchTips
|
||||
{
|
||||
position: absolute;
|
||||
background: white;
|
||||
padding-left: 6px;
|
||||
padding-right: 6px;
|
||||
padding-bottom: 6px;
|
||||
border: 1px solid #C0CAD5;
|
||||
border-top: 0px;
|
||||
width: fit-content;
|
||||
z-index: 666666;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
.searchTips td
|
||||
{
|
||||
color: black;
|
||||
padding: 3px;
|
||||
font-weight: lighter;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.searchTips td .desq
|
||||
{
|
||||
margin-top: -9px;
|
||||
}
|
||||
|
||||
.restip td a:hover
|
||||
{
|
||||
color: black;
|
||||
font-weight: lighter;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.searchTips .restip
|
||||
{
|
||||
padding-right: 10px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.searchTips .restip:hover
|
||||
{
|
||||
background: rgb(236, 235, 235);
|
||||
}
|
||||
|
||||
.attachment_note_icon {
|
||||
max-width: 9px;
|
||||
}
|
||||
|
@ -3066,12 +3231,6 @@ hr {
|
|||
height: 1px;
|
||||
}
|
||||
|
||||
.searchList hr {
|
||||
width: 153px;
|
||||
margin-left: 0px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.showMore, .showMoreAudiosPlaylist {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
|
@ -3089,3 +3248,54 @@ hr {
|
|||
background-repeat: no-repeat !important;
|
||||
background-position: 50% !important;
|
||||
}
|
||||
|
||||
.entity_vertical_list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3px;
|
||||
height: 197px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.entity_vertical_list .entity_vertical_list_item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.entity_vertical_list .entity_vertical_list_item .first_column {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.entity_vertical_list .entity_vertical_list_item .avatar {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.entity_vertical_list .entity_vertical_list_item img {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.entity_vertical_list .entity_vertical_list_item .info {
|
||||
width: 300px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.entity_vertical_list.mini .entity_vertical_list_item img {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
#gif_loader {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
background-image: url('/assets/packages/static/openvk/img/loading_mini.gif');
|
||||
width: 30px;
|
||||
height: 7px;
|
||||
}
|
||||
|
|
72
Web/static/img/app_icons_mini/wphone.svg
Normal file
72
Web/static/img/app_icons_mini/wphone.svg
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
id="windowskey"
|
||||
version="1.1"
|
||||
width="13"
|
||||
height="12"
|
||||
viewBox="0 0 13 12"
|
||||
sodipodi:docname="wphone.svg"
|
||||
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs79" />
|
||||
<sodipodi:namedview
|
||||
id="namedview77"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#eeeeee"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#505050"
|
||||
showgrid="false"
|
||||
inkscape:zoom="45.254834"
|
||||
inkscape:cx="4.6514368"
|
||||
inkscape:cy="5.0381358"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1009"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="windowskey" />
|
||||
<g
|
||||
id="g26"
|
||||
transform="matrix(1.1345617,0,0,1.1369577,0.2820346,-0.32489569)"
|
||||
style="stroke:none;fill:#b1bfcd;fill-opacity:1">
|
||||
<path
|
||||
id="rbyll"
|
||||
d="M 10.7,5.95 V 10.8 L 5.13,9.93 V 5.94 Z"
|
||||
style="fill:#b1bfcd;stroke-width:0;stroke:none;fill-opacity:1" />
|
||||
<path
|
||||
id="rtgrn"
|
||||
d="M 5.13,1.13 10.7,0.326 V 5.1 H 5.13 Z"
|
||||
style="fill:#b1bfcd;stroke-width:0;stroke:none;fill-opacity:1" />
|
||||
<path
|
||||
id="lbblu"
|
||||
d="M 4.39,5.91 V 9.86 L 0.264,9.29 v -3.4 z"
|
||||
style="fill:#b1bfcd;stroke-width:0;stroke:none;fill-opacity:1" />
|
||||
<path
|
||||
id="ltred"
|
||||
d="M 0.261,1.77 4.39,1.2 V 5.15 H 0.263 Z"
|
||||
style="fill:#b1bfcd;stroke-width:0;stroke:none;fill-opacity:1" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:#b1bfcd;stroke-width:0.019;stroke-dasharray:none;stroke:none;fill-opacity:1"
|
||||
d="M 0.59279246,5.1581071 C 0.58639332,4.9590688 0.58035022,4.0999853 0.57936334,3.2490325 l -0.001794,-1.5471867 0.0538026,-0.010946 C 0.66096303,1.6848789 1.0412718,1.6310397 1.4765021,1.5712567 1.9117325,1.5114737 2.93877,1.3697978 3.7588077,1.2564213 L 5.2497853,1.0502822 V 3.2851385 5.5199949 H 2.9271062 0.60442726 Z"
|
||||
id="path277" />
|
||||
<path
|
||||
style="fill:#b1bfcd;stroke-width:0.019;stroke-dasharray:none;stroke:none;fill-opacity:1"
|
||||
d="m 6.118316,3.2135634 c 0,-1.2366911 0.00303,-2.24852933 0.00672,-2.24852933 0.0037,0 0.4575049,-0.0654202 1.0084606,-0.14537825 0.5509557,-0.079958 1.422975,-0.2061814 1.9378206,-0.2804964 0.5148457,-0.074315 1.4729638,-0.2129995 2.1291498,-0.30818778 0.656188,-0.0951883 1.196848,-0.1730696 1.201468,-0.1730696 0.0046,0 0.0084,1.21594296 0.0084,2.70209536 V 5.4620928 H 9.2643271 6.118316 Z"
|
||||
id="path279" />
|
||||
<path
|
||||
style="fill:#b1bfcd;stroke-width:0;stroke-dasharray:none;stroke:none;fill-opacity:1"
|
||||
d="M 11.802367,11.85061 C 11.483905,11.79947 10.658801,11.669367 9.9688019,11.561492 9.2788026,11.453616 8.1371252,11.274777 7.4317409,11.164071 6.7263567,11.053365 6.1422699,10.962787 6.1337701,10.962787 c -0.0085,0 -0.015454,-1.0161809 -0.015454,-2.2581797 V 6.4464276 h 3.1460111 3.1460108 v 2.7503471 c 0,1.5126913 -0.0065,2.7495523 -0.01447,2.7485813 -0.008,-9.71e-4 -0.275035,-0.04361 -0.593496,-0.09475 z"
|
||||
id="path281" />
|
||||
<path
|
||||
style="fill:#b1bfcd;stroke-width:0.019;stroke-dasharray:none;stroke:none;fill-opacity:1"
|
||||
d="M 4.8830724,10.826259 C 4.5998231,10.784852 3.2581997,10.598446 1.7756627,10.394512 1.1971248,10.31493 0.6955483,10.244822 0.66104834,10.238715 l -0.0627272,-0.0111 V 8.3080688 6.3885255 L 2.0989491,6.38855 c 0.8253454,1.36e-5 1.8719248,0.00577 2.3257321,0.012793 l 0.8251041,0.012769 v 2.2260859 2.2260861 l -0.062727,-0.0024 c -0.0345,-0.0013 -0.1712935,-0.01825 -0.3039857,-0.03765 z"
|
||||
id="path283" />
|
||||
</svg>
|
After Width: | Height: | Size: 3.8 KiB |
BIN
Web/static/img/arrows.png
Normal file
BIN
Web/static/img/arrows.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 219 B |
Binary file not shown.
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 4.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 263 B |
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue