mirror of
https://github.com/openvk/openvk
synced 2025-04-23 16:43:02 +03:00
Merge branch 'master' into disco
This commit is contained in:
commit
861456964e
188 changed files with 7189 additions and 3636 deletions
58
.github/workflows/build-base.yaml
vendored
Normal file
58
.github/workflows/build-base.yaml
vendored
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
name: Build base images
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * *'
|
||||||
|
|
||||||
|
env:
|
||||||
|
BASE_IMAGE_NAME: php
|
||||||
|
BASE_IMAGE_VERSION: "8.1"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-cli:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
lfs: false
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
id: buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
|
- 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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
build-apache:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
lfs: false
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
id: buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
|
- 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
|
||||||
|
|
||||||
|
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
|
64
.github/workflows/build.yaml
vendored
Normal file
64
.github/workflows/build.yaml
vendored
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
name: Build images
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
# Publish `master` as Docker `latest` image.
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
# Publish `v1.2.3` tags as releases.
|
||||||
|
tags:
|
||||||
|
- v*
|
||||||
|
|
||||||
|
env:
|
||||||
|
BASE_IMAGE_NAME: openvk
|
||||||
|
DB_IMAGE_NAME: mariadb
|
||||||
|
EVENT_IMAGE_NAME: mariadb
|
||||||
|
DB_VERSION: "10.9"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
arch: ['x86_64']
|
||||||
|
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
lfs: false
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
id: buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
|
- 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=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
|
||||||
|
VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
|
||||||
|
[[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')
|
||||||
|
[ "$VERSION" == "master" ] && VERSION=latest
|
||||||
|
echo IMAGE_ID=$IMAGE_ID
|
||||||
|
echo VERSION=$VERSION
|
||||||
|
|
||||||
|
docker buildx build --platform linux/amd64,linux/arm64 -t $IMAGE_ID:$VERSION . --push -f install/automated/docker/openvk.Dockerfile --build-arg GITREPO=${{ github.repository }}
|
||||||
|
|
||||||
|
- name: Build MariaDB primary image
|
||||||
|
run: |
|
||||||
|
IMAGE_NAME=ghcr.io/${{ github.repository }}/$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
|
||||||
|
|
||||||
|
docker buildx build --platform linux/amd64,linux/arm64 -t $IMAGE_NAME . --push -f install/automated/docker/mariadb-eventdb.Dockerfile --build-arg VERSION=$DB_VERSION
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,5 +1,6 @@
|
||||||
vendor
|
vendor
|
||||||
openvk.yml
|
openvk.yml
|
||||||
|
chandler.yml
|
||||||
update.pid
|
update.pid
|
||||||
update.pid.old
|
update.pid.old
|
||||||
Web/static/js/node_modules
|
Web/static/js/node_modules
|
||||||
|
@ -10,5 +11,6 @@ tmp/*
|
||||||
themepacks/*
|
themepacks/*
|
||||||
!themepacks/.gitkeep
|
!themepacks/.gitkeep
|
||||||
!themepacks/openvk_modern
|
!themepacks/openvk_modern
|
||||||
|
!themepacks/midnight
|
||||||
storage/*
|
storage/*
|
||||||
!storage/.gitkeep
|
!storage/.gitkeep
|
||||||
|
|
82
Dockerfile
82
Dockerfile
|
@ -1,82 +0,0 @@
|
||||||
FROM fedora:33
|
|
||||||
|
|
||||||
#update and install httpd
|
|
||||||
RUN dnf -y update && dnf -y autoremove && dnf install -y httpd
|
|
||||||
|
|
||||||
#Let's install Remi repos for PHP 7.4:
|
|
||||||
RUN dnf -y install https://rpms.remirepo.net/fedora/remi-release-$(rpm -E %fedora).rpm
|
|
||||||
|
|
||||||
#Then enable modules that we need:
|
|
||||||
RUN dnf -y module enable php:remi-7.4 && \
|
|
||||||
dnf -y module enable nodejs:14
|
|
||||||
|
|
||||||
#And install dependencies:
|
|
||||||
RUN dnf -y --skip-broken install php php-cli php-common unzip php-zip php-yaml php-gd php-pdo_mysql nodejs git
|
|
||||||
|
|
||||||
#Don't forget about Yarn and Composer:
|
|
||||||
RUN npm i -g yarn && \
|
|
||||||
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" && \
|
|
||||||
php composer-setup.php --filename=composer2 --install-dir=/bin --snapshot && \
|
|
||||||
rm composer-setup.php
|
|
||||||
|
|
||||||
#We will use Mariadb for DB:
|
|
||||||
RUN dnf -y install mysql mysql-server && \
|
|
||||||
systemctl enable mariadb && \
|
|
||||||
echo 'skip-grant-tables' >> /etc/my.cnf
|
|
||||||
|
|
||||||
#Additionally, you can install ffmpeg for processing videos.
|
|
||||||
#You will need to use RPMFusion repo to install it:
|
|
||||||
RUN dnf -y install --nogpgcheck https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm && \
|
|
||||||
dnf -y install --nogpgcheck https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm
|
|
||||||
|
|
||||||
#Then install SDL2 and ffmpeg:
|
|
||||||
RUN dnf -y install --nogpgcheck SDL2 ffmpeg
|
|
||||||
|
|
||||||
#Install Chandler and OpenVk/Capcha-extention in /opt:
|
|
||||||
RUN cd /opt && \
|
|
||||||
git clone https://github.com/samukhin/chandler.git && \
|
|
||||||
cd chandler/ && \
|
|
||||||
composer2 install && \
|
|
||||||
mv chandler-example.yml chandler.yml && \
|
|
||||||
cd extensions/available/ && \
|
|
||||||
git clone https://github.com/samukhin/commitcaptcha.git && \
|
|
||||||
cd commitcaptcha/ && \
|
|
||||||
composer2 install && \
|
|
||||||
cd .. && \
|
|
||||||
git clone https://github.com/samukhin/openvk.git && \
|
|
||||||
cd openvk/ && \
|
|
||||||
composer2 install && \
|
|
||||||
cd Web/static/js && \
|
|
||||||
yarn install && \
|
|
||||||
cd ../../../ && \
|
|
||||||
mv openvk-example.yml openvk.yml && \
|
|
||||||
ln -s /opt/chandler/extensions/available/commitcaptcha/ /opt/chandler/extensions/enabled/commitcaptcha && \
|
|
||||||
ln -s /opt/chandler/extensions/available/openvk/ /opt/chandler/extensions/enabled/openvk
|
|
||||||
|
|
||||||
#Create database
|
|
||||||
RUN cp /opt/chandler/extensions/available/openvk/install/automated/common/create_db.service /etc/systemd/system/ && \
|
|
||||||
chmod 644 /etc/systemd/system/create_db.service && \
|
|
||||||
chmod 777 /opt/chandler/extensions/available/openvk/install/automated/common/autoexec && \
|
|
||||||
systemctl enable create_db
|
|
||||||
|
|
||||||
#Make the user apache owner of the chandler folder:
|
|
||||||
RUN cd /opt && \
|
|
||||||
chown -R apache: chandler/
|
|
||||||
|
|
||||||
#Now let's create config file /etc/httpd/conf.d/10-openvk.conf and
|
|
||||||
#Also enable rewrite_module by creating /etc/httpd/conf.modules.d/02-rewrite.conf
|
|
||||||
RUN cp /opt/chandler/extensions/available/openvk/install/automated/common/10-openvk.conf /etc/httpd/conf.d/ && \
|
|
||||||
cp /opt/chandler/extensions/available/openvk/install/automated/common/02-rewrite.conf /etc/httpd/conf.modules.d/
|
|
||||||
|
|
||||||
#Make directory for OpenVK logs and make the user apache owner of it:
|
|
||||||
RUN mkdir /var/log/openvk && \
|
|
||||||
chown apache: /var/log/openvk/
|
|
||||||
|
|
||||||
#And start Apache:
|
|
||||||
#RUN systemctl enable httpd
|
|
||||||
|
|
||||||
#For login
|
|
||||||
RUN dnf -y install passwd && passwd -d root
|
|
||||||
|
|
||||||
#Start systemd
|
|
||||||
CMD ["/sbin/init"]
|
|
|
@ -72,6 +72,9 @@ Once you are done, you can login as a system administrator on the network itself
|
||||||
|
|
||||||
💡Confused? Full installation walkthrough is available [here](https://docs.openvk.su/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.openvk.su/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 it's 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're planning to redistribute this, then you should license it under terms of any LGPL-compatible license (like OSL, GPL, LGPL etc).
|
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're planning to redistribute this, then you should license it under terms of any LGPL-compatible license (like OSL, GPL, LGPL etc).
|
||||||
|
|
|
@ -72,6 +72,9 @@ ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions
|
||||||
|
|
||||||
💡Запутались? Полное руководство по установке доступно [здесь](https://docs.openvk.su/openvk_engine/centos8_installation/) (CentOS 8 [и](https://almalinux.org/ru/) [семейство](https://yum.oracle.com/oracle-linux-isos.html)).
|
💡Запутались? Полное руководство по установке доступно [здесь](https://docs.openvk.su/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` соответственно.
|
||||||
|
|
||||||
### Если мой сайт использует OpenVK, должен ли я публиковать его исходные тексты?
|
### Если мой сайт использует OpenVK, должен ли я публиковать его исходные тексты?
|
||||||
|
|
||||||
Это зависит от обстоятельств. Вы можете оставить исходные тексты при себе, если не планируете распространять бинарники вашего сайта. Если программное обеспечение вашего сайта должно распространяться, оно может оставаться не-OSS при условии, что OpenVK не используется в качестве основного приложения и не модифицируется. Если вы модифицировали OpenVK для своих нужд или ваша работа основана на нем и вы планируете ее распространять, то вы должны лицензировать ее на условиях любой совместимой с LGPL лицензии (например, OSL, GPL, LGPL и т.д.).
|
Это зависит от обстоятельств. Вы можете оставить исходные тексты при себе, если не планируете распространять бинарники вашего сайта. Если программное обеспечение вашего сайта должно распространяться, оно может оставаться не-OSS при условии, что OpenVK не используется в качестве основного приложения и не модифицируется. Если вы модифицировали OpenVK для своих нужд или ваша работа основана на нем и вы планируете ее распространять, то вы должны лицензировать ее на условиях любой совместимой с LGPL лицензии (например, OSL, GPL, LGPL и т.д.).
|
||||||
|
|
|
@ -55,6 +55,11 @@ class Apps implements Handler
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($amount < 0) {
|
||||||
|
$reject(552, "Payment amount is invalid");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$coinsLeft = $this->user->getCoins() - $amount;
|
$coinsLeft = $this->user->getCoins() - $amount;
|
||||||
if($coinsLeft < 0) {
|
if($coinsLeft < 0) {
|
||||||
$reject(41, "Not enough money");
|
$reject(41, "Not enough money");
|
||||||
|
|
50
ServiceAPI/Mentions.php
Normal file
50
ServiceAPI/Mentions.php
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\ServiceAPI;
|
||||||
|
use openvk\Web\Models\Entities\User;
|
||||||
|
use openvk\Web\Models\Repositories\{Users, Clubs};
|
||||||
|
|
||||||
|
class Mentions implements Handler
|
||||||
|
{
|
||||||
|
protected $user;
|
||||||
|
|
||||||
|
function __construct(?User $user)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolve(int $id, callable $resolve, callable $reject): void
|
||||||
|
{
|
||||||
|
if($id > 0) {
|
||||||
|
$user = (new Users)->get($id);
|
||||||
|
if(!$user) {
|
||||||
|
$reject("Not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$resolve([
|
||||||
|
"url" => $user->getURL(),
|
||||||
|
"name" => $user->getFullName(),
|
||||||
|
"ava" => $user->getAvatarURL("miniscule"),
|
||||||
|
"about" => $user->getStatus() ?? "",
|
||||||
|
"online" => ($user->isFemale() ? tr("was_online_f") : tr("was_online_m")) . " " . $user->getOnline(),
|
||||||
|
"verif" => $user->isVerified(),
|
||||||
|
]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$club = (new Clubs)->get(abs($id));
|
||||||
|
if(!$club) {
|
||||||
|
$reject("Not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$resolve([
|
||||||
|
"url" => $club->getURL(),
|
||||||
|
"name" => $club->getName(),
|
||||||
|
"ava" => $club->getAvatarURL("miniscule"),
|
||||||
|
"about" => $club->getDescription() ?? "",
|
||||||
|
"online" => tr("participants", $club->getFollowersCount()),
|
||||||
|
"verif" => $club->isVerified(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
70
ServiceAPI/Polls.php
Normal file
70
ServiceAPI/Polls.php
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\ServiceAPI;
|
||||||
|
use Chandler\MVC\Routing\Router;
|
||||||
|
use openvk\Web\Models\Entities\User;
|
||||||
|
use openvk\Web\Models\Exceptions\{AlreadyVotedException, InvalidOptionException, PollLockedException};
|
||||||
|
use openvk\Web\Models\Repositories\Polls as PollRepo;
|
||||||
|
use UnexpectedValueException;
|
||||||
|
|
||||||
|
class Polls implements Handler
|
||||||
|
{
|
||||||
|
protected $user;
|
||||||
|
protected $polls;
|
||||||
|
|
||||||
|
function __construct(?User $user)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
$this->polls = new PollRepo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getPollHtml(int $poll): string
|
||||||
|
{
|
||||||
|
return Router::i()->execute("/poll$poll", "SAPI");
|
||||||
|
}
|
||||||
|
|
||||||
|
function vote(int $pollId, string $options, callable $resolve, callable $reject): void
|
||||||
|
{
|
||||||
|
$poll = $this->polls->get($pollId);
|
||||||
|
if(!$poll) {
|
||||||
|
$reject("Poll not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$options = explode(",", $options);
|
||||||
|
$poll->vote($this->user, $options);
|
||||||
|
} catch(AlreadyVotedException $ex) {
|
||||||
|
$reject("Poll state changed: user has already voted.");
|
||||||
|
return;
|
||||||
|
} catch(PollLockedException $ex) {
|
||||||
|
$reject("Poll state changed: poll has ended.");
|
||||||
|
return;
|
||||||
|
} catch(InvalidOptionException $ex) {
|
||||||
|
$reject("Foreign options passed.");
|
||||||
|
return;
|
||||||
|
} catch(UnexpectedValueException $ex) {
|
||||||
|
$reject("Too much options passed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$resolve(["html" => $this->getPollHtml($pollId)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function unvote(int $pollId, callable $resolve, callable $reject): void
|
||||||
|
{
|
||||||
|
$poll = $this->polls->get($pollId);
|
||||||
|
if(!$poll) {
|
||||||
|
$reject("Poll not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$poll->revokeVote($this->user);
|
||||||
|
} catch(PollLockedException $ex) {
|
||||||
|
$reject("Votes can't be revoked from this poll.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$resolve(["html" => $this->getPollHtml($pollId)]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\VKAPI\Handlers;
|
namespace openvk\VKAPI\Handlers;
|
||||||
|
use openvk\Web\Models\Exceptions\InvalidUserNameException;
|
||||||
|
|
||||||
final class Account extends VKAPIRequestHandler
|
final class Account extends VKAPIRequestHandler
|
||||||
{
|
{
|
||||||
|
@ -13,7 +14,7 @@ final class Account extends VKAPIRequestHandler
|
||||||
"last_name" => $this->getUser()->getLastName(),
|
"last_name" => $this->getUser()->getLastName(),
|
||||||
"home_town" => $this->getUser()->getHometown(),
|
"home_town" => $this->getUser()->getHometown(),
|
||||||
"status" => $this->getUser()->getStatus(),
|
"status" => $this->getUser()->getStatus(),
|
||||||
"bdate" => $this->getUser()->getBirthday()->format('%e.%m.%Y'),
|
"bdate" => is_null($this->getUser()->getBirthday()) ? '01.01.1970' : $this->getUser()->getBirthday()->format('%e.%m.%Y'),
|
||||||
"bdate_visibility" => $this->getUser()->getBirthdayPrivacy(),
|
"bdate_visibility" => $this->getUser()->getBirthdayPrivacy(),
|
||||||
"phone" => "+420 ** *** 228", # TODO
|
"phone" => "+420 ** *** 228", # TODO
|
||||||
"relation" => $this->getUser()->getMaritalStatus(),
|
"relation" => $this->getUser()->getMaritalStatus(),
|
||||||
|
@ -74,4 +75,77 @@ final class Account extends VKAPIRequestHandler
|
||||||
|
|
||||||
# TODO: Filter
|
# TODO: Filter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function saveProfileInfo(string $first_name = "", string $last_name = "", string $screen_name = "", int $sex = -1, int $relation = -1, string $bdate = "", int $bdate_visibility = -1, string $home_town = "", string $status = ""): object
|
||||||
|
{
|
||||||
|
$this->requireUser();
|
||||||
|
$user = $this->getUser();
|
||||||
|
|
||||||
|
$output = [
|
||||||
|
"changed" => 0,
|
||||||
|
];
|
||||||
|
|
||||||
|
if(!empty($first_name) || !empty($last_name)) {
|
||||||
|
$output["name_request"] = [
|
||||||
|
"id" => random_int(1, 2048), # For compatibility with original VK API
|
||||||
|
"status" => "success",
|
||||||
|
"first_name" => !empty($first_name) ? $first_name : $user->getFirstName(),
|
||||||
|
"last_name" => !empty($last_name) ? $last_name : $user->getLastName(),
|
||||||
|
];
|
||||||
|
|
||||||
|
try {
|
||||||
|
if(!empty($first_name))
|
||||||
|
$user->setFirst_name($first_name);
|
||||||
|
if(!empty($last_name))
|
||||||
|
$user->setLast_Name($last_name);
|
||||||
|
} catch (InvalidUserNameException $e) {
|
||||||
|
$output["name_request"]["status"] = "declined";
|
||||||
|
return (object) $output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!empty($screen_name))
|
||||||
|
if (!$user->setShortCode($screen_name))
|
||||||
|
$this->fail(1260, "Invalid screen name");
|
||||||
|
|
||||||
|
# For compatibility with original VK API
|
||||||
|
if($sex > 0)
|
||||||
|
$user->setSex($sex == 1 ? 1 : 0);
|
||||||
|
|
||||||
|
if($relation > -1)
|
||||||
|
$user->setMarital_Status($relation);
|
||||||
|
|
||||||
|
if(!empty($bdate)) {
|
||||||
|
$birthday = strtotime($bdate);
|
||||||
|
if (!is_int($birthday))
|
||||||
|
$this->fail(100, "invalid value of bdate.");
|
||||||
|
|
||||||
|
$user->setBirthday($birthday);
|
||||||
|
}
|
||||||
|
|
||||||
|
# For compatibility with original VK API
|
||||||
|
switch($bdate_visibility) {
|
||||||
|
case 0:
|
||||||
|
$this->fail(946, "Hiding date of birth is not implemented.");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
$user->setBirthday_privacy(0);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
$user->setBirthday_privacy(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!empty($home_town))
|
||||||
|
$user->setHometown($home_town);
|
||||||
|
|
||||||
|
if(!empty($status))
|
||||||
|
$user->setStatus($status);
|
||||||
|
|
||||||
|
if($sex > 0 || $relation > -1 || $bdate_visibility > 1 || !empty("$first_name$last_name$screen_name$bdate$home_town$status")) {
|
||||||
|
$output["changed"] = 1;
|
||||||
|
$user->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (object) $output;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,7 +107,7 @@ final class Friends extends VKAPIRequestHandler
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fail(15, "Access denied: No friend or friend request found.");
|
$this->fail(15, "Access denied: No friend or friend request found.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,15 +133,18 @@ final class Friends extends VKAPIRequestHandler
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRequests(string $fields = "", int $offset = 0, int $count = 100): object
|
function getRequests(string $fields = "", 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.");
|
||||||
|
|
||||||
$this->requireUser();
|
$this->requireUser();
|
||||||
|
|
||||||
$i = 0;
|
$i = 0;
|
||||||
$offset++;
|
$offset++;
|
||||||
$followers = [];
|
$followers = [];
|
||||||
|
|
||||||
foreach($this->getUser()->getFollowers() as $follower) {
|
foreach($this->getUser()->getFollowers($offset, $count) as $follower) {
|
||||||
$followers[$i] = $follower->getId();
|
$followers[$i] = $follower->getId();
|
||||||
$i++;
|
$i++;
|
||||||
}
|
}
|
||||||
|
@ -149,8 +152,10 @@ final class Friends extends VKAPIRequestHandler
|
||||||
$response = $followers;
|
$response = $followers;
|
||||||
$usersApi = new Users($this->getUser());
|
$usersApi = new Users($this->getUser());
|
||||||
|
|
||||||
if(!is_null($fields))
|
if($extended == 1)
|
||||||
$response = $usersApi->get(implode(',', $followers), $fields, 0, $count); # FIXME
|
$response = $usersApi->get(implode(',', $followers), $fields, 0, $count);
|
||||||
|
else
|
||||||
|
$response = $usersApi->get(implode(',', $followers), "", 0, $count);
|
||||||
|
|
||||||
foreach($response as $user)
|
foreach($response as $user)
|
||||||
$user->user_id = $user->id;
|
$user->user_id = $user->id;
|
||||||
|
|
|
@ -10,7 +10,7 @@ final class Groups extends VKAPIRequestHandler
|
||||||
$this->requireUser();
|
$this->requireUser();
|
||||||
|
|
||||||
if($user_id == 0) {
|
if($user_id == 0) {
|
||||||
foreach($this->getUser()->getClubs($offset+1) as $club)
|
foreach($this->getUser()->getClubs($offset, false, $count, true) as $club)
|
||||||
$clbs[] = $club;
|
$clbs[] = $club;
|
||||||
$clbsCount = $this->getUser()->getClubCount();
|
$clbsCount = $this->getUser()->getClubCount();
|
||||||
} else {
|
} else {
|
||||||
|
@ -20,7 +20,7 @@ final class Groups extends VKAPIRequestHandler
|
||||||
if(is_null($user))
|
if(is_null($user))
|
||||||
$this->fail(15, "Access denied");
|
$this->fail(15, "Access denied");
|
||||||
|
|
||||||
foreach($user->getClubs($offset+1) as $club)
|
foreach($user->getClubs($offset, false, $count, true) as $club)
|
||||||
$clbs[] = $club;
|
$clbs[] = $club;
|
||||||
|
|
||||||
$clbsCount = $user->getClubCount();
|
$clbsCount = $user->getClubCount();
|
||||||
|
@ -33,17 +33,9 @@ final class Groups extends VKAPIRequestHandler
|
||||||
$ic = $count;
|
$ic = $count;
|
||||||
|
|
||||||
if(!empty($clbs)) {
|
if(!empty($clbs)) {
|
||||||
$clbs = array_slice($clbs, $offset * $count);
|
|
||||||
|
|
||||||
for($i=0; $i < $ic; $i++) {
|
for($i=0; $i < $ic; $i++) {
|
||||||
$usr = $clbs[$i];
|
$usr = $clbs[$i];
|
||||||
if(is_null($usr)) {
|
if(is_null($usr)) {
|
||||||
$rClubs[$i] = (object)[
|
|
||||||
"id" => $clbs[$i],
|
|
||||||
"name" => "DELETED",
|
|
||||||
"deactivated" => "deleted"
|
|
||||||
];
|
|
||||||
} else if($clbs[$i] == NULL) {
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$rClubs[$i] = (object) [
|
$rClubs[$i] = (object) [
|
||||||
|
@ -102,23 +94,32 @@ final class Groups extends VKAPIRequestHandler
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getById(string $group_ids = "", string $group_id = "", string $fields = ""): ?array
|
function getById(string $group_ids = "", string $group_id = "", string $fields = "", int $offset = 0, int $count = 500): ?array
|
||||||
{
|
{
|
||||||
|
/* Both offset and count SHOULD be used only in OpenVK code,
|
||||||
|
not in your app or script, since it's not oficially documented by VK */
|
||||||
|
|
||||||
$clubs = new ClubsRepo;
|
$clubs = new ClubsRepo;
|
||||||
|
|
||||||
if($group_ids == NULL && $group_id != NULL)
|
if(empty($group_ids) && !empty($group_id))
|
||||||
$group_ids = $group_id;
|
$group_ids = $group_id;
|
||||||
|
|
||||||
if($group_ids == NULL && $group_id == NULL)
|
if(empty($group_ids) && empty($group_id))
|
||||||
$this->fail(100, "One of the parameters specified was missing or invalid: group_ids is undefined");
|
$this->fail(100, "One of the parameters specified was missing or invalid: group_ids is undefined");
|
||||||
|
|
||||||
$clbs = explode(',', $group_ids);
|
$clbs = explode(',', $group_ids);
|
||||||
$response;
|
$response = array();
|
||||||
|
|
||||||
$ic = sizeof($clbs);
|
$ic = sizeof($clbs);
|
||||||
|
|
||||||
|
if(sizeof($clbs) > $count)
|
||||||
|
$ic = $count;
|
||||||
|
|
||||||
|
$clbs = array_slice($clbs, $offset * $count);
|
||||||
|
|
||||||
|
|
||||||
for($i=0; $i < $ic; $i++) {
|
for($i=0; $i < $ic; $i++) {
|
||||||
if($i > 500)
|
if($i > 500 || $clbs[$i] == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if($clbs[$i] < 0)
|
if($clbs[$i] < 0)
|
||||||
|
@ -142,6 +143,7 @@ final class Groups extends VKAPIRequestHandler
|
||||||
"screen_name" => $clb->getShortCode() ?? "club".$clb->getId(),
|
"screen_name" => $clb->getShortCode() ?? "club".$clb->getId(),
|
||||||
"is_closed" => false,
|
"is_closed" => false,
|
||||||
"type" => "group",
|
"type" => "group",
|
||||||
|
"is_member" => !is_null($this->getUser()) ? (int) $clb->getSubscriptionStatus($this->getUser()) : 0,
|
||||||
"can_access_closed" => true,
|
"can_access_closed" => true,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -204,10 +206,6 @@ final class Groups extends VKAPIRequestHandler
|
||||||
else
|
else
|
||||||
$response[$i]->can_post = $clb->canPost();
|
$response[$i]->can_post = $clb->canPost();
|
||||||
break;
|
break;
|
||||||
case "is_member":
|
|
||||||
if(!is_null($this->getUser()))
|
|
||||||
$response[$i]->is_member = (int) $clb->getSubscriptionStatus($this->getUser());
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,4 +213,52 @@ final class Groups extends VKAPIRequestHandler
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function search(string $q, int $offset = 0, int $count = 100)
|
||||||
|
{
|
||||||
|
$clubs = new ClubsRepo;
|
||||||
|
|
||||||
|
$array = [];
|
||||||
|
$find = $clubs->find($q);
|
||||||
|
|
||||||
|
foreach ($find as $group)
|
||||||
|
$array[] = $group->getId();
|
||||||
|
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function join(int $group_id)
|
||||||
|
{
|
||||||
|
$this->requireUser();
|
||||||
|
|
||||||
|
$club = (new ClubsRepo)->get($group_id);
|
||||||
|
|
||||||
|
$isMember = !is_null($this->getUser()) ? (int) $club->getSubscriptionStatus($this->getUser()) : 0;
|
||||||
|
|
||||||
|
if($isMember == 0)
|
||||||
|
$club->toggleSubscription($this->getUser());
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function leave(int $group_id)
|
||||||
|
{
|
||||||
|
$this->requireUser();
|
||||||
|
|
||||||
|
$club = (new ClubsRepo)->get($group_id);
|
||||||
|
|
||||||
|
$isMember = !is_null($this->getUser()) ? (int) $club->getSubscriptionStatus($this->getUser()) : 0;
|
||||||
|
|
||||||
|
if($isMember == 1)
|
||||||
|
$club->toggleSubscription($this->getUser());
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -247,6 +247,7 @@ final class Messages extends VKAPIRequestHandler
|
||||||
|
|
||||||
$user = (new USRRepo)->get((int) $peer);
|
$user = (new USRRepo)->get((int) $peer);
|
||||||
|
|
||||||
|
if($user) {
|
||||||
$dialogue = new Correspondence($this->getUser(), $user);
|
$dialogue = new Correspondence($this->getUser(), $user);
|
||||||
$iterator = $dialogue->getMessages(Correspondence::CAP_BEHAVIOUR_START_MESSAGE_ID, 0, 1, 0, false);
|
$iterator = $dialogue->getMessages(Correspondence::CAP_BEHAVIOUR_START_MESSAGE_ID, 0, 1, 0, false);
|
||||||
$msg = $iterator[0]->unwrap(); // шоб удобнее было
|
$msg = $iterator[0]->unwrap(); // шоб удобнее было
|
||||||
|
@ -274,6 +275,7 @@ final class Messages extends VKAPIRequestHandler
|
||||||
];
|
];
|
||||||
$userslist[] = $user->getId();
|
$userslist[] = $user->getId();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if($extended == 1) {
|
if($extended == 1) {
|
||||||
$userslist = array_unique($userslist);
|
$userslist = array_unique($userslist);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
namespace openvk\VKAPI\Handlers;
|
namespace openvk\VKAPI\Handlers;
|
||||||
use Chandler\Database\DatabaseConnection;
|
use Chandler\Database\DatabaseConnection;
|
||||||
use openvk\Web\Models\Repositories\Posts as PostsRepo;
|
use openvk\Web\Models\Repositories\Posts as PostsRepo;
|
||||||
|
use openvk\Web\Models\Entities\User;
|
||||||
use openvk\VKAPI\Handlers\Wall;
|
use openvk\VKAPI\Handlers\Wall;
|
||||||
|
|
||||||
final class Newsfeed extends VKAPIRequestHandler
|
final class Newsfeed extends VKAPIRequestHandler
|
||||||
|
@ -26,7 +27,7 @@ final class Newsfeed extends VKAPIRequestHandler
|
||||||
->select("id")
|
->select("id")
|
||||||
->where("wall IN (?)", $ids)
|
->where("wall IN (?)", $ids)
|
||||||
->where("deleted", 0)
|
->where("deleted", 0)
|
||||||
->where("id < (?)", empty($start_from) ? time()+1 : $start_from)
|
->where("id < (?)", empty($start_from) ? PHP_INT_MAX : $start_from)
|
||||||
->order("created DESC");
|
->order("created DESC");
|
||||||
|
|
||||||
$rposts = [];
|
$rposts = [];
|
||||||
|
@ -35,6 +36,32 @@ final class Newsfeed extends VKAPIRequestHandler
|
||||||
|
|
||||||
$response = (new Wall)->getById(implode(',', $rposts), $extended, $fields, $this->getUser());
|
$response = (new Wall)->getById(implode(',', $rposts), $extended, $fields, $this->getUser());
|
||||||
$response->next_from = end(end($posts->page((int) ($offset + 1), $count))); // ну и костыли пиздец конечно)
|
$response->next_from = end(end($posts->page((int) ($offset + 1), $count))); // ну и костыли пиздец конечно)
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getGlobal(string $fields = "", int $start_from = 0, int $offset = 0, int $count = 30, int $extended = 0)
|
||||||
|
{
|
||||||
|
$this->requireUser();
|
||||||
|
|
||||||
|
$queryBase = "FROM `posts` LEFT JOIN `groups` ON GREATEST(`posts`.`wall`, 0) = 0 AND `groups`.`id` = ABS(`posts`.`wall`) WHERE (`groups`.`hide_from_global_feed` = 0 OR `groups`.`name` IS NULL) AND `posts`.`deleted` = 0";
|
||||||
|
|
||||||
|
if($this->getUser()->getNsfwTolerance() === User::NSFW_INTOLERANT)
|
||||||
|
$queryBase .= " AND `nsfw` = 0";
|
||||||
|
|
||||||
|
$start_from = empty($start_from) ? PHP_INT_MAX : $start_from;
|
||||||
|
$posts = DatabaseConnection::i()->getConnection()->query("SELECT `posts`.`id` " . $queryBase . " AND `posts`.`id` < " . $start_from . " ORDER BY `created` DESC LIMIT " . $count . " OFFSET " . $offset);
|
||||||
|
|
||||||
|
$rposts = [];
|
||||||
|
$ids = [];
|
||||||
|
foreach($posts as $post) {
|
||||||
|
$rposts[] = (new PostsRepo)->get($post->id)->getPrettyId();
|
||||||
|
$ids[] = $post->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = (new Wall)->getById(implode(',', $rposts), $extended, $fields, $this->getUser());
|
||||||
|
$response->next_from = end($ids);
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
105
VKAPI/Handlers/Polls.php
Executable file
105
VKAPI/Handlers/Polls.php
Executable file
|
@ -0,0 +1,105 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\VKAPI\Handlers;
|
||||||
|
use openvk\Web\Models\Entities\User;
|
||||||
|
use openvk\Web\Models\Repositories\Users as UsersRepo;
|
||||||
|
use openvk\Web\Models\Entities\Poll;
|
||||||
|
use openvk\Web\Models\Exceptions\AlreadyVotedException;
|
||||||
|
use openvk\Web\Models\Exceptions\InvalidOptionException;
|
||||||
|
use openvk\Web\Models\Exceptions\PollLockedException;
|
||||||
|
use openvk\Web\Models\Repositories\Polls as PollsRepo;
|
||||||
|
|
||||||
|
final class Polls extends VKAPIRequestHandler
|
||||||
|
{
|
||||||
|
function getById(int $poll_id, bool $extended = false, string $fields = "sex,screen_name,photo_50,photo_100,online_info,online")
|
||||||
|
{
|
||||||
|
$poll = (new PollsRepo)->get($poll_id);
|
||||||
|
|
||||||
|
if (!$poll)
|
||||||
|
$this->fail(100, "One of the parameters specified was missing or invalid: poll_id is incorrect");
|
||||||
|
|
||||||
|
$users = array();
|
||||||
|
$answers = array();
|
||||||
|
foreach($poll->getResults()->options as $answer) {
|
||||||
|
$answers[] = (object)[
|
||||||
|
"id" => $answer->id,
|
||||||
|
"rate" => $answer->pct,
|
||||||
|
"text" => $answer->name,
|
||||||
|
"votes" => $answer->votes
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$userVote = array();
|
||||||
|
foreach($poll->getUserVote($this->getUser()) as $vote)
|
||||||
|
$userVote[] = $vote[0];
|
||||||
|
|
||||||
|
$response = [
|
||||||
|
"multiple" => $poll->isMultipleChoice(),
|
||||||
|
"end_date" => $poll->endsAt() == NULL ? 0 : $poll->endsAt()->timestamp(),
|
||||||
|
"closed" => $poll->hasEnded(),
|
||||||
|
"is_board" => false,
|
||||||
|
"can_edit" => false,
|
||||||
|
"can_vote" => $poll->canVote($this->getUser()),
|
||||||
|
"can_report" => false,
|
||||||
|
"can_share" => true,
|
||||||
|
"created" => 0,
|
||||||
|
"id" => $poll->getId(),
|
||||||
|
"owner_id" => $poll->getOwner()->getId(),
|
||||||
|
"question" => $poll->getTitle(),
|
||||||
|
"votes" => $poll->getVoterCount(),
|
||||||
|
"disable_unvote" => $poll->isRevotable(),
|
||||||
|
"anonymous" => $poll->isAnonymous(),
|
||||||
|
"answer_ids" => $userVote,
|
||||||
|
"answers" => $answers,
|
||||||
|
"author_id" => $poll->getOwner()->getId(),
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($extended) {
|
||||||
|
$response["profiles"] = (new Users)->get(strval($poll->getOwner()->getId()), $fields, 0, 1);
|
||||||
|
/* Currently there is only one person that can be shown trough "Extended" param.
|
||||||
|
* As "friends" param will be implemented, "profiles" will show more users
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
return (object) $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addVote(int $poll_id, string $answers_ids)
|
||||||
|
{
|
||||||
|
$this->requireUser();
|
||||||
|
|
||||||
|
$poll = (new PollsRepo)->get($poll_id);
|
||||||
|
|
||||||
|
if(!$poll)
|
||||||
|
$this->fail(251, "Invalid poll id");
|
||||||
|
|
||||||
|
try {
|
||||||
|
$poll->vote($this->getUser(), explode(",", $answers_ids));
|
||||||
|
return 0;
|
||||||
|
} catch(AlreadyVotedException $ex) {
|
||||||
|
return 0;
|
||||||
|
} catch(PollLockedException $ex) {
|
||||||
|
return 0;
|
||||||
|
} catch(InvalidOptionException $ex) {
|
||||||
|
$this->fail(8, "бдсм вибратор купить в киеве");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteVote(int $poll_id)
|
||||||
|
{
|
||||||
|
$this->requireUser();
|
||||||
|
|
||||||
|
$poll = (new PollsRepo)->get($poll_id);
|
||||||
|
|
||||||
|
if(!$poll)
|
||||||
|
$this->fail(251, "Invalid poll id");
|
||||||
|
|
||||||
|
try {
|
||||||
|
$poll->revokeVote($this->getUser());
|
||||||
|
return 0;
|
||||||
|
} catch(PollLockedException $ex) {
|
||||||
|
$this->fail(15, "Access denied: Poll is locked or isn't revotable");
|
||||||
|
} catch(InvalidOptionException $ex) {
|
||||||
|
$this->fail(8, "how.to. ook.bacon.in.microwova.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,10 +21,17 @@ final class Wall extends VKAPIRequestHandler
|
||||||
$groups = [];
|
$groups = [];
|
||||||
$cnt = $posts->getPostCountOnUserWall($owner_id);
|
$cnt = $posts->getPostCountOnUserWall($owner_id);
|
||||||
|
|
||||||
|
if ($owner_id > 0)
|
||||||
$wallOnwer = (new UsersRepo)->get($owner_id);
|
$wallOnwer = (new UsersRepo)->get($owner_id);
|
||||||
|
else
|
||||||
|
$wallOnwer = (new ClubsRepo)->get($owner_id * -1);
|
||||||
|
|
||||||
if(!$wallOnwer || $wallOnwer->isDeleted() || $wallOnwer->isDeleted())
|
if ($owner_id > 0)
|
||||||
|
if(!$wallOnwer || $wallOnwer->isDeleted())
|
||||||
$this->fail(18, "User was deleted or banned");
|
$this->fail(18, "User was deleted or banned");
|
||||||
|
else
|
||||||
|
if(!$wallOnwer)
|
||||||
|
$this->fail(15, "Access denied: wall is disabled"); // Don't search for logic here pls
|
||||||
|
|
||||||
foreach($posts->getPostsFromUsersWall($owner_id, 1, $count, $offset) as $post) {
|
foreach($posts->getPostsFromUsersWall($owner_id, 1, $count, $offset) as $post) {
|
||||||
$from_id = get_class($post->getOwner()) == "openvk\Web\Models\Entities\Club" ? $post->getOwner()->getId() * (-1) : $post->getOwner()->getId();
|
$from_id = get_class($post->getOwner()) == "openvk\Web\Models\Entities\Club" ? $post->getOwner()->getId() * (-1) : $post->getOwner()->getId();
|
||||||
|
@ -37,12 +44,14 @@ final class Wall extends VKAPIRequestHandler
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
$attachments[] = $this->getApiPhoto($attachment);
|
$attachments[] = $this->getApiPhoto($attachment);
|
||||||
|
} else if($attachment instanceof \openvk\Web\Models\Entities\Poll) {
|
||||||
|
$attachments[] = $this->getApiPoll($attachment, $this->getUser());
|
||||||
} else if ($attachment instanceof \openvk\Web\Models\Entities\Post) {
|
} else if ($attachment instanceof \openvk\Web\Models\Entities\Post) {
|
||||||
$repostAttachments = [];
|
$repostAttachments = [];
|
||||||
|
|
||||||
foreach($attachment->getChildren() as $repostAttachment) {
|
foreach($attachment->getChildren() as $repostAttachment) {
|
||||||
if($repostAttachment instanceof \openvk\Web\Models\Entities\Photo) {
|
if($repostAttachment instanceof \openvk\Web\Models\Entities\Photo) {
|
||||||
if($attachment->isDeleted())
|
if($repostAttachment->isDeleted())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
$repostAttachments[] = $this->getApiPhoto($repostAttachment);
|
$repostAttachments[] = $this->getApiPhoto($repostAttachment);
|
||||||
|
@ -50,6 +59,11 @@ final class Wall extends VKAPIRequestHandler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($attachment->isPostedOnBehalfOfGroup())
|
||||||
|
$groups[] = $attachment->getOwner()->getId();
|
||||||
|
else
|
||||||
|
$profiles[] = $attachment->getOwner()->getId();
|
||||||
|
|
||||||
$repost[] = [
|
$repost[] = [
|
||||||
"id" => $attachment->getVirtualId(),
|
"id" => $attachment->getVirtualId(),
|
||||||
"owner_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(),
|
"owner_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(),
|
||||||
|
@ -178,6 +192,8 @@ final class Wall extends VKAPIRequestHandler
|
||||||
foreach($post->getChildren() as $attachment) {
|
foreach($post->getChildren() as $attachment) {
|
||||||
if($attachment instanceof \openvk\Web\Models\Entities\Photo) {
|
if($attachment instanceof \openvk\Web\Models\Entities\Photo) {
|
||||||
$attachments[] = $this->getApiPhoto($attachment);
|
$attachments[] = $this->getApiPhoto($attachment);
|
||||||
|
} else if($attachment instanceof \openvk\Web\Models\Entities\Poll) {
|
||||||
|
$attachments[] = $this->getApiPoll($attachment, $user);
|
||||||
} else if ($attachment instanceof \openvk\Web\Models\Entities\Post) {
|
} else if ($attachment instanceof \openvk\Web\Models\Entities\Post) {
|
||||||
$repostAttachments = [];
|
$repostAttachments = [];
|
||||||
|
|
||||||
|
@ -191,6 +207,11 @@ final class Wall extends VKAPIRequestHandler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($attachment->isPostedOnBehalfOfGroup())
|
||||||
|
$groups[] = $attachment->getOwner()->getId();
|
||||||
|
else
|
||||||
|
$profiles[] = $attachment->getOwner()->getId();
|
||||||
|
|
||||||
$repost[] = [
|
$repost[] = [
|
||||||
"id" => $attachment->getVirtualId(),
|
"id" => $attachment->getVirtualId(),
|
||||||
"owner_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(),
|
"owner_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(),
|
||||||
|
@ -420,9 +441,14 @@ final class Wall extends VKAPIRequestHandler
|
||||||
$profiles = [];
|
$profiles = [];
|
||||||
|
|
||||||
foreach($comments as $comment) {
|
foreach($comments as $comment) {
|
||||||
|
$owner = $comment->getOwner();
|
||||||
|
$oid = $owner->getId();
|
||||||
|
if($owner instanceof Club)
|
||||||
|
$oid *= -1;
|
||||||
|
|
||||||
$item = [
|
$item = [
|
||||||
"id" => $comment->getId(),
|
"id" => $comment->getId(),
|
||||||
"from_id" => $comment->getOwner()->getId(),
|
"from_id" => $oid,
|
||||||
"date" => $comment->getPublicationTime()->timestamp(),
|
"date" => $comment->getPublicationTime()->timestamp(),
|
||||||
"text" => $comment->getText(false),
|
"text" => $comment->getText(false),
|
||||||
"post_id" => $post->getVirtualId(),
|
"post_id" => $post->getVirtualId(),
|
||||||
|
@ -576,4 +602,44 @@ final class Wall extends VKAPIRequestHandler
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getApiPoll($attachment, $user) {
|
||||||
|
$answers = array();
|
||||||
|
foreach($attachment->getResults()->options as $answer) {
|
||||||
|
$answers[] = (object)[
|
||||||
|
"id" => $answer->id,
|
||||||
|
"rate" => $answer->pct,
|
||||||
|
"text" => $answer->name,
|
||||||
|
"votes" => $answer->votes
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$userVote = array();
|
||||||
|
foreach($attachment->getUserVote($user) as $vote)
|
||||||
|
$userVote[] = $vote[0];
|
||||||
|
|
||||||
|
return [
|
||||||
|
"type" => "poll",
|
||||||
|
"poll" => [
|
||||||
|
"multiple" => $attachment->isMultipleChoice(),
|
||||||
|
"end_date" => $attachment->endsAt() == NULL ? 0 : $attachment->endsAt()->timestamp(),
|
||||||
|
"closed" => $attachment->hasEnded(),
|
||||||
|
"is_board" => false,
|
||||||
|
"can_edit" => false,
|
||||||
|
"can_vote" => $attachment->canVote($user),
|
||||||
|
"can_report" => false,
|
||||||
|
"can_share" => true,
|
||||||
|
"created" => 0,
|
||||||
|
"id" => $attachment->getId(),
|
||||||
|
"owner_id" => $attachment->getOwner()->getId(),
|
||||||
|
"question" => $attachment->getTitle(),
|
||||||
|
"votes" => $attachment->getVoterCount(),
|
||||||
|
"disable_unvote" => $attachment->isRevotable(),
|
||||||
|
"anonymous" => $attachment->isAnonymous(),
|
||||||
|
"answer_ids" => $userVote,
|
||||||
|
"answers" => $answers,
|
||||||
|
"author_id" => $attachment->getOwner()->getId(),
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
# VK API Compatability layer for OpenVK
|
# VK API Compatability layer for OpenVK
|
||||||
|
|
||||||
This directory contains VK api handlers, structures and relared
|
This directory contains VK API handlers, structures and relared
|
||||||
exceptions. It is still a work-in-progress functionality.
|
exceptions. It is still a work-in-progress functionality.
|
||||||
**Note**: requests to api are routed through
|
**Note**: requests to API are routed through
|
||||||
openvk.Web.Presenters.VKAPIPresenter, this dir contains only handlers.
|
openvk.Web.Presenters.VKAPIPresenter, this dir contains only handlers.
|
||||||
|
|
||||||
|
[Documentation for API clients](https://docs.openvk.su/openvk_engine/api/description/)
|
||||||
|
|
||||||
## Implementing API methods
|
## Implementing API methods
|
||||||
|
|
||||||
VK API methods have names like this: `example.test`. To implement a
|
VK API methods have names like this: `example.test`. To implement a
|
||||||
|
|
|
@ -27,14 +27,23 @@ class NewMessageEvent implements ILPEmitable
|
||||||
if($peer === $userId)
|
if($peer === $userId)
|
||||||
$peer = $msg->getRecipient()->getId();
|
$peer = $msg->getRecipient()->getId();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Source:
|
||||||
|
* https://github.com/danyadev/longpoll-doc
|
||||||
|
*/
|
||||||
|
|
||||||
return [
|
return [
|
||||||
4, # event type
|
4, # event type
|
||||||
|
$msg->getId(), # messageId
|
||||||
256, # checked for spam flag
|
256, # checked for spam flag
|
||||||
$peer, # TODO calculate peer correctly
|
$peer, # TODO calculate peer correctly
|
||||||
$msg->getSendTime()->timestamp(), # creation time in unix
|
$msg->getSendTime()->timestamp(), # creation time in unix
|
||||||
$msg->getText(), # text (formatted)
|
$msg->getText(), # text (formatted)
|
||||||
|
[], # empty additional info
|
||||||
[], # empty attachments
|
[], # empty attachments
|
||||||
$msg->getId() << 2, # id as random_id
|
$msg->getId() << 2, # id as random_id
|
||||||
|
$peer, # conversation id
|
||||||
|
0 # not edited yet
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
34
Web/Models/Entities/Alias.php
Normal file
34
Web/Models/Entities/Alias.php
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Models\Entities;
|
||||||
|
|
||||||
|
use openvk\Web\Models\RowModel;
|
||||||
|
use openvk\Web\Models\Entities\{User, Club};
|
||||||
|
use openvk\Web\Models\Repositories\{Users, Clubs};
|
||||||
|
|
||||||
|
class Alias extends RowModel
|
||||||
|
{
|
||||||
|
protected $tableName = "aliases";
|
||||||
|
|
||||||
|
function getOwnerId(): int
|
||||||
|
{
|
||||||
|
return $this->getRecord()->owner_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getType(): string
|
||||||
|
{
|
||||||
|
if ($this->getOwnerId() < 0)
|
||||||
|
return "club";
|
||||||
|
|
||||||
|
return "user";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUser(): ?User
|
||||||
|
{
|
||||||
|
return (new Users)->get($this->getOwnerId());
|
||||||
|
}
|
||||||
|
|
||||||
|
function getClub(): ?Club
|
||||||
|
{
|
||||||
|
return (new Clubs)->get($this->getOwnerId() * -1);
|
||||||
|
}
|
||||||
|
}
|
|
@ -360,5 +360,6 @@ class Club extends RowModel
|
||||||
return $this->getRecord()->alert;
|
return $this->getRecord()->alert;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use Traits\TBackDrops;
|
||||||
use Traits\TSubscribable;
|
use Traits\TSubscribable;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,6 @@ final class CommentNotification extends Notification
|
||||||
|
|
||||||
function __construct(User $recipient, Comment $comment, $postable, User $commenter)
|
function __construct(User $recipient, Comment $comment, $postable, User $commenter)
|
||||||
{
|
{
|
||||||
parent::__construct($recipient, $postable, $commenter, time(), ovk_proc_strtr($comment->getText(), 10));
|
parent::__construct($recipient, $postable, $commenter, time(), ovk_proc_strtr(strip_tags($comment->getText()), 400));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Models\Entities\Notifications;
|
namespace openvk\Web\Models\Entities\Notifications;
|
||||||
|
use openvk\Web\Models\Entities\Postable;
|
||||||
use openvk\Web\Models\Entities\User;
|
use openvk\Web\Models\Entities\User;
|
||||||
|
|
||||||
final class MentionNotification extends Notification
|
final class MentionNotification extends Notification
|
||||||
{
|
{
|
||||||
protected $actionCode = 4;
|
protected $actionCode = 4;
|
||||||
|
|
||||||
function __construct(User $recipient, User $target, User $mentioner)
|
function __construct(User $recipient, Postable $discussionHost, $mentioner, string $quote = "")
|
||||||
{
|
{
|
||||||
parent::__construct($recipient, $target, $mentioner, time(), "");
|
parent::__construct($recipient, $mentioner, $discussionHost, time(), $quote);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,11 @@ class Notification
|
||||||
return (int) json_decode(file_get_contents(__DIR__ . "/../../../../data/modelCodes.json"), true)[get_class($model)];
|
return (int) json_decode(file_get_contents(__DIR__ . "/../../../../data/modelCodes.json"), true)[get_class($model)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function reverseModelOrder(): bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function getActionCode(): int
|
function getActionCode(): int
|
||||||
{
|
{
|
||||||
return $this->actionCode;
|
return $this->actionCode;
|
||||||
|
|
295
Web/Models/Entities/Poll.php
Normal file
295
Web/Models/Entities/Poll.php
Normal file
|
@ -0,0 +1,295 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Models\Entities;
|
||||||
|
use openvk\Web\Models\Exceptions\TooMuchOptionsException;
|
||||||
|
use openvk\Web\Util\DateTime;
|
||||||
|
use \UnexpectedValueException;
|
||||||
|
use Nette\InvalidStateException;
|
||||||
|
use openvk\Web\Models\Repositories\Users;
|
||||||
|
use Chandler\Database\DatabaseConnection;
|
||||||
|
use openvk\Web\Models\Exceptions\PollLockedException;
|
||||||
|
use openvk\Web\Models\Exceptions\AlreadyVotedException;
|
||||||
|
use openvk\Web\Models\Exceptions\InvalidOptionException;
|
||||||
|
|
||||||
|
class Poll extends Attachable
|
||||||
|
{
|
||||||
|
protected $tableName = "polls";
|
||||||
|
|
||||||
|
private $choicesToPersist = [];
|
||||||
|
|
||||||
|
function getTitle(): string
|
||||||
|
{
|
||||||
|
return $this->getRecord()->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMetaDescription(): string
|
||||||
|
{
|
||||||
|
$props = [];
|
||||||
|
$props[] = tr($this->isAnonymous() ? "poll_anon" : "poll_public");
|
||||||
|
if($this->isMultipleChoice()) $props[] = tr("poll_multi");
|
||||||
|
if(!$this->isRevotable()) $props[] = tr("poll_lock");
|
||||||
|
if(!is_null($this->endsAt())) $props[] = tr("poll_until", $this->endsAt());
|
||||||
|
|
||||||
|
return implode(" • ", $props);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOwner(): User
|
||||||
|
{
|
||||||
|
return (new Users)->get($this->getRecord()->owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOptions(): array
|
||||||
|
{
|
||||||
|
$options = $this->getRecord()->related("poll_options.poll");
|
||||||
|
$res = [];
|
||||||
|
foreach($options as $opt)
|
||||||
|
$res[$opt->id] = $opt->name;
|
||||||
|
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUserVote(User $user): ?array
|
||||||
|
{
|
||||||
|
$ctx = DatabaseConnection::i()->getContext();
|
||||||
|
$votedOpts = $ctx->table("poll_votes")
|
||||||
|
->where(["user" => $user->getId(), "poll" => $this->getId()]);
|
||||||
|
|
||||||
|
if($votedOpts->count() == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
$res = [];
|
||||||
|
foreach($votedOpts as $votedOpt) {
|
||||||
|
$option = $ctx->table("poll_options")->get($votedOpt->option);
|
||||||
|
$res[] = [$option->id, $option->name];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getVoters(int $optionId, int $page = 1, ?int $perPage = NULL): array
|
||||||
|
{
|
||||||
|
$res = [];
|
||||||
|
$ctx = DatabaseConnection::i()->getContext();
|
||||||
|
$perPage = $perPage ?? OPENVK_DEFAULT_PER_PAGE;
|
||||||
|
$voters = $ctx->table("poll_votes")->where(["poll" => $this->getId(), "option" => $optionId]);
|
||||||
|
foreach($voters->page($page, $perPage) as $vote)
|
||||||
|
$res[] = (new Users)->get($vote->user);
|
||||||
|
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getVoterCount(?int $optionId = NULL): int
|
||||||
|
{
|
||||||
|
$votes = DatabaseConnection::i()->getContext()->table("poll_votes");
|
||||||
|
if(!$optionId)
|
||||||
|
return $votes->select("COUNT(DISTINCT user) AS c")->where("poll", $this->getId())->fetch()->c;
|
||||||
|
|
||||||
|
return $votes->where(["poll" => $this->getId(), "option" => $optionId])->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getResults(?User $user = NULL): object
|
||||||
|
{
|
||||||
|
$ctx = DatabaseConnection::i()->getContext();
|
||||||
|
$voted = NULL;
|
||||||
|
if(!is_null($user))
|
||||||
|
$voted = $this->getUserVote($user);
|
||||||
|
|
||||||
|
$result = (object) [];
|
||||||
|
$result->totalVotes = $this->getVoterCount();
|
||||||
|
|
||||||
|
$unsOptions = [];
|
||||||
|
foreach($this->getOptions() as $id => $title) {
|
||||||
|
$option = (object) [];
|
||||||
|
$option->id = $id;
|
||||||
|
$option->name = $title;
|
||||||
|
|
||||||
|
$option->votes = $this->getVoterCount($id);
|
||||||
|
$option->pct = $result->totalVotes == 0 ? 0 : min(100, floor(($option->votes / $result->totalVotes) * 100));
|
||||||
|
$option->voters = $this->getVoters($id, 1, 10);
|
||||||
|
if(!$user || !$voted)
|
||||||
|
$option->voted = NULL;
|
||||||
|
else
|
||||||
|
$option->voted = in_array([$id, $title], $voted);
|
||||||
|
|
||||||
|
$unsOptions[$id] = $option;
|
||||||
|
}
|
||||||
|
|
||||||
|
$optionsC = sizeof($unsOptions);
|
||||||
|
$sOptions = $unsOptions;
|
||||||
|
usort($sOptions, function($a, $b) { return $a->votes <=> $b->votes; });
|
||||||
|
for($i = 0; $i < $optionsC; $i++)
|
||||||
|
$unsOptions[$id]->rate = $optionsC - $i - 1;
|
||||||
|
|
||||||
|
$result->options = array_values($unsOptions);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isAnonymous(): bool
|
||||||
|
{
|
||||||
|
return (bool) $this->getRecord()->is_anonymous;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isMultipleChoice(): bool
|
||||||
|
{
|
||||||
|
return (bool) $this->getRecord()->allows_multiple;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isRevotable(): bool
|
||||||
|
{
|
||||||
|
return (bool) $this->getRecord()->can_revote;
|
||||||
|
}
|
||||||
|
|
||||||
|
function endsAt(): ?DateTime
|
||||||
|
{
|
||||||
|
if(!$this->getRecord()->until)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return new DateTime($this->getRecord()->until);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasEnded(): bool
|
||||||
|
{
|
||||||
|
if($this->getRecord()->ended)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if(!is_null($this->getRecord()->until))
|
||||||
|
return time() >= $this->getRecord()->until;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasVoted(User $user): bool
|
||||||
|
{
|
||||||
|
return !is_null($this->getUserVote($user));
|
||||||
|
}
|
||||||
|
|
||||||
|
function canVote(User $user): bool
|
||||||
|
{
|
||||||
|
return !$this->hasEnded() && !$this->hasVoted($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
function vote(User $user, array $optionIds): void
|
||||||
|
{
|
||||||
|
if($this->hasEnded())
|
||||||
|
throw new PollLockedException;
|
||||||
|
|
||||||
|
if($this->hasVoted($user))
|
||||||
|
throw new AlreadyVotedException;
|
||||||
|
|
||||||
|
$optionIds = array_map(function($x) { return (int) $x; }, array_unique($optionIds));
|
||||||
|
$validOpts = array_keys($this->getOptions());
|
||||||
|
if(empty($optionIds) || (sizeof($optionIds) > 1 && !$this->isMultipleChoice()))
|
||||||
|
throw new UnexpectedValueException;
|
||||||
|
|
||||||
|
if(sizeof(array_diff($optionIds, $validOpts)) > 0)
|
||||||
|
throw new InvalidOptionException;
|
||||||
|
|
||||||
|
foreach($optionIds as $opt) {
|
||||||
|
DatabaseConnection::i()->getContext()->table("poll_votes")->insert([
|
||||||
|
"user" => $user->getId(),
|
||||||
|
"poll" => $this->getId(),
|
||||||
|
"option" => $opt,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function revokeVote(User $user): void
|
||||||
|
{
|
||||||
|
if(!$this->isRevotable())
|
||||||
|
throw new PollLockedException;
|
||||||
|
|
||||||
|
$this->getRecord()->related("poll_votes.poll")
|
||||||
|
->where("user", $user->getId())->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setOwner(User $owner): void
|
||||||
|
{
|
||||||
|
$this->stateChanges("owner", $owner->getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
function setEndDate(int $timestamp): void
|
||||||
|
{
|
||||||
|
if(!is_null($this->getRecord()))
|
||||||
|
throw new PollLockedException;
|
||||||
|
|
||||||
|
$this->stateChanges("until", $timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setEnded(): void
|
||||||
|
{
|
||||||
|
$this->stateChanges("ended", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setOptions(array $options): void
|
||||||
|
{
|
||||||
|
if(!is_null($this->getRecord()))
|
||||||
|
throw new PollLockedException;
|
||||||
|
|
||||||
|
if(sizeof($options) > ovkGetQuirk("polls.max-opts"))
|
||||||
|
throw new TooMuchOptionsException;
|
||||||
|
|
||||||
|
$this->choicesToPersist = $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setRevotability(bool $canReVote): void
|
||||||
|
{
|
||||||
|
if(!is_null($this->getRecord()))
|
||||||
|
throw new PollLockedException;
|
||||||
|
|
||||||
|
$this->stateChanges("can_revote", $canReVote);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setAnonymity(bool $anonymous): void
|
||||||
|
{
|
||||||
|
$this->stateChanges("is_anonymous", $anonymous);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setMultipleChoice(bool $mc): void
|
||||||
|
{
|
||||||
|
$this->stateChanges("allows_multiple", $mc);
|
||||||
|
}
|
||||||
|
|
||||||
|
function importXML(User $owner, string $xml): void
|
||||||
|
{
|
||||||
|
$xml = simplexml_load_string($xml);
|
||||||
|
$this->setOwner($owner);
|
||||||
|
$this->setTitle($xml["title"] ?? "Untitled");
|
||||||
|
$this->setMultipleChoice(($xml["multiple"] ?? "no") == "yes");
|
||||||
|
$this->setAnonymity(($xml["anonymous"] ?? "no") == "yes");
|
||||||
|
$this->setRevotability(($xml["locked"] ?? "no") == "no");
|
||||||
|
if(ctype_digit((string) ($xml["duration"] ?? "")))
|
||||||
|
$this->setEndDate(time() + ((86400 * (int) $xml["duration"])));
|
||||||
|
|
||||||
|
$options = [];
|
||||||
|
foreach($xml->options->option as $opt)
|
||||||
|
$options[] = (string) $opt;
|
||||||
|
|
||||||
|
if(empty($options))
|
||||||
|
throw new UnexpectedValueException;
|
||||||
|
|
||||||
|
$this->setOptions($options);
|
||||||
|
}
|
||||||
|
|
||||||
|
static function import(User $owner, string $xml): Poll
|
||||||
|
{
|
||||||
|
$poll = new Poll;
|
||||||
|
$poll->importXML($owner, $xml);
|
||||||
|
$poll->save();
|
||||||
|
|
||||||
|
return $poll;
|
||||||
|
}
|
||||||
|
|
||||||
|
function save(): void
|
||||||
|
{
|
||||||
|
if(empty($this->choicesToPersist))
|
||||||
|
throw new InvalidStateException;
|
||||||
|
|
||||||
|
parent::save();
|
||||||
|
foreach($this->choicesToPersist as $option) {
|
||||||
|
DatabaseConnection::i()->getContext()->table("poll_options")->insert([
|
||||||
|
"poll" => $this->getId(),
|
||||||
|
"name" => $option,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Models\Entities;
|
namespace openvk\Web\Models\Entities;
|
||||||
use Chandler\Database\DatabaseConnection as DB;
|
use Chandler\Database\DatabaseConnection as DB;
|
||||||
use openvk\Web\Models\Repositories\Clubs;
|
use openvk\Web\Models\Repositories\{Clubs, Users};
|
||||||
use openvk\Web\Models\RowModel;
|
use openvk\Web\Models\RowModel;
|
||||||
use openvk\Web\Models\Entities\Notifications\LikeNotification;
|
use openvk\Web\Models\Entities\Notifications\LikeNotification;
|
||||||
|
|
||||||
|
@ -56,6 +56,15 @@ class Post extends Postable
|
||||||
return $this->getRecord()->wall;
|
return $this->getRecord()->wall;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getWallOwner()
|
||||||
|
{
|
||||||
|
$w = $this->getRecord()->wall;
|
||||||
|
if($w < 0)
|
||||||
|
return (new Clubs)->get(abs($w));
|
||||||
|
|
||||||
|
return (new Users)->get($w);
|
||||||
|
}
|
||||||
|
|
||||||
function getRepostCount(): int
|
function getRepostCount(): int
|
||||||
{
|
{
|
||||||
return sizeof(
|
return sizeof(
|
||||||
|
@ -87,7 +96,7 @@ class Post extends Postable
|
||||||
|
|
||||||
function isDeactivationMessage(): bool
|
function isDeactivationMessage(): bool
|
||||||
{
|
{
|
||||||
return ($this->getRecord()->flags & 0b00100000) > 0;
|
return (($this->getRecord()->flags & 0b00100000) > 0) && ($this->getRecord()->owner > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isExplicit(): bool
|
function isExplicit(): bool
|
||||||
|
|
39
Web/Models/Entities/SupportAgent.php
Normal file
39
Web/Models/Entities/SupportAgent.php
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Models\Entities;
|
||||||
|
use openvk\Web\Models\Repositories\Users;
|
||||||
|
use openvk\Web\Models\RowModel;
|
||||||
|
|
||||||
|
class SupportAgent extends RowModel
|
||||||
|
{
|
||||||
|
protected $tableName = "support_names";
|
||||||
|
|
||||||
|
function getAgentId(): int
|
||||||
|
{
|
||||||
|
return $this->getRecord()->agent;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getName(): ?string
|
||||||
|
{
|
||||||
|
return $this->getRecord()->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCanonicalName(): string
|
||||||
|
{
|
||||||
|
return $this->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAvatarURL(): ?string
|
||||||
|
{
|
||||||
|
return $this->getRecord()->icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isShowNumber(): int
|
||||||
|
{
|
||||||
|
return $this->getRecord()->numerate;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRealName(): string
|
||||||
|
{
|
||||||
|
return (new Users)->get($this->getAgentId())->getCanonicalName();
|
||||||
|
}
|
||||||
|
}
|
|
@ -42,7 +42,7 @@ class TicketComment extends RowModel
|
||||||
|
|
||||||
$alias = $this->getSupportAlias();
|
$alias = $this->getSupportAlias();
|
||||||
if(!$alias)
|
if(!$alias)
|
||||||
return OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["supportName"] . " №" . $this->getAgentNumber();
|
return tr("helpdesk_agent") . " #" . $this->getAgentNumber();
|
||||||
|
|
||||||
$name = $alias->getName();
|
$name = $alias->getName();
|
||||||
if($alias->shouldAppendNumber())
|
if($alias->shouldAppendNumber())
|
||||||
|
|
44
Web/Models/Entities/Traits/TBackDrops.php
Normal file
44
Web/Models/Entities/Traits/TBackDrops.php
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Models\Entities\Traits;
|
||||||
|
|
||||||
|
use openvk\Web\Models\Entities\Photo;
|
||||||
|
use openvk\Web\Models\Repositories\Photos;
|
||||||
|
|
||||||
|
trait TBackDrops {
|
||||||
|
function getBackDropPictureURLs(): ?array
|
||||||
|
{
|
||||||
|
$photo1 = $this->getRecord()->backdrop_1;
|
||||||
|
$photo2 = $this->getRecord()->backdrop_2;
|
||||||
|
if(is_null($photo1) && is_null($photo2))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
$photo1obj = $photo2obj = NULL;
|
||||||
|
if(!is_null($photo1))
|
||||||
|
$photo1obj = (new Photos)->get($photo1);
|
||||||
|
if(!is_null($photo2))
|
||||||
|
$photo2obj = (new Photos)->get($photo2);
|
||||||
|
|
||||||
|
if(is_null($photo1obj) && is_null($photo2obj))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return [
|
||||||
|
is_null($photo1obj) ? "" : $photo1obj->getURL(),
|
||||||
|
is_null($photo2obj) ? "" : $photo2obj->getURL(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function setBackDropPictures(?Photo $first, ?Photo $second): void
|
||||||
|
{
|
||||||
|
if(!is_null($first))
|
||||||
|
$this->stateChanges("backdrop_1", $first->getId());
|
||||||
|
|
||||||
|
if(!is_null($second))
|
||||||
|
$this->stateChanges("backdrop_2", $second->getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
function unsetBackDropPictures(): void
|
||||||
|
{
|
||||||
|
$this->stateChanges("backdrop_1", NULL);
|
||||||
|
$this->stateChanges("backdrop_2", NULL);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Models\Entities\Traits;
|
namespace openvk\Web\Models\Entities\Traits;
|
||||||
|
use openvk\Web\Models\Repositories\{Users, Clubs};
|
||||||
use Wkhooy\ObsceneCensorRus;
|
use Wkhooy\ObsceneCensorRus;
|
||||||
|
|
||||||
trait TRichText
|
trait TRichText
|
||||||
|
@ -51,6 +52,62 @@ trait TRichText
|
||||||
return preg_replace("%[\x{0300}-\x{036F}]{3,}%Xu", "<EFBFBD>", $text);
|
return preg_replace("%[\x{0300}-\x{036F}]{3,}%Xu", "<EFBFBD>", $text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveMentions(array $skipUsers = []): \Traversable
|
||||||
|
{
|
||||||
|
$contentColumn = property_exists($this, "overrideContentColumn") ? $this->overrideContentColumn : "content";
|
||||||
|
$text = $this->getRecord()->{$contentColumn};
|
||||||
|
$text = preg_replace("%@([A-Za-z0-9]++) \(((?:[\p{L&}\p{Lo} 0-9]\p{Mn}?)++)\)%Xu", "[$1|$2]", $text);
|
||||||
|
$text = preg_replace("%([\n\r\s]|^)(@([A-Za-z0-9]++))%Xu", "$1[$3|@$3]", $text);
|
||||||
|
|
||||||
|
$resolvedUsers = $skipUsers;
|
||||||
|
$resolvedClubs = [];
|
||||||
|
preg_match_all("%\[([A-Za-z0-9]++)\|((?:[\p{L&}\p{Lo} 0-9@]\p{Mn}?)++)\]%Xu", $text, $links, PREG_PATTERN_ORDER);
|
||||||
|
foreach($links[1] as $link) {
|
||||||
|
if(preg_match("%^id([0-9]++)$%", $link, $match)) {
|
||||||
|
$uid = (int) $match[1];
|
||||||
|
if(in_array($uid, $resolvedUsers))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$resolvedUsers[] = $uid;
|
||||||
|
$maybeUser = (new Users)->get($uid);
|
||||||
|
if($maybeUser)
|
||||||
|
yield $maybeUser;
|
||||||
|
} else if(preg_match("%^(?:club|public|event)([0-9]++)$%", $link, $match)) {
|
||||||
|
$cid = (int) $match[1];
|
||||||
|
if(in_array($cid, $resolvedClubs))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$resolvedClubs[] = $cid;
|
||||||
|
$maybeClub = (new Clubs)->get($cid);
|
||||||
|
if($maybeClub)
|
||||||
|
yield $maybeClub;
|
||||||
|
} else {
|
||||||
|
$maybeUser = (new Users)->getByShortURL($link);
|
||||||
|
if($maybeUser) {
|
||||||
|
$uid = $maybeUser->getId();
|
||||||
|
if(in_array($uid, $resolvedUsers))
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
$resolvedUsers[] = $uid;
|
||||||
|
|
||||||
|
yield $maybeUser;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$maybeClub = (new Clubs)->getByShortURL($link);
|
||||||
|
if($maybeClub) {
|
||||||
|
$cid = $maybeClub->getId();
|
||||||
|
if(in_array($cid, $resolvedClubs))
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
$resolvedClubs[] = $cid;
|
||||||
|
|
||||||
|
yield $maybeClub;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getText(bool $html = true): string
|
function getText(bool $html = true): string
|
||||||
{
|
{
|
||||||
$contentColumn = property_exists($this, "overrideContentColumn") ? $this->overrideContentColumn : "content";
|
$contentColumn = property_exists($this, "overrideContentColumn") ? $this->overrideContentColumn : "content";
|
||||||
|
@ -59,7 +116,6 @@ trait TRichText
|
||||||
$proc = iconv_strlen($this->getRecord()->{$contentColumn}) <= OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["postSizes"]["processingLimit"];
|
$proc = iconv_strlen($this->getRecord()->{$contentColumn}) <= OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["postSizes"]["processingLimit"];
|
||||||
if($html) {
|
if($html) {
|
||||||
if($proc) {
|
if($proc) {
|
||||||
$rel = $this->isAd() ? "sponsored" : "ugc";
|
|
||||||
$text = $this->formatLinks($text);
|
$text = $this->formatLinks($text);
|
||||||
$text = preg_replace("%@([A-Za-z0-9]++) \(((?:[\p{L&}\p{Lo} 0-9]\p{Mn}?)++)\)%Xu", "[$1|$2]", $text);
|
$text = preg_replace("%@([A-Za-z0-9]++) \(((?:[\p{L&}\p{Lo} 0-9]\p{Mn}?)++)\)%Xu", "[$1|$2]", $text);
|
||||||
$text = preg_replace("%([\n\r\s]|^)(@([A-Za-z0-9]++))%Xu", "$1[$3|@$3]", $text);
|
$text = preg_replace("%([\n\r\s]|^)(@([A-Za-z0-9]++))%Xu", "$1[$3|@$3]", $text);
|
||||||
|
|
|
@ -5,7 +5,7 @@ use openvk\Web\Themes\{Themepack, Themepacks};
|
||||||
use openvk\Web\Util\DateTime;
|
use openvk\Web\Util\DateTime;
|
||||||
use openvk\Web\Models\RowModel;
|
use openvk\Web\Models\RowModel;
|
||||||
use openvk\Web\Models\Entities\{Photo, Message, Correspondence, Gift};
|
use openvk\Web\Models\Entities\{Photo, Message, Correspondence, Gift};
|
||||||
use openvk\Web\Models\Repositories\{Users, Clubs, Albums, Gifts, Notifications};
|
use openvk\Web\Models\Repositories\{Photos, Users, Clubs, Albums, Gifts, Notifications};
|
||||||
use openvk\Web\Models\Exceptions\InvalidUserNameException;
|
use openvk\Web\Models\Exceptions\InvalidUserNameException;
|
||||||
use Nette\Database\Table\ActiveRow;
|
use Nette\Database\Table\ActiveRow;
|
||||||
use Chandler\Database\DatabaseConnection;
|
use Chandler\Database\DatabaseConnection;
|
||||||
|
@ -148,8 +148,9 @@ class User extends RowModel
|
||||||
function getFirstName(bool $pristine = false): string
|
function getFirstName(bool $pristine = false): string
|
||||||
{
|
{
|
||||||
$name = ($this->isDeleted() && !$this->isDeactivated() ? "DELETED" : mb_convert_case($this->getRecord()->first_name, MB_CASE_TITLE));
|
$name = ($this->isDeleted() && !$this->isDeactivated() ? "DELETED" : mb_convert_case($this->getRecord()->first_name, MB_CASE_TITLE));
|
||||||
if((($ts = tr("__transNames")) !== "@__transNames") && !$pristine)
|
$tsn = tr("__transNames");
|
||||||
return mb_convert_case(transliterator_transliterate($ts, $name), MB_CASE_TITLE);
|
if(( $tsn !== "@__transNames" && !empty($tsn) ) && !$pristine)
|
||||||
|
return mb_convert_case(transliterator_transliterate($tsn, $name), MB_CASE_TITLE);
|
||||||
else
|
else
|
||||||
return $name;
|
return $name;
|
||||||
}
|
}
|
||||||
|
@ -157,8 +158,9 @@ class User extends RowModel
|
||||||
function getLastName(bool $pristine = false): string
|
function getLastName(bool $pristine = false): string
|
||||||
{
|
{
|
||||||
$name = ($this->isDeleted() && !$this->isDeactivated() ? "DELETED" : mb_convert_case($this->getRecord()->last_name, MB_CASE_TITLE));
|
$name = ($this->isDeleted() && !$this->isDeactivated() ? "DELETED" : mb_convert_case($this->getRecord()->last_name, MB_CASE_TITLE));
|
||||||
if((($ts = tr("__transNames")) !== "@__transNames") && !$pristine)
|
$tsn = tr("__transNames");
|
||||||
return mb_convert_case(transliterator_transliterate($ts, $name), MB_CASE_TITLE);
|
if(( $tsn !== "@__transNames" && !empty($tsn) ) && !$pristine)
|
||||||
|
return mb_convert_case(transliterator_transliterate($tsn, $name), MB_CASE_TITLE);
|
||||||
else
|
else
|
||||||
return $name;
|
return $name;
|
||||||
}
|
}
|
||||||
|
@ -535,12 +537,15 @@ class User extends RowModel
|
||||||
return sizeof(DatabaseConnection::i()->getContext()->table("messages")->where(["recipient_id" => $this->getId(), "unread" => 1]));
|
return sizeof(DatabaseConnection::i()->getContext()->table("messages")->where(["recipient_id" => $this->getId(), "unread" => 1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getClubs(int $page = 1, bool $admin = false): \Traversable
|
function getClubs(int $page = 1, bool $admin = false, int $count = OPENVK_DEFAULT_PER_PAGE, bool $offset = false): \Traversable
|
||||||
{
|
{
|
||||||
|
if(!$offset)
|
||||||
|
$page = ($page - 1) * $count;
|
||||||
|
|
||||||
if($admin) {
|
if($admin) {
|
||||||
$id = $this->getId();
|
$id = $this->getId();
|
||||||
$query = "SELECT `id` FROM `groups` WHERE `owner` = ? UNION SELECT `club` as `id` FROM `group_coadmins` WHERE `user` = ?";
|
$query = "SELECT `id` FROM `groups` WHERE `owner` = ? UNION SELECT `club` as `id` FROM `group_coadmins` WHERE `user` = ?";
|
||||||
$query .= " LIMIT " . OPENVK_DEFAULT_PER_PAGE . " OFFSET " . ($page - 1) * OPENVK_DEFAULT_PER_PAGE;
|
$query .= " LIMIT " . $count . " OFFSET " . $page;
|
||||||
|
|
||||||
$sel = DatabaseConnection::i()->getConnection()->query($query, $id, $id);
|
$sel = DatabaseConnection::i()->getConnection()->query($query, $id, $id);
|
||||||
foreach($sel as $target) {
|
foreach($sel as $target) {
|
||||||
|
@ -550,7 +555,7 @@ class User extends RowModel
|
||||||
yield $target;
|
yield $target;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$sel = $this->getRecord()->related("subscriptions.follower")->page($page, OPENVK_DEFAULT_PER_PAGE);
|
$sel = $this->getRecord()->related("subscriptions.follower")->limit($count, $page);
|
||||||
foreach($sel->where("model", "openvk\\Web\\Models\\Entities\\Club") as $target) {
|
foreach($sel->where("model", "openvk\\Web\\Models\\Entities\\Club") as $target) {
|
||||||
$target = (new Clubs)->get($target->target);
|
$target = (new Clubs)->get($target->target);
|
||||||
if(!$target) continue;
|
if(!$target) continue;
|
||||||
|
@ -908,6 +913,10 @@ class User extends RowModel
|
||||||
$pClub = DatabaseConnection::i()->getContext()->table("groups")->where("shortcode", $code)->fetch();
|
$pClub = DatabaseConnection::i()->getContext()->table("groups")->where("shortcode", $code)->fetch();
|
||||||
if(!is_null($pClub))
|
if(!is_null($pClub))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
$pAlias = DatabaseConnection::i()->getContext()->table("aliases")->where("shortcode", $code)->fetch();
|
||||||
|
if(!is_null($pAlias))
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->stateChanges("shortcode", $code);
|
$this->stateChanges("shortcode", $code);
|
||||||
|
@ -1035,5 +1044,6 @@ class User extends RowModel
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use Traits\TBackDrops;
|
||||||
use Traits\TSubscribable;
|
use Traits\TSubscribable;
|
||||||
}
|
}
|
||||||
|
|
7
Web/Models/Exceptions/AlreadyVotedException.php
Normal file
7
Web/Models/Exceptions/AlreadyVotedException.php
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Models\Exceptions;
|
||||||
|
|
||||||
|
final class AlreadyVotedException extends \RuntimeException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
7
Web/Models/Exceptions/InvalidOptionException.php
Normal file
7
Web/Models/Exceptions/InvalidOptionException.php
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Models\Exceptions;
|
||||||
|
|
||||||
|
final class InvalidOptionException extends \UnexpectedValueException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
8
Web/Models/Exceptions/PollLockedException.php
Normal file
8
Web/Models/Exceptions/PollLockedException.php
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Models\Exceptions;
|
||||||
|
use Nette\InvalidStateException;
|
||||||
|
|
||||||
|
final class PollLockedException extends InvalidStateException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
7
Web/Models/Exceptions/TooMuchOptionsException.php
Normal file
7
Web/Models/Exceptions/TooMuchOptionsException.php
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Models\Exceptions;
|
||||||
|
|
||||||
|
final class TooMuchOptionsException extends \UnexpectedValueException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
35
Web/Models/Repositories/Aliases.php
Normal file
35
Web/Models/Repositories/Aliases.php
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Models\Repositories;
|
||||||
|
|
||||||
|
use openvk\Web\Models\Entities\Alias;
|
||||||
|
use Nette\Database\Table\ActiveRow;
|
||||||
|
use Chandler\Database\DatabaseConnection as DB;
|
||||||
|
use openvk\Web\Models\Entities\{Club, User};
|
||||||
|
use openvk\Web\Models\Repositories\{Clubs, Users};
|
||||||
|
|
||||||
|
class Aliases
|
||||||
|
{
|
||||||
|
private $context;
|
||||||
|
private $aliases;
|
||||||
|
|
||||||
|
function __construct()
|
||||||
|
{
|
||||||
|
$this->context = DB::i()->getContext();
|
||||||
|
$this->aliases = $this->context->table("aliases");
|
||||||
|
}
|
||||||
|
|
||||||
|
private function toAlias(?ActiveRow $ar): ?Alias
|
||||||
|
{
|
||||||
|
return is_null($ar) ? NULL : new Alias($ar);
|
||||||
|
}
|
||||||
|
|
||||||
|
function get(int $id): ?Alias
|
||||||
|
{
|
||||||
|
return $this->toAlias($this->aliases->get($id));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getByShortcode(string $shortcode): ?Alias
|
||||||
|
{
|
||||||
|
return $this->toAlias($this->aliases->where("shortcode", $shortcode)->fetch());
|
||||||
|
}
|
||||||
|
}
|
48
Web/Models/Repositories/ChandlerGroups.php
Normal file
48
Web/Models/Repositories/ChandlerGroups.php
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Models\Repositories;
|
||||||
|
use Nette\Database\Table\ActiveRow;
|
||||||
|
use Chandler\Database\DatabaseConnection as DB;
|
||||||
|
use openvk\Web\Models\Entities\User;
|
||||||
|
use Chandler\Security\User as ChandlerUser;
|
||||||
|
|
||||||
|
class ChandlerGroups
|
||||||
|
{
|
||||||
|
private $context;
|
||||||
|
private $groups;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->context = DB::i()->getContext();
|
||||||
|
$this->groups = $this->context->table("ChandlerGroups");
|
||||||
|
$this->members = $this->context->table("ChandlerACLRelations");
|
||||||
|
$this->perms = $this->context->table("ChandlerACLGroupsPermissions");
|
||||||
|
}
|
||||||
|
|
||||||
|
function get(string $UUID): ?ActiveRow
|
||||||
|
{
|
||||||
|
return $this->groups->where("id", $UUID)->fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getList(): \Traversable
|
||||||
|
{
|
||||||
|
foreach($this->groups as $group) yield $group;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMembersById(string $UUID): \Traversable
|
||||||
|
{
|
||||||
|
foreach($this->members->where("group", $UUID) as $member)
|
||||||
|
yield (new Users)->getByChandlerUser(
|
||||||
|
new ChandlerUser($this->context->table("ChandlerUsers")->where("id", $member->user)->fetch())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUsersMemberships(string $UUID): \Traversable
|
||||||
|
{
|
||||||
|
foreach($this->members->where("user", $UUID) as $member) yield $member;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPermissionsById(string $UUID): \Traversable
|
||||||
|
{
|
||||||
|
foreach($this->perms->where("group", $UUID) as $perm) yield $perm;
|
||||||
|
}
|
||||||
|
}
|
39
Web/Models/Repositories/ChandlerUsers.php
Normal file
39
Web/Models/Repositories/ChandlerUsers.php
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Models\Repositories;
|
||||||
|
use Nette\Database\Table\ActiveRow;
|
||||||
|
use Chandler\Database\DatabaseConnection as DB;
|
||||||
|
use openvk\Web\Models\Entities\User;
|
||||||
|
use Chandler\Security\User as ChandlerUser;
|
||||||
|
|
||||||
|
class ChandlerUsers
|
||||||
|
{
|
||||||
|
private $context;
|
||||||
|
private $users;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->context = DB::i()->getContext();
|
||||||
|
$this->users = $this->context->table("ChandlerUsers");
|
||||||
|
}
|
||||||
|
|
||||||
|
private function toUser(?ActiveRow $ar): ?ChandlerUser
|
||||||
|
{
|
||||||
|
return is_null($ar) ? NULL : (new User($ar))->getChandlerUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
function get(int $id): ?ChandlerUser
|
||||||
|
{
|
||||||
|
return (new Users)->get($id)->getChandlerUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getById(string $UUID): ?ChandlerUser
|
||||||
|
{
|
||||||
|
return new ChandlerUser($this->users->where("id", $UUID)->fetch());
|
||||||
|
}
|
||||||
|
|
||||||
|
function getList(int $page = 1): \Traversable
|
||||||
|
{
|
||||||
|
foreach($this->users as $user)
|
||||||
|
yield new ChandlerUser($user);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Models\Repositories;
|
namespace openvk\Web\Models\Repositories;
|
||||||
use openvk\Web\Models\Entities\Club;
|
use openvk\Web\Models\Entities\Club;
|
||||||
|
use openvk\Web\Models\Repositories\Aliases;
|
||||||
use Nette\Database\Table\ActiveRow;
|
use Nette\Database\Table\ActiveRow;
|
||||||
use Chandler\Database\DatabaseConnection;
|
use Chandler\Database\DatabaseConnection;
|
||||||
|
|
||||||
|
@ -22,7 +23,17 @@ class Clubs
|
||||||
|
|
||||||
function getByShortURL(string $url): ?Club
|
function getByShortURL(string $url): ?Club
|
||||||
{
|
{
|
||||||
return $this->toClub($this->clubs->where("shortcode", $url)->fetch());
|
$shortcode = $this->toClub($this->clubs->where("shortcode", $url)->fetch());
|
||||||
|
|
||||||
|
if ($shortcode)
|
||||||
|
return $shortcode;
|
||||||
|
|
||||||
|
$alias = (new Aliases)->getByShortcode($url);
|
||||||
|
|
||||||
|
if (!$alias) return NULL;
|
||||||
|
if ($alias->getType() !== "club") return NULL;
|
||||||
|
|
||||||
|
return $alias->getClub();
|
||||||
}
|
}
|
||||||
|
|
||||||
function get(int $id): ?Club
|
function get(int $id): ?Club
|
||||||
|
@ -45,6 +56,9 @@ class Clubs
|
||||||
|
|
||||||
function getPopularClubs(): \Traversable
|
function getPopularClubs(): \Traversable
|
||||||
{
|
{
|
||||||
|
// TODO rewrite
|
||||||
|
|
||||||
|
/*
|
||||||
$query = "SELECT ROW_NUMBER() OVER (ORDER BY `subscriptions` DESC) as `place`, `target` as `id`, COUNT(`follower`) as `subscriptions` FROM `subscriptions` WHERE `model` = \"openvk\\\Web\\\Models\\\Entities\\\Club\" GROUP BY `target` ORDER BY `subscriptions` DESC, `id` LIMIT 30;";
|
$query = "SELECT ROW_NUMBER() OVER (ORDER BY `subscriptions` DESC) as `place`, `target` as `id`, COUNT(`follower`) as `subscriptions` FROM `subscriptions` WHERE `model` = \"openvk\\\Web\\\Models\\\Entities\\\Club\" GROUP BY `target` ORDER BY `subscriptions` DESC, `id` LIMIT 30;";
|
||||||
$entries = DatabaseConnection::i()->getConnection()->query($query);
|
$entries = DatabaseConnection::i()->getConnection()->query($query);
|
||||||
|
|
||||||
|
@ -54,6 +68,7 @@ class Clubs
|
||||||
"club" => $this->get($entry["id"]),
|
"club" => $this->get($entry["id"]),
|
||||||
"subscriptions" => $entry["subscriptions"],
|
"subscriptions" => $entry["subscriptions"],
|
||||||
];
|
];
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
use \Nette\SmartObject;
|
use \Nette\SmartObject;
|
||||||
|
|
23
Web/Models/Repositories/Polls.php
Normal file
23
Web/Models/Repositories/Polls.php
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Models\Repositories;
|
||||||
|
use Chandler\Database\DatabaseConnection;
|
||||||
|
use openvk\Web\Models\Entities\Poll;
|
||||||
|
|
||||||
|
class Polls
|
||||||
|
{
|
||||||
|
private $polls;
|
||||||
|
|
||||||
|
function __construct()
|
||||||
|
{
|
||||||
|
$this->polls = DatabaseConnection::i()->getContext()->table("polls");
|
||||||
|
}
|
||||||
|
|
||||||
|
function get(int $id): ?Poll
|
||||||
|
{
|
||||||
|
$poll = $this->polls->get($id);
|
||||||
|
if(!$poll)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return new Poll($poll);
|
||||||
|
}
|
||||||
|
}
|
32
Web/Models/Repositories/SupportAgents.php
Normal file
32
Web/Models/Repositories/SupportAgents.php
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Models\Repositories;
|
||||||
|
use Nette\Database\Table\ActiveRow;
|
||||||
|
use Chandler\Database\DatabaseConnection;
|
||||||
|
use openvk\Web\Models\Entities\{User, SupportAgent};
|
||||||
|
|
||||||
|
class SupportAgents
|
||||||
|
{
|
||||||
|
private $context;
|
||||||
|
private $tickets;
|
||||||
|
|
||||||
|
function __construct()
|
||||||
|
{
|
||||||
|
$this->context = DatabaseConnection::i()->getContext();
|
||||||
|
$this->agents = $this->context->table("support_names");
|
||||||
|
}
|
||||||
|
|
||||||
|
private function toAgent(?ActiveRow $ar)
|
||||||
|
{
|
||||||
|
return is_null($ar) ? NULL : new SupportAgent($ar);
|
||||||
|
}
|
||||||
|
|
||||||
|
function get(int $id): ?SupportAgent
|
||||||
|
{
|
||||||
|
return $this->toAgent($this->agents->where("agent", $id)->fetch());
|
||||||
|
}
|
||||||
|
|
||||||
|
function isExists(int $id): bool
|
||||||
|
{
|
||||||
|
return !is_null($this->get($id));
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,5 +28,12 @@ class TicketComments
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCountByAgent(int $agent_id, int $mark = NULL): int
|
||||||
|
{
|
||||||
|
$filter = ['user_id' => $agent_id, 'user_type' => 1];
|
||||||
|
$mark && $filter['mark'] = $mark;
|
||||||
|
return sizeof($this->comments->where($filter));
|
||||||
|
}
|
||||||
|
|
||||||
use \Nette\SmartObject;
|
use \Nette\SmartObject;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Models\Repositories;
|
namespace openvk\Web\Models\Repositories;
|
||||||
use openvk\Web\Models\Entities\User;
|
use openvk\Web\Models\Entities\User;
|
||||||
|
use openvk\Web\Models\Repositories\Aliases;
|
||||||
use Nette\Database\Table\ActiveRow;
|
use Nette\Database\Table\ActiveRow;
|
||||||
use Chandler\Database\DatabaseConnection;
|
use Chandler\Database\DatabaseConnection;
|
||||||
use Chandler\Security\User as ChandlerUser;
|
use Chandler\Security\User as ChandlerUser;
|
||||||
|
@ -9,11 +10,13 @@ class Users
|
||||||
{
|
{
|
||||||
private $context;
|
private $context;
|
||||||
private $users;
|
private $users;
|
||||||
|
private $aliases;
|
||||||
|
|
||||||
function __construct()
|
function __construct()
|
||||||
{
|
{
|
||||||
$this->context = DatabaseConnection::i()->getContext();
|
$this->context = DatabaseConnection::i()->getContext();
|
||||||
$this->users = $this->context->table("profiles");
|
$this->users = $this->context->table("profiles");
|
||||||
|
$this->aliases = $this->context->table("aliases");
|
||||||
}
|
}
|
||||||
|
|
||||||
private function toUser(?ActiveRow $ar): ?User
|
private function toUser(?ActiveRow $ar): ?User
|
||||||
|
@ -28,7 +31,17 @@ class Users
|
||||||
|
|
||||||
function getByShortURL(string $url): ?User
|
function getByShortURL(string $url): ?User
|
||||||
{
|
{
|
||||||
return $this->toUser($this->users->where("shortcode", $url)->fetch());
|
$shortcode = $this->toUser($this->users->where("shortcode", $url)->fetch());
|
||||||
|
|
||||||
|
if ($shortcode)
|
||||||
|
return $shortcode;
|
||||||
|
|
||||||
|
$alias = (new Aliases)->getByShortcode($url);
|
||||||
|
|
||||||
|
if (!$alias) return NULL;
|
||||||
|
if ($alias->getType() !== "user") return NULL;
|
||||||
|
|
||||||
|
return $alias->getUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getByChandlerUser(ChandlerUser $user): ?User
|
function getByChandlerUser(ChandlerUser $user): ?User
|
||||||
|
|
|
@ -19,7 +19,7 @@ final class YouTubeVideoDriver extends VideoDriver
|
||||||
<iframe
|
<iframe
|
||||||
width="600"
|
width="600"
|
||||||
height="340"
|
height="340"
|
||||||
src="https://www.youtube.com/embed/$this->id"
|
src="https://www.youtube-nocookie.com/embed/$this->id"
|
||||||
frameborder="0"
|
frameborder="0"
|
||||||
sandbox="allow-same-origin allow-scripts allow-popups"
|
sandbox="allow-same-origin allow-scripts allow-popups"
|
||||||
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
|
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
|
||||||
|
|
|
@ -10,6 +10,8 @@ SELECT DISTINCT id, class FROM
|
||||||
sender_id = ?
|
sender_id = ?
|
||||||
AND
|
AND
|
||||||
sender_type = ?
|
sender_type = ?
|
||||||
|
AND
|
||||||
|
deleted = 0
|
||||||
) UNION (
|
) UNION (
|
||||||
SELECT
|
SELECT
|
||||||
sender_id AS id,
|
sender_id AS id,
|
||||||
|
@ -20,6 +22,8 @@ SELECT DISTINCT id, class FROM
|
||||||
recipient_id = ?
|
recipient_id = ?
|
||||||
AND
|
AND
|
||||||
recipient_type = ?
|
recipient_type = ?
|
||||||
|
AND
|
||||||
|
deleted = 0
|
||||||
)
|
)
|
||||||
ORDER BY
|
ORDER BY
|
||||||
time
|
time
|
||||||
|
|
|
@ -64,7 +64,7 @@ final class AboutPresenter extends OpenVKPresenter
|
||||||
$this->template->usersStats = (new Users)->getStatistics();
|
$this->template->usersStats = (new Users)->getStatistics();
|
||||||
$this->template->clubsCount = (new Clubs)->getCount();
|
$this->template->clubsCount = (new Clubs)->getCount();
|
||||||
$this->template->postsCount = (new Posts)->getCount();
|
$this->template->postsCount = (new Posts)->getCount();
|
||||||
$this->template->popularClubs = iterator_to_array((new Clubs)->getPopularClubs());
|
$this->template->popularClubs = [];
|
||||||
$this->template->admins = iterator_to_array((new Users)->getInstanceAdmins());
|
$this->template->admins = iterator_to_array((new Users)->getInstanceAdmins());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,6 +76,9 @@ final class AboutPresenter extends OpenVKPresenter
|
||||||
$this->assertNoCSRF();
|
$this->assertNoCSRF();
|
||||||
setLanguage($_GET['lg']);
|
setLanguage($_GET['lg']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!is_null($_GET['jReturnTo']))
|
||||||
|
$this->redirect(rawurldecode($_GET['jReturnTo']));
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderExportJSLanguage($lg = NULL): void
|
function renderExportJSLanguage($lg = NULL): void
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Presenters;
|
namespace openvk\Web\Presenters;
|
||||||
use openvk\Web\Models\Entities\{Voucher, Gift, GiftCategory, User, BannedLink};
|
use openvk\Web\Models\Entities\{Voucher, Gift, GiftCategory, User, BannedLink};
|
||||||
use openvk\Web\Models\Repositories\{Users, Clubs, Vouchers, Gifts, BannedLinks};
|
use openvk\Web\Models\Repositories\{ChandlerGroups, ChandlerUsers, Users, Clubs, Vouchers, Gifts, BannedLinks};
|
||||||
use Chandler\Database\DatabaseConnection;
|
use Chandler\Database\DatabaseConnection;
|
||||||
|
|
||||||
final class AdminPresenter extends OpenVKPresenter
|
final class AdminPresenter extends OpenVKPresenter
|
||||||
|
@ -11,14 +11,16 @@ final class AdminPresenter extends OpenVKPresenter
|
||||||
private $vouchers;
|
private $vouchers;
|
||||||
private $gifts;
|
private $gifts;
|
||||||
private $bannedLinks;
|
private $bannedLinks;
|
||||||
|
private $chandlerGroups;
|
||||||
|
|
||||||
function __construct(Users $users, Clubs $clubs, Vouchers $vouchers, Gifts $gifts, BannedLinks $bannedLinks)
|
function __construct(Users $users, Clubs $clubs, Vouchers $vouchers, Gifts $gifts, BannedLinks $bannedLinks, ChandlerGroups $chandlerGroups)
|
||||||
{
|
{
|
||||||
$this->users = $users;
|
$this->users = $users;
|
||||||
$this->clubs = $clubs;
|
$this->clubs = $clubs;
|
||||||
$this->vouchers = $vouchers;
|
$this->vouchers = $vouchers;
|
||||||
$this->gifts = $gifts;
|
$this->gifts = $gifts;
|
||||||
$this->bannedLinks = $bannedLinks;
|
$this->bannedLinks = $bannedLinks;
|
||||||
|
$this->chandlerGroups = $chandlerGroups;
|
||||||
|
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
|
@ -62,6 +64,8 @@ final class AdminPresenter extends OpenVKPresenter
|
||||||
$this->notFound();
|
$this->notFound();
|
||||||
|
|
||||||
$this->template->user = $user;
|
$this->template->user = $user;
|
||||||
|
$this->template->c_groups_list = (new ChandlerGroups)->getList();
|
||||||
|
$this->template->c_memberships = $this->chandlerGroups->getUsersMemberships($user->getChandlerGUID());
|
||||||
|
|
||||||
if($_SERVER["REQUEST_METHOD"] !== "POST")
|
if($_SERVER["REQUEST_METHOD"] !== "POST")
|
||||||
return;
|
return;
|
||||||
|
@ -78,8 +82,13 @@ final class AdminPresenter extends OpenVKPresenter
|
||||||
$user->changeEmail($this->postParam("email"));
|
$user->changeEmail($this->postParam("email"));
|
||||||
if($user->onlineStatus() != $this->postParam("online")) $user->setOnline(intval($this->postParam("online")));
|
if($user->onlineStatus() != $this->postParam("online")) $user->setOnline(intval($this->postParam("online")));
|
||||||
$user->setVerified(empty($this->postParam("verify") ? 0 : 1));
|
$user->setVerified(empty($this->postParam("verify") ? 0 : 1));
|
||||||
|
if($this->postParam("add-to-group")) {
|
||||||
|
$query = "INSERT INTO `ChandlerACLRelations` (`user`, `group`) VALUES ('" . $user->getChandlerGUID() . "', '" . $this->postParam("add-to-group") . "')";
|
||||||
|
DatabaseConnection::i()->getConnection()->query($query);
|
||||||
|
}
|
||||||
|
|
||||||
$user->save();
|
$user->save();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -447,4 +456,95 @@ final class AdminPresenter extends OpenVKPresenter
|
||||||
|
|
||||||
$this->redirect("/admin/bannedLinks");
|
$this->redirect("/admin/bannedLinks");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderChandlerGroups(): void
|
||||||
|
{
|
||||||
|
$this->template->groups = (new ChandlerGroups)->getList();
|
||||||
|
|
||||||
|
if($_SERVER["REQUEST_METHOD"] !== "POST")
|
||||||
|
return;
|
||||||
|
|
||||||
|
$req = "INSERT INTO `ChandlerGroups` (`name`) VALUES ('" . $this->postParam("name") . "')";
|
||||||
|
DatabaseConnection::i()->getConnection()->query($req);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderChandlerGroup(string $UUID): void
|
||||||
|
{
|
||||||
|
$DB = DatabaseConnection::i()->getConnection();
|
||||||
|
|
||||||
|
if(is_null($DB->query("SELECT * FROM `ChandlerGroups` WHERE `id` = '$UUID'")->fetch()))
|
||||||
|
$this->flashFail("err", tr("error"), tr("c_group_not_found"));
|
||||||
|
|
||||||
|
$this->template->group = (new ChandlerGroups)->get($UUID);
|
||||||
|
$this->template->mode = in_array(
|
||||||
|
$this->queryParam("act"),
|
||||||
|
[
|
||||||
|
"main",
|
||||||
|
"members",
|
||||||
|
"permissions",
|
||||||
|
"removeMember",
|
||||||
|
"removePermission",
|
||||||
|
"delete"
|
||||||
|
]) ? $this->queryParam("act") : "main";
|
||||||
|
$this->template->members = (new ChandlerGroups)->getMembersById($UUID);
|
||||||
|
$this->template->perms = (new ChandlerGroups)->getPermissionsById($UUID);
|
||||||
|
|
||||||
|
if($this->template->mode == "removeMember") {
|
||||||
|
$where = "`user` = '" . $this->queryParam("uid") . "' AND `group` = '$UUID'";
|
||||||
|
|
||||||
|
if(is_null($DB->query("SELECT * FROM `ChandlerACLRelations` WHERE " . $where)->fetch()))
|
||||||
|
$this->flashFail("err", tr("error"), tr("c_user_is_not_in_group"));
|
||||||
|
|
||||||
|
$DB->query("DELETE FROM `ChandlerACLRelations` WHERE " . $where);
|
||||||
|
$this->flashFail("succ", tr("changes_saved"), tr("c_user_removed_from_group"));
|
||||||
|
} elseif($this->template->mode == "removePermission") {
|
||||||
|
$where = "`model` = '" . trim(addslashes($this->queryParam("model"))) . "' AND `permission` = '". $this->queryParam("perm") ."' AND `group` = '$UUID'";
|
||||||
|
|
||||||
|
if(is_null($DB->query("SELECT * FROM `ChandlerACLGroupsPermissions WHERE $where`")))
|
||||||
|
$this->flashFail("err", tr("error"), tr("c_permission_not_found"));
|
||||||
|
|
||||||
|
$DB->query("DELETE FROM `ChandlerACLGroupsPermissions` WHERE $where");
|
||||||
|
$this->flashFail("succ", tr("changes_saved"), tr("c_permission_removed_from_group"));
|
||||||
|
} elseif($this->template->mode == "delete") {
|
||||||
|
$DB->query("DELETE FROM `ChandlerGroups` WHERE `id` = '$UUID'");
|
||||||
|
$DB->query("DELETE FROM `ChandlerACLGroupsPermissions` WHERE `group` = '$UUID'");
|
||||||
|
$DB->query("DELETE FROM `ChandlerACLRelations` WHERE `group` = '$UUID'");
|
||||||
|
|
||||||
|
$this->flashFail("succ", tr("changes_saved"), tr("c_group_removed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_SERVER["REQUEST_METHOD"] !== "POST") return;
|
||||||
|
|
||||||
|
$req = "";
|
||||||
|
|
||||||
|
if($this->template->mode == "main")
|
||||||
|
if($this->postParam("delete"))
|
||||||
|
$req = "DELETE FROM `ChandlerGroups` WHERE `id`='$UUID'";
|
||||||
|
else
|
||||||
|
$req = "UPDATE `ChandlerGroups` SET `name`='". $this->postParam('name') ."' , `color`='". $this->postParam("color") ."' WHERE `id`='$UUID'";
|
||||||
|
|
||||||
|
if($this->template->mode == "members")
|
||||||
|
if($this->postParam("uid"))
|
||||||
|
if(!is_null($DB->query("SELECT * FROM `ChandlerACLRelations` WHERE `user` = '" . $this->postParam("uid") . "'")))
|
||||||
|
$this->flashFail("err", tr("error"), tr("c_user_is_already_in_group"));
|
||||||
|
|
||||||
|
$req = "INSERT INTO `ChandlerACLRelations` (`user`, `group`, `priority`) VALUES ('". $this->postParam("uid") ."', '$UUID', 32)";
|
||||||
|
|
||||||
|
if($this->template->mode == "permissions")
|
||||||
|
$req = "INSERT INTO `ChandlerACLGroupsPermissions` (`group`, `model`, `permission`, `context`) VALUES ('$UUID', '". trim(addslashes($this->postParam("model"))) ."', '". $this->postParam("permission") ."', 0)";
|
||||||
|
|
||||||
|
$DB->query($req);
|
||||||
|
$this->flashFail("succ", tr("changes_saved"));
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderChandlerUser(string $UUID): void
|
||||||
|
{
|
||||||
|
if(!$UUID) $this->notFound();
|
||||||
|
|
||||||
|
$c_user = (new ChandlerUsers())->getById($UUID);
|
||||||
|
$user = $this->users->getByChandlerUser($c_user);
|
||||||
|
if(!$user) $this->notFound();
|
||||||
|
|
||||||
|
$this->redirect("/admin/users/id" . $user->getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use openvk\Web\Models\Repositories\Applications;
|
||||||
final class AppsPresenter extends OpenVKPresenter
|
final class AppsPresenter extends OpenVKPresenter
|
||||||
{
|
{
|
||||||
private $apps;
|
private $apps;
|
||||||
|
protected $presenterName = "apps";
|
||||||
function __construct(Applications $apps)
|
function __construct(Applications $apps)
|
||||||
{
|
{
|
||||||
$this->apps = $apps;
|
$this->apps = $apps;
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Presenters;
|
namespace openvk\Web\Presenters;
|
||||||
use openvk\Web\Models\Entities\{Comment, Photo, Video, User, Topic, Post};
|
use openvk\Web\Models\Entities\{Comment, Notifications\MentionNotification, Photo, Video, User, Topic, Post};
|
||||||
use openvk\Web\Models\Entities\Notifications\CommentNotification;
|
use openvk\Web\Models\Entities\Notifications\CommentNotification;
|
||||||
use openvk\Web\Models\Repositories\{Comments, Clubs};
|
use openvk\Web\Models\Repositories\{Comments, Clubs};
|
||||||
|
|
||||||
final class CommentPresenter extends OpenVKPresenter
|
final class CommentPresenter extends OpenVKPresenter
|
||||||
{
|
{
|
||||||
|
protected $presenterName = "comment";
|
||||||
private $models = [
|
private $models = [
|
||||||
"posts" => "openvk\\Web\\Models\\Repositories\\Posts",
|
"posts" => "openvk\\Web\\Models\\Repositories\\Posts",
|
||||||
"photos" => "openvk\\Web\\Models\\Repositories\\Photos",
|
"photos" => "openvk\\Web\\Models\\Repositories\\Photos",
|
||||||
|
@ -105,6 +106,15 @@ final class CommentPresenter extends OpenVKPresenter
|
||||||
if(($owner = $entity->getOwner()) instanceof User)
|
if(($owner = $entity->getOwner()) instanceof User)
|
||||||
(new CommentNotification($owner, $comment, $entity, $this->user->identity))->emit();
|
(new CommentNotification($owner, $comment, $entity, $this->user->identity))->emit();
|
||||||
|
|
||||||
|
$excludeMentions = [$this->user->identity->getId()];
|
||||||
|
if(($owner = $entity->getOwner()) instanceof User)
|
||||||
|
$excludeMentions[] = $owner->getId();
|
||||||
|
|
||||||
|
$mentions = iterator_to_array($comment->resolveMentions($excludeMentions));
|
||||||
|
foreach($mentions as $mentionee)
|
||||||
|
if($mentionee instanceof User)
|
||||||
|
(new MentionNotification($mentionee, $entity, $comment->getOwner(), strip_tags($comment->getText())))->emit();
|
||||||
|
|
||||||
$this->flashFail("succ", "Комментарий добавлен", "Ваш комментарий появится на странице.");
|
$this->flashFail("succ", "Комментарий добавлен", "Ваш комментарий появится на странице.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ final class GiftsPresenter extends OpenVKPresenter
|
||||||
{
|
{
|
||||||
private $gifts;
|
private $gifts;
|
||||||
private $users;
|
private $users;
|
||||||
|
protected $presenterName = "gifts";
|
||||||
|
|
||||||
function __construct(Gifts $gifts, Users $users)
|
function __construct(Gifts $gifts, Users $users)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Presenters;
|
namespace openvk\Web\Presenters;
|
||||||
use openvk\Web\Models\Entities\{Club, Photo};
|
use openvk\Web\Models\Entities\{Club, Photo};
|
||||||
|
use Nette\InvalidStateException;
|
||||||
use openvk\Web\Models\Entities\Notifications\ClubModeratorNotification;
|
use openvk\Web\Models\Entities\Notifications\ClubModeratorNotification;
|
||||||
use openvk\Web\Models\Repositories\{Clubs, Users, Albums, Managers, Topics};
|
use openvk\Web\Models\Repositories\{Clubs, Users, Albums, Managers, Topics};
|
||||||
use Chandler\Security\Authenticator;
|
use Chandler\Security\Authenticator;
|
||||||
|
@ -8,6 +9,7 @@ use Chandler\Security\Authenticator;
|
||||||
final class GroupPresenter extends OpenVKPresenter
|
final class GroupPresenter extends OpenVKPresenter
|
||||||
{
|
{
|
||||||
private $clubs;
|
private $clubs;
|
||||||
|
protected $presenterName = "group";
|
||||||
|
|
||||||
function __construct(Clubs $clubs)
|
function __construct(Clubs $clubs)
|
||||||
{
|
{
|
||||||
|
@ -190,7 +192,7 @@ final class GroupPresenter extends OpenVKPresenter
|
||||||
$this->willExecuteWriteAction();
|
$this->willExecuteWriteAction();
|
||||||
|
|
||||||
$club = $this->clubs->get($id);
|
$club = $this->clubs->get($id);
|
||||||
if(!$club->canBeModifiedBy($this->user->identity))
|
if(!$club || !$club->canBeModifiedBy($this->user->identity))
|
||||||
$this->notFound();
|
$this->notFound();
|
||||||
else
|
else
|
||||||
$this->template->club = $club;
|
$this->template->club = $club;
|
||||||
|
@ -249,6 +251,45 @@ final class GroupPresenter extends OpenVKPresenter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderEditBackdrop(int $id): void
|
||||||
|
{
|
||||||
|
$this->assertUserLoggedIn();
|
||||||
|
$this->willExecuteWriteAction();
|
||||||
|
|
||||||
|
$club = $this->clubs->get($id);
|
||||||
|
if(!$club || !$club->canBeModifiedBy($this->user->identity))
|
||||||
|
$this->notFound();
|
||||||
|
else
|
||||||
|
$this->template->club = $club;
|
||||||
|
|
||||||
|
if($_SERVER["REQUEST_METHOD"] !== "POST")
|
||||||
|
return;
|
||||||
|
|
||||||
|
if($this->postParam("subact") === "remove") {
|
||||||
|
$club->unsetBackDropPictures();
|
||||||
|
$club->save();
|
||||||
|
$this->flashFail("succ", tr("backdrop_succ_rem"), tr("backdrop_succ_desc")); # will exit
|
||||||
|
}
|
||||||
|
|
||||||
|
$pic1 = $pic2 = NULL;
|
||||||
|
try {
|
||||||
|
if($_FILES["backdrop1"]["error"] !== UPLOAD_ERR_NO_FILE)
|
||||||
|
$pic1 = Photo::fastMake($this->user->id, "Profile backdrop (system)", $_FILES["backdrop1"]);
|
||||||
|
|
||||||
|
if($_FILES["backdrop2"]["error"] !== UPLOAD_ERR_NO_FILE)
|
||||||
|
$pic2 = Photo::fastMake($this->user->id, "Profile backdrop (system)", $_FILES["backdrop2"]);
|
||||||
|
} catch(InvalidStateException $e) {
|
||||||
|
$this->flashFail("err", tr("backdrop_error_title"), tr("backdrop_error_no_media"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if($pic1 == $pic2 && is_null($pic1))
|
||||||
|
$this->flashFail("err", tr("backdrop_error_title"), tr("backdrop_error_no_media"));
|
||||||
|
|
||||||
|
$club->setBackDropPictures($pic1, $pic2);
|
||||||
|
$club->save();
|
||||||
|
$this->flashFail("succ", tr("backdrop_succ"), tr("backdrop_succ_desc"));
|
||||||
|
}
|
||||||
|
|
||||||
function renderStatistics(int $id): void
|
function renderStatistics(int $id): void
|
||||||
{
|
{
|
||||||
$this->assertUserLoggedIn();
|
$this->assertUserLoggedIn();
|
||||||
|
|
35
Web/Presenters/MaintenancePresenter.php
Normal file
35
Web/Presenters/MaintenancePresenter.php
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace openvk\Web\Presenters;
|
||||||
|
|
||||||
|
final class MaintenancePresenter extends OpenVKPresenter
|
||||||
|
{
|
||||||
|
protected $presenterName = "maintenance";
|
||||||
|
|
||||||
|
function renderSection(string $name): void
|
||||||
|
{
|
||||||
|
if(!OPENVK_ROOT_CONF["openvk"]["preferences"]["maintenanceMode"][$name])
|
||||||
|
$this->flashFail("err", tr("error"), tr("forbidden"));
|
||||||
|
|
||||||
|
$this->template->name = [
|
||||||
|
"photos" => tr("my_photos"),
|
||||||
|
"videos" => tr("my_videos"),
|
||||||
|
"messenger" => tr("my_messages"),
|
||||||
|
"user" => tr("users"),
|
||||||
|
"group" => tr("my_groups"),
|
||||||
|
"comment" => tr("comments"),
|
||||||
|
"gifts" => tr("gifts"),
|
||||||
|
"apps" => tr("apps"),
|
||||||
|
"notes" => tr("my_notes"),
|
||||||
|
"notification" => tr("my_feedback"),
|
||||||
|
"support" => tr("menu_support"),
|
||||||
|
"topics" => tr("topics")
|
||||||
|
][$name] ?? $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderAll(): void
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,11 +9,13 @@ final class MessengerPresenter extends OpenVKPresenter
|
||||||
{
|
{
|
||||||
private $messages;
|
private $messages;
|
||||||
private $signaler;
|
private $signaler;
|
||||||
|
protected $presenterName = "messenger";
|
||||||
|
|
||||||
function __construct(Messages $messages)
|
function __construct(Messages $messages)
|
||||||
{
|
{
|
||||||
$this->messages = $messages;
|
$this->messages = $messages;
|
||||||
$this->signaler = SignalManager::i();
|
$this->signaler = SignalManager::i();
|
||||||
|
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,6 +96,13 @@ final class MessengerPresenter extends OpenVKPresenter
|
||||||
|
|
||||||
$legacy = $this->queryParam("version") < 3;
|
$legacy = $this->queryParam("version") < 3;
|
||||||
|
|
||||||
|
$time = intval($this->queryParam("wait"));
|
||||||
|
|
||||||
|
if($time > 60)
|
||||||
|
$time = 60;
|
||||||
|
elseif($time == 0)
|
||||||
|
$time = 25; // default
|
||||||
|
|
||||||
$this->signaler->listen(function($event, $eId) use ($id) {
|
$this->signaler->listen(function($event, $eId) use ($id) {
|
||||||
exit(json_encode([
|
exit(json_encode([
|
||||||
"ts" => time(),
|
"ts" => time(),
|
||||||
|
@ -101,7 +110,7 @@ final class MessengerPresenter extends OpenVKPresenter
|
||||||
$event->getVKAPISummary($id),
|
$event->getVKAPISummary($id),
|
||||||
],
|
],
|
||||||
]));
|
]));
|
||||||
}, $id);
|
}, $id, $time);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderApiGetMessages(int $sel, int $lastMsg): void
|
function renderApiGetMessages(int $sel, int $lastMsg): void
|
||||||
|
|
|
@ -6,6 +6,7 @@ use openvk\Web\Models\Entities\Note;
|
||||||
final class NotesPresenter extends OpenVKPresenter
|
final class NotesPresenter extends OpenVKPresenter
|
||||||
{
|
{
|
||||||
private $notes;
|
private $notes;
|
||||||
|
protected $presenterName = "notes";
|
||||||
|
|
||||||
function __construct(Notes $notes)
|
function __construct(Notes $notes)
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,6 +3,8 @@ namespace openvk\Web\Presenters;
|
||||||
|
|
||||||
final class NotificationPresenter extends OpenVKPresenter
|
final class NotificationPresenter extends OpenVKPresenter
|
||||||
{
|
{
|
||||||
|
protected $presenterName = "notification";
|
||||||
|
|
||||||
function renderFeed(): void
|
function renderFeed(): void
|
||||||
{
|
{
|
||||||
$this->assertUserLoggedIn();
|
$this->assertUserLoggedIn();
|
||||||
|
|
|
@ -17,6 +17,7 @@ abstract class OpenVKPresenter extends SimplePresenter
|
||||||
protected $deactivationTolerant = false;
|
protected $deactivationTolerant = false;
|
||||||
protected $errorTemplate = "@error";
|
protected $errorTemplate = "@error";
|
||||||
protected $user = NULL;
|
protected $user = NULL;
|
||||||
|
protected $presenterName;
|
||||||
|
|
||||||
private function calculateQueryString(array $data): string
|
private function calculateQueryString(array $data): string
|
||||||
{
|
{
|
||||||
|
@ -202,6 +203,7 @@ abstract class OpenVKPresenter extends SimplePresenter
|
||||||
|
|
||||||
$userValidated = 0;
|
$userValidated = 0;
|
||||||
$cacheTime = OPENVK_ROOT_CONF["openvk"]["preferences"]["nginxCacheTime"] ?? 0;
|
$cacheTime = OPENVK_ROOT_CONF["openvk"]["preferences"]["nginxCacheTime"] ?? 0;
|
||||||
|
|
||||||
if(!is_null($user)) {
|
if(!is_null($user)) {
|
||||||
$this->user = (object) [];
|
$this->user = (object) [];
|
||||||
$this->user->raw = $user;
|
$this->user->raw = $user;
|
||||||
|
@ -264,6 +266,16 @@ abstract class OpenVKPresenter extends SimplePresenter
|
||||||
header("X-Accel-Expires: $cacheTime");
|
header("X-Accel-Expires: $cacheTime");
|
||||||
setlocale(LC_TIME, ...(explode(";", tr("__locale"))));
|
setlocale(LC_TIME, ...(explode(";", tr("__locale"))));
|
||||||
|
|
||||||
|
if (!OPENVK_ROOT_CONF["openvk"]["preferences"]["maintenanceMode"]["all"]) {
|
||||||
|
if (OPENVK_ROOT_CONF["openvk"]["preferences"]["maintenanceMode"][$this->presenterName]) {
|
||||||
|
$this->pass("openvk!Maintenance->section", $this->presenterName);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($this->presenterName != "maintenance") {
|
||||||
|
$this->redirect("/maintenances/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
parent::onStartup();
|
parent::onStartup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,8 +284,12 @@ abstract class OpenVKPresenter extends SimplePresenter
|
||||||
parent::onBeforeRender();
|
parent::onBeforeRender();
|
||||||
|
|
||||||
$whichbrowser = new WhichBrowser\Parser(getallheaders());
|
$whichbrowser = new WhichBrowser\Parser(getallheaders());
|
||||||
|
$featurephonetheme = OPENVK_ROOT_CONF["openvk"]["preferences"]["defaultFeaturePhoneTheme"];
|
||||||
$mobiletheme = OPENVK_ROOT_CONF["openvk"]["preferences"]["defaultMobileTheme"];
|
$mobiletheme = OPENVK_ROOT_CONF["openvk"]["preferences"]["defaultMobileTheme"];
|
||||||
if($mobiletheme && $whichbrowser->isType('mobile') && Session::i()->get("_tempTheme") == NULL)
|
|
||||||
|
if($featurephonetheme && $this->isOldThing($whichbrowser) && Session::i()->get("_tempTheme") == NULL) {
|
||||||
|
$this->setSessionTheme($featurephonetheme);
|
||||||
|
} elseif($mobiletheme && $whichbrowser->isType('mobile') && Session::i()->get("_tempTheme") == NULL)
|
||||||
$this->setSessionTheme($mobiletheme);
|
$this->setSessionTheme($mobiletheme);
|
||||||
|
|
||||||
$theme = NULL;
|
$theme = NULL;
|
||||||
|
@ -306,4 +322,33 @@ abstract class OpenVKPresenter extends SimplePresenter
|
||||||
header("Content-Length: $size");
|
header("Content-Length: $size");
|
||||||
exit($payload);
|
exit($payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function isOldThing($whichbrowser) {
|
||||||
|
if($whichbrowser->isOs('Series60') ||
|
||||||
|
$whichbrowser->isOs('Series40') ||
|
||||||
|
$whichbrowser->isOs('Series80') ||
|
||||||
|
$whichbrowser->isOs('Windows CE') ||
|
||||||
|
$whichbrowser->isOs('Windows Mobile') ||
|
||||||
|
$whichbrowser->isOs('Nokia Asha Platform') ||
|
||||||
|
$whichbrowser->isOs('UIQ') ||
|
||||||
|
$whichbrowser->isEngine('NetFront') || // PSP and other japanese portable systems
|
||||||
|
$whichbrowser->isOs('Android') ||
|
||||||
|
$whichbrowser->isOs('iOS') ||
|
||||||
|
$whichbrowser->isBrowser('Internet Explorer', '<=', '8')) {
|
||||||
|
// yeah, it's old, but ios and android are?
|
||||||
|
if($whichbrowser->isOs('iOS') && $whichbrowser->isOs('iOS', '<=', '9'))
|
||||||
|
return true;
|
||||||
|
elseif($whichbrowser->isOs('iOS') && $whichbrowser->isOs('iOS', '>', '9'))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if($whichbrowser->isOs('Android') && $whichbrowser->isOs('Android', '<=', '5'))
|
||||||
|
return true;
|
||||||
|
elseif($whichbrowser->isOs('Android') && $whichbrowser->isOs('Android', '>', '5'))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ final class PhotosPresenter extends OpenVKPresenter
|
||||||
private $users;
|
private $users;
|
||||||
private $photos;
|
private $photos;
|
||||||
private $albums;
|
private $albums;
|
||||||
|
protected $presenterName = "photos";
|
||||||
|
|
||||||
function __construct(Photos $photos, Albums $albums, Users $users)
|
function __construct(Photos $photos, Albums $albums, Users $users)
|
||||||
{
|
{
|
||||||
|
|
75
Web/Presenters/PollPresenter.php
Normal file
75
Web/Presenters/PollPresenter.php
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Presenters;
|
||||||
|
use openvk\Web\Models\Entities\Poll;
|
||||||
|
use openvk\Web\Models\Repositories\Polls;
|
||||||
|
|
||||||
|
final class PollPresenter extends OpenVKPresenter
|
||||||
|
{
|
||||||
|
private $polls;
|
||||||
|
|
||||||
|
function __construct(Polls $polls)
|
||||||
|
{
|
||||||
|
$this->polls = $polls;
|
||||||
|
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderView(int $id): void
|
||||||
|
{
|
||||||
|
$poll = $this->polls->get($id);
|
||||||
|
if(!$poll)
|
||||||
|
$this->notFound();
|
||||||
|
|
||||||
|
$this->template->id = $poll->getId();
|
||||||
|
$this->template->title = $poll->getTitle();
|
||||||
|
$this->template->isAnon = $poll->isAnonymous();
|
||||||
|
$this->template->multiple = $poll->isMultipleChoice();
|
||||||
|
$this->template->unlocked = $poll->isRevotable();
|
||||||
|
$this->template->until = $poll->endsAt();
|
||||||
|
$this->template->votes = $poll->getVoterCount();
|
||||||
|
$this->template->meta = $poll->getMetaDescription();
|
||||||
|
$this->template->ended = $ended = $poll->hasEnded();
|
||||||
|
if((is_null($this->user) || $poll->canVote($this->user->identity)) && !$ended) {
|
||||||
|
$this->template->options = $poll->getOptions();
|
||||||
|
|
||||||
|
$this->template->_template = "Poll/Poll.xml";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(is_null($this->user)) {
|
||||||
|
$this->template->voted = false;
|
||||||
|
$this->template->results = $poll->getResults();
|
||||||
|
} else {
|
||||||
|
$this->template->voted = $poll->hasVoted($this->user->identity);
|
||||||
|
$this->template->results = $poll->getResults($this->user->identity);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->template->_template = "Poll/PollResults.xml";
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderVoters(int $pollId): void
|
||||||
|
{
|
||||||
|
$poll = $this->polls->get($pollId);
|
||||||
|
if(!$poll)
|
||||||
|
$this->notFound();
|
||||||
|
|
||||||
|
if($poll->isAnonymous())
|
||||||
|
$this->flashFail("err", tr("forbidden"), tr("poll_err_anonymous"));
|
||||||
|
|
||||||
|
$options = $poll->getOptions();
|
||||||
|
$option = (int) base_convert($this->queryParam("option"), 32, 10);
|
||||||
|
if(!in_array($option, array_keys($options)))
|
||||||
|
$this->notFound();
|
||||||
|
|
||||||
|
$page = (int) ($this->queryParam("p") ?? 1);
|
||||||
|
$voters = $poll->getVoters($option, $page);
|
||||||
|
|
||||||
|
$this->template->pollId = $pollId;
|
||||||
|
$this->template->options = $options;
|
||||||
|
$this->template->option = [$option, $options[$option]];
|
||||||
|
$this->template->tabs = $options;
|
||||||
|
$this->template->iterator = $voters;
|
||||||
|
$this->template->count = $poll->getVoterCount($option);
|
||||||
|
$this->template->page = $page;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Presenters;
|
namespace openvk\Web\Presenters;
|
||||||
use openvk\Web\Models\Entities\{Ticket, TicketComment};
|
use openvk\Web\Models\Entities\{SupportAgent, Ticket, TicketComment};
|
||||||
use openvk\Web\Models\Repositories\{Tickets, Users, TicketComments};
|
use openvk\Web\Models\Repositories\{Tickets, Users, TicketComments, SupportAgents};
|
||||||
use openvk\Web\Util\Telegram;
|
use openvk\Web\Util\Telegram;
|
||||||
use Chandler\Session\Session;
|
use Chandler\Session\Session;
|
||||||
use Chandler\Database\DatabaseConnection;
|
use Chandler\Database\DatabaseConnection;
|
||||||
|
@ -11,6 +11,7 @@ final class SupportPresenter extends OpenVKPresenter
|
||||||
{
|
{
|
||||||
protected $banTolerant = true;
|
protected $banTolerant = true;
|
||||||
protected $deactivationTolerant = true;
|
protected $deactivationTolerant = true;
|
||||||
|
protected $presenterName = "support";
|
||||||
|
|
||||||
private $tickets;
|
private $tickets;
|
||||||
private $comments;
|
private $comments;
|
||||||
|
@ -155,11 +156,12 @@ final class SupportPresenter extends OpenVKPresenter
|
||||||
$this->notFound();
|
$this->notFound();
|
||||||
} else {
|
} else {
|
||||||
if($ticket->getUserId() !== $this->user->id && $this->hasPermission('openvk\Web\Models\Entities\TicketReply', 'write', 0))
|
if($ticket->getUserId() !== $this->user->id && $this->hasPermission('openvk\Web\Models\Entities\TicketReply', 'write', 0))
|
||||||
$this->redirect("/support/tickets");
|
$_redirect = "/support/tickets";
|
||||||
else
|
else
|
||||||
$this->redirect("/support");
|
$_redirect = "/support?act=list";
|
||||||
|
|
||||||
$ticket->delete();
|
$ticket->delete();
|
||||||
|
$this->redirect($_redirect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -340,4 +342,58 @@ final class SupportPresenter extends OpenVKPresenter
|
||||||
$user->save();
|
$user->save();
|
||||||
$this->returnJson([ "success" => true ]);
|
$this->returnJson([ "success" => true ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderAgent(int $id): void
|
||||||
|
{
|
||||||
|
$this->assertPermission("openvk\Web\Models\Entities\TicketReply", "write", 0);
|
||||||
|
|
||||||
|
$support_names = new SupportAgents;
|
||||||
|
|
||||||
|
if(!$support_names->isExists($id))
|
||||||
|
$this->template->mode = "edit";
|
||||||
|
|
||||||
|
$this->template->agent_id = $id;
|
||||||
|
$this->template->mode = in_array($this->queryParam("act"), ["info", "edit"]) ? $this->queryParam("act") : "info";
|
||||||
|
$this->template->agent = $support_names->get($id) ?? NULL;
|
||||||
|
$this->template->counters = [
|
||||||
|
"all" => (new TicketComments)->getCountByAgent($id),
|
||||||
|
"good" => (new TicketComments)->getCountByAgent($id, 1),
|
||||||
|
"bad" => (new TicketComments)->getCountByAgent($id, 2)
|
||||||
|
];
|
||||||
|
|
||||||
|
if($id != $this->user->identity->getId())
|
||||||
|
if ($support_names->isExists($id))
|
||||||
|
$this->template->mode = "info";
|
||||||
|
else
|
||||||
|
$this->redirect("/support/agent" . $this->user->identity->getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderEditAgent(int $id): void
|
||||||
|
{
|
||||||
|
$this->assertPermission("openvk\Web\Models\Entities\TicketReply", "write", 0);
|
||||||
|
$this->assertNoCSRF();
|
||||||
|
|
||||||
|
$support_names = new SupportAgents;
|
||||||
|
$agent = $support_names->get($id);
|
||||||
|
|
||||||
|
if($agent)
|
||||||
|
if($agent->getAgentId() != $this->user->identity->getId()) $this->flashFail("err", tr("error"), tr("forbidden"));
|
||||||
|
|
||||||
|
if ($support_names->isExists($id)) {
|
||||||
|
$agent = $support_names->get($id);
|
||||||
|
$agent->setName($this->postParam("name") ?? tr("helpdesk_agent"));
|
||||||
|
$agent->setNumerate((int) $this->postParam("number") ?? NULL);
|
||||||
|
$agent->setIcon($this->postParam("avatar"));
|
||||||
|
$agent->save();
|
||||||
|
$this->flashFail("succ", "Успех", "Профиль отредактирован.");
|
||||||
|
} else {
|
||||||
|
$agent = new SupportAgent;
|
||||||
|
$agent->setAgent($this->user->identity->getId());
|
||||||
|
$agent->setName($this->postParam("name") ?? tr("helpdesk_agent"));
|
||||||
|
$agent->setNumerate((int) $this->postParam("number") ?? NULL);
|
||||||
|
$agent->setIcon($this->postParam("avatar"));
|
||||||
|
$agent->save();
|
||||||
|
$this->flashFail("succ", "Успех", "Профиль создан. Теперь пользователи видят Ваши псевдоним и аватарку вместо стандартных аватарки и номера.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ final class TopicsPresenter extends OpenVKPresenter
|
||||||
{
|
{
|
||||||
private $topics;
|
private $topics;
|
||||||
private $clubs;
|
private $clubs;
|
||||||
|
protected $presenterName = "topics";
|
||||||
|
|
||||||
function __construct(Topics $topics, Clubs $clubs)
|
function __construct(Topics $topics, Clubs $clubs)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Presenters;
|
namespace openvk\Web\Presenters;
|
||||||
|
use Nette\InvalidStateException;
|
||||||
use openvk\Web\Util\Sms;
|
use openvk\Web\Util\Sms;
|
||||||
use openvk\Web\Themes\Themepacks;
|
use openvk\Web\Themes\Themepacks;
|
||||||
use openvk\Web\Models\Entities\{Photo, Post, EmailChangeVerification};
|
use openvk\Web\Models\Entities\{Photo, Post, EmailChangeVerification};
|
||||||
|
@ -15,8 +16,9 @@ use Nette\Database\UniqueConstraintViolationException;
|
||||||
final class UserPresenter extends OpenVKPresenter
|
final class UserPresenter extends OpenVKPresenter
|
||||||
{
|
{
|
||||||
private $users;
|
private $users;
|
||||||
|
|
||||||
public $deactivationTolerant = false;
|
public $deactivationTolerant = false;
|
||||||
|
protected $presenterName = "user";
|
||||||
|
|
||||||
function __construct(Users $users)
|
function __construct(Users $users)
|
||||||
{
|
{
|
||||||
$this->users = $users;
|
$this->users = $users;
|
||||||
|
@ -28,7 +30,7 @@ final class UserPresenter extends OpenVKPresenter
|
||||||
{
|
{
|
||||||
$user = $this->users->get($id);
|
$user = $this->users->get($id);
|
||||||
if(!$user || $user->isDeleted()) {
|
if(!$user || $user->isDeleted()) {
|
||||||
if($user->isDeactivated()) {
|
if(!is_null($user) && $user->isDeactivated()) {
|
||||||
$this->template->_template = "User/deactivated.xml";
|
$this->template->_template = "User/deactivated.xml";
|
||||||
|
|
||||||
$this->template->user = $user;
|
$this->template->user = $user;
|
||||||
|
@ -207,6 +209,30 @@ final class UserPresenter extends OpenVKPresenter
|
||||||
$user->setFav_Books(empty($this->postParam("fav_books")) ? NULL : ovk_proc_strtr($this->postParam("fav_books"), 300));
|
$user->setFav_Books(empty($this->postParam("fav_books")) ? NULL : ovk_proc_strtr($this->postParam("fav_books"), 300));
|
||||||
$user->setFav_Quote(empty($this->postParam("fav_quote")) ? NULL : ovk_proc_strtr($this->postParam("fav_quote"), 300));
|
$user->setFav_Quote(empty($this->postParam("fav_quote")) ? NULL : ovk_proc_strtr($this->postParam("fav_quote"), 300));
|
||||||
$user->setAbout(empty($this->postParam("about")) ? NULL : ovk_proc_strtr($this->postParam("about"), 300));
|
$user->setAbout(empty($this->postParam("about")) ? NULL : ovk_proc_strtr($this->postParam("about"), 300));
|
||||||
|
} elseif($_GET["act"] === "backdrop") {
|
||||||
|
if($this->postParam("subact") === "remove") {
|
||||||
|
$user->unsetBackDropPictures();
|
||||||
|
$user->save();
|
||||||
|
$this->flashFail("succ", tr("backdrop_succ_rem"), tr("backdrop_succ_desc")); # will exit
|
||||||
|
}
|
||||||
|
|
||||||
|
$pic1 = $pic2 = NULL;
|
||||||
|
try {
|
||||||
|
if($_FILES["backdrop1"]["error"] !== UPLOAD_ERR_NO_FILE)
|
||||||
|
$pic1 = Photo::fastMake($user->getId(), "Profile backdrop (system)", $_FILES["backdrop1"]);
|
||||||
|
|
||||||
|
if($_FILES["backdrop2"]["error"] !== UPLOAD_ERR_NO_FILE)
|
||||||
|
$pic2 = Photo::fastMake($user->getId(), "Profile backdrop (system)", $_FILES["backdrop2"]);
|
||||||
|
} catch(InvalidStateException $e) {
|
||||||
|
$this->flashFail("err", tr("backdrop_error_title"), tr("backdrop_error_no_media"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if($pic1 == $pic2 && is_null($pic1))
|
||||||
|
$this->flashFail("err", tr("backdrop_error_title"), tr("backdrop_error_no_media"));
|
||||||
|
|
||||||
|
$user->setBackDropPictures($pic1, $pic2);
|
||||||
|
$user->save();
|
||||||
|
$this->flashFail("succ", tr("backdrop_succ"), tr("backdrop_succ_desc"));
|
||||||
} elseif($_GET['act'] === "status") {
|
} elseif($_GET['act'] === "status") {
|
||||||
if(mb_strlen($this->postParam("status")) > 255) {
|
if(mb_strlen($this->postParam("status")) > 255) {
|
||||||
$statusLength = (string) mb_strlen($this->postParam("status"));
|
$statusLength = (string) mb_strlen($this->postParam("status"));
|
||||||
|
@ -234,7 +260,7 @@ final class UserPresenter extends OpenVKPresenter
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->template->mode = in_array($this->queryParam("act"), [
|
$this->template->mode = in_array($this->queryParam("act"), [
|
||||||
"main", "contacts", "interests", "avatar"
|
"main", "contacts", "interests", "avatar", "backdrop"
|
||||||
]) ? $this->queryParam("act")
|
]) ? $this->queryParam("act")
|
||||||
: "main";
|
: "main";
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ final class VideosPresenter extends OpenVKPresenter
|
||||||
{
|
{
|
||||||
private $videos;
|
private $videos;
|
||||||
private $users;
|
private $users;
|
||||||
|
protected $presenterName = "videos";
|
||||||
|
|
||||||
function __construct(Videos $videos, Users $users)
|
function __construct(Videos $videos, Users $users)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Presenters;
|
namespace openvk\Web\Presenters;
|
||||||
use openvk\Web\Models\Entities\{Post, Photo, Video, Club, User};
|
use openvk\Web\Models\Exceptions\TooMuchOptionsException;
|
||||||
use openvk\Web\Models\Entities\Notifications\{RepostNotification, WallPostNotification};
|
use openvk\Web\Models\Entities\{Poll, Post, Photo, Video, Club, User};
|
||||||
|
use openvk\Web\Models\Entities\Notifications\{MentionNotification, RepostNotification, WallPostNotification};
|
||||||
use openvk\Web\Models\Repositories\{Posts, Users, Clubs, Albums};
|
use openvk\Web\Models\Repositories\{Posts, Users, Clubs, Albums};
|
||||||
use Chandler\Database\DatabaseConnection;
|
use Chandler\Database\DatabaseConnection;
|
||||||
use Nette\InvalidStateException as ISE;
|
use Nette\InvalidStateException as ISE;
|
||||||
|
@ -44,9 +45,6 @@ final class WallPresenter extends OpenVKPresenter
|
||||||
|
|
||||||
function renderWall(int $user, bool $embedded = false): void
|
function renderWall(int $user, bool $embedded = false): void
|
||||||
{
|
{
|
||||||
if(false)
|
|
||||||
exit(tr("forbidden") . ": " . (string) random_int(0, 255));
|
|
||||||
|
|
||||||
$owner = ($user < 0 ? (new Clubs) : (new Users))->get(abs($user));
|
$owner = ($user < 0 ? (new Clubs) : (new Users))->get(abs($user));
|
||||||
if(is_null($this->user)) {
|
if(is_null($this->user)) {
|
||||||
$canPost = false;
|
$canPost = false;
|
||||||
|
@ -66,6 +64,9 @@ final class WallPresenter extends OpenVKPresenter
|
||||||
|
|
||||||
if ($embedded == true) $this->template->_template = "components/wall.xml";
|
if ($embedded == true) $this->template->_template = "components/wall.xml";
|
||||||
$this->template->oObj = $owner;
|
$this->template->oObj = $owner;
|
||||||
|
if($user < 0)
|
||||||
|
$this->template->club = $owner;
|
||||||
|
|
||||||
$this->template->owner = $user;
|
$this->template->owner = $user;
|
||||||
$this->template->canPost = $canPost;
|
$this->template->canPost = $canPost;
|
||||||
$this->template->count = $this->posts->getPostCountOnUserWall($user);
|
$this->template->count = $this->posts->getPostCountOnUserWall($user);
|
||||||
|
@ -88,9 +89,6 @@ final class WallPresenter extends OpenVKPresenter
|
||||||
|
|
||||||
function renderRSS(int $user): void
|
function renderRSS(int $user): void
|
||||||
{
|
{
|
||||||
if(false)
|
|
||||||
exit(tr("forbidden") . ": " . (string) random_int(0, 255));
|
|
||||||
|
|
||||||
$owner = ($user < 0 ? (new Clubs) : (new Users))->get(abs($user));
|
$owner = ($user < 0 ? (new Clubs) : (new Users))->get(abs($user));
|
||||||
if(is_null($this->user)) {
|
if(is_null($this->user)) {
|
||||||
$canPost = false;
|
$canPost = false;
|
||||||
|
@ -259,16 +257,26 @@ final class WallPresenter extends OpenVKPresenter
|
||||||
$photo = Photo::fastMake($this->user->id, $this->postParam("text"), $_FILES["_pic_attachment"], $album, $anon);
|
$photo = Photo::fastMake($this->user->id, $this->postParam("text"), $_FILES["_pic_attachment"], $album, $anon);
|
||||||
}
|
}
|
||||||
|
|
||||||
if($_FILES["_vid_attachment"]["error"] === UPLOAD_ERR_OK) {
|
if($_FILES["_vid_attachment"]["error"] === UPLOAD_ERR_OK)
|
||||||
$video = Video::fastMake($this->user->id, $this->postParam("text"), $_FILES["_vid_attachment"], $anon);
|
$video = Video::fastMake($this->user->id, $this->postParam("text"), $_FILES["_vid_attachment"], $anon);
|
||||||
}
|
|
||||||
} catch(\DomainException $ex) {
|
} catch(\DomainException $ex) {
|
||||||
$this->flashFail("err", tr("failed_to_publish_post"), tr("media_file_corrupted"));
|
$this->flashFail("err", tr("failed_to_publish_post"), tr("media_file_corrupted"));
|
||||||
} catch(ISE $ex) {
|
} catch(ISE $ex) {
|
||||||
$this->flashFail("err", tr("failed_to_publish_post"), tr("media_file_corrupted_or_too_large"));
|
$this->flashFail("err", tr("failed_to_publish_post"), tr("media_file_corrupted_or_too_large"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(empty($this->postParam("text")) && !$photo && !$video)
|
try {
|
||||||
|
$poll = NULL;
|
||||||
|
$xml = $this->postParam("poll");
|
||||||
|
if (!is_null($xml) && $xml != "none")
|
||||||
|
$poll = Poll::import($this->user->identity, $xml);
|
||||||
|
} catch(TooMuchOptionsException $e) {
|
||||||
|
$this->flashFail("err", tr("failed_to_publish_post"), tr("poll_err_to_much_options"));
|
||||||
|
} catch(\UnexpectedValueException $e) {
|
||||||
|
$this->flashFail("err", tr("failed_to_publish_post"), "Poll format invalid");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(empty($this->postParam("text")) && !$photo && !$video && !$poll)
|
||||||
$this->flashFail("err", tr("failed_to_publish_post"), tr("post_is_empty_or_too_big"));
|
$this->flashFail("err", tr("failed_to_publish_post"), tr("post_is_empty_or_too_big"));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -291,9 +299,21 @@ final class WallPresenter extends OpenVKPresenter
|
||||||
if(!is_null($video))
|
if(!is_null($video))
|
||||||
$post->attach($video);
|
$post->attach($video);
|
||||||
|
|
||||||
|
if(!is_null($poll))
|
||||||
|
$post->attach($poll);
|
||||||
|
|
||||||
if($wall > 0 && $wall !== $this->user->identity->getId())
|
if($wall > 0 && $wall !== $this->user->identity->getId())
|
||||||
(new WallPostNotification($wallOwner, $post, $this->user->identity))->emit();
|
(new WallPostNotification($wallOwner, $post, $this->user->identity))->emit();
|
||||||
|
|
||||||
|
$excludeMentions = [$this->user->identity->getId()];
|
||||||
|
if($wall > 0)
|
||||||
|
$excludeMentions[] = $wall;
|
||||||
|
|
||||||
|
$mentions = iterator_to_array($post->resolveMentions($excludeMentions));
|
||||||
|
foreach($mentions as $mentionee)
|
||||||
|
if($mentionee instanceof User)
|
||||||
|
(new MentionNotification($mentionee, $post, $post->getOwner(), strip_tags($post->getText())))->emit();
|
||||||
|
|
||||||
$this->redirect($wallOwner->getURL());
|
$this->redirect($wallOwner->getURL());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,62 +17,19 @@
|
||||||
{script "js/l10n.js"}
|
{script "js/l10n.js"}
|
||||||
{script "js/openvk.cls.js"}
|
{script "js/openvk.cls.js"}
|
||||||
|
|
||||||
|
{css "js/node_modules/tippy.js/dist/backdrop.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"}
|
||||||
|
{script "js/node_modules/@popperjs/core/dist/umd/popper.min.js"}
|
||||||
|
{script "js/node_modules/tippy.js/dist/tippy-bundle.umd.min.js"}
|
||||||
|
{script "js/node_modules/handlebars/dist/handlebars.min.js"}
|
||||||
|
|
||||||
{if $isTimezoned == NULL}
|
{if $isTimezoned == NULL}
|
||||||
{script "js/timezone.js"}
|
{script "js/timezone.js"}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{ifset $thisUser}
|
{include "_includeCSS.xml"}
|
||||||
{if $thisUser->getNsfwTolerance() < 2}
|
|
||||||
{css "css/nsfw-posts.css"}
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{if $theme !== NULL}
|
|
||||||
{if $theme->inheritDefault()}
|
|
||||||
{css "css/style.css"}
|
|
||||||
{css "css/dialog.css"}
|
|
||||||
{css "css/notifications.css"}
|
|
||||||
|
|
||||||
{if $isXmas}
|
|
||||||
{css "css/xmas.css"}
|
|
||||||
{/if}
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="/themepack/{$theme->getId()}/{$theme->getVersion()}/stylesheet/styles.css" />
|
|
||||||
|
|
||||||
{if $isXmas}
|
|
||||||
<link rel="stylesheet" href="/themepack/{$theme->getId()}/{$theme->getVersion()}/resource/xmas.css" />
|
|
||||||
{/if}
|
|
||||||
{else}
|
|
||||||
{css "css/style.css"}
|
|
||||||
{css "css/dialog.css"}
|
|
||||||
{css "css/notifications.css"}
|
|
||||||
|
|
||||||
{if $isXmas}
|
|
||||||
{css "css/xmas.css"}
|
|
||||||
{/if}
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{if $thisUser->getStyleAvatar() == 1}
|
|
||||||
{css "css/avatar.1.css"}
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{if $thisUser->getStyleAvatar() == 2}
|
|
||||||
{css "css/avatar.2.css"}
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{if $thisUser->hasMicroblogEnabled() == 1}
|
|
||||||
{css "css/microblog.css"}
|
|
||||||
{/if}
|
|
||||||
{else}
|
|
||||||
{css "css/style.css"}
|
|
||||||
{css "css/dialog.css"}
|
|
||||||
{css "css/nsfw-posts.css"}
|
|
||||||
{css "css/notifications.css"}
|
|
||||||
|
|
||||||
{if $isXmas}
|
|
||||||
{css "css/xmas.css"}
|
|
||||||
{/if}
|
|
||||||
{/ifset}
|
|
||||||
|
|
||||||
{ifset headIncludes}
|
{ifset headIncludes}
|
||||||
{include headIncludes}
|
{include headIncludes}
|
||||||
|
@ -92,6 +49,12 @@
|
||||||
<div class="notifications_global_wrap"></div>
|
<div class="notifications_global_wrap"></div>
|
||||||
<div class="dimmer"></div>
|
<div class="dimmer"></div>
|
||||||
|
|
||||||
|
{if isset($backdrops) && !is_null($backdrops)}
|
||||||
|
<div id="backdrop" style="background-image: url('{$backdrops[0]|noescape}'), url('{$backdrops[1]|noescape}');">
|
||||||
|
<div id="backdropDripper"></div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div class="toTop">
|
<div class="toTop">
|
||||||
⬆ {_to_top}
|
⬆ {_to_top}
|
||||||
</div>
|
</div>
|
||||||
|
@ -181,7 +144,7 @@
|
||||||
{var $menuLinksAvaiable = sizeof(OPENVK_ROOT_CONF['openvk']['preferences']['menu']['links']) > 0 && $thisUser->getLeftMenuItemStatus('links')}
|
{var $menuLinksAvaiable = sizeof(OPENVK_ROOT_CONF['openvk']['preferences']['menu']['links']) > 0 && $thisUser->getLeftMenuItemStatus('links')}
|
||||||
<div n:if="$canAccessAdminPanel || $canAccessHelpdesk || $menuLinksAvaiable" class="menu_divider"></div>
|
<div n:if="$canAccessAdminPanel || $canAccessHelpdesk || $menuLinksAvaiable" class="menu_divider"></div>
|
||||||
<a href="/admin" class="link" n:if="$canAccessAdminPanel" title="{_admin} [Alt+Shift+A]" accesskey="a">{_admin}</a>
|
<a href="/admin" class="link" n:if="$canAccessAdminPanel" title="{_admin} [Alt+Shift+A]" accesskey="a">{_admin}</a>
|
||||||
<a href="/support/tickets" class="link" n:if="$canAccessHelpdesk">Helpdesk
|
<a href="/support/tickets" class="link" n:if="$canAccessHelpdesk">{_helpdesk}
|
||||||
{if $helpdeskTicketNotAnsweredCount > 0}
|
{if $helpdeskTicketNotAnsweredCount > 0}
|
||||||
(<b>{$helpdeskTicketNotAnsweredCount}</b>)
|
(<b>{$helpdeskTicketNotAnsweredCount}</b>)
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -306,9 +269,17 @@
|
||||||
<a href="/blog" class="link">{_footer_blog}</a>
|
<a href="/blog" class="link">{_footer_blog}</a>
|
||||||
<a href="/support" class="link">{_footer_help}</a>
|
<a href="/support" class="link">{_footer_help}</a>
|
||||||
<a href="/dev" target="_blank" class="link">{_footer_developers}</a>
|
<a href="/dev" target="_blank" class="link">{_footer_developers}</a>
|
||||||
<a href="/language" class="link">{_footer_choose_language}</a>
|
|
||||||
<a href="/privacy" class="link">{_footer_privacy}</a>
|
<a href="/privacy" class="link">{_footer_privacy}</a>
|
||||||
</div>
|
</div>
|
||||||
|
<p>
|
||||||
|
{var $currentUrl = $_SERVER["REQUEST_URI"]}
|
||||||
|
{foreach array_slice(getLanguages(), 0, 3) as $language}
|
||||||
|
<a href="/language?lg={$language['code']}&hash={urlencode($csrfToken)}&jReturnTo={php echo rawurlencode($currentUrl)}" rel="nofollow" title="{$language['native_name']}" class="link">
|
||||||
|
<img src="/assets/packages/static/openvk/img/flags/{$language['flag']}.gif" alt="{$language['native_name']}">
|
||||||
|
</a>
|
||||||
|
{/foreach}
|
||||||
|
<a href="/language" class="link">all languages »</a>
|
||||||
|
</p>
|
||||||
<p>OpenVK <a href="/about:openvk">{php echo OPENVK_VERSION}</a> | PHP: {phpversion()} | DB: {$dbVersion}</p>
|
<p>OpenVK <a href="/about:openvk">{php echo OPENVK_VERSION}</a> | PHP: {phpversion()} | DB: {$dbVersion}</p>
|
||||||
<p n:ifcontent>
|
<p n:ifcontent>
|
||||||
{php echo OPENVK_ROOT_CONF["openvk"]["appearance"]["motd"]}
|
{php echo OPENVK_ROOT_CONF["openvk"]["appearance"]["motd"]}
|
||||||
|
@ -325,6 +296,8 @@
|
||||||
{script "js/scroll.js"}
|
{script "js/scroll.js"}
|
||||||
{script "js/al_wall.js"}
|
{script "js/al_wall.js"}
|
||||||
{script "js/al_api.js"}
|
{script "js/al_api.js"}
|
||||||
|
{script "js/al_mentions.js"}
|
||||||
|
{script "js/al_polls.js"}
|
||||||
|
|
||||||
{ifset $thisUser}
|
{ifset $thisUser}
|
||||||
{script "js/al_notifs.js"}
|
{script "js/al_notifs.js"}
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
{var $result = preg_match("/(.+)\((.+)\)/", $language['native_name'], $name)}
|
{var $result = preg_match("/(.+)\((.+)\)/", $language['native_name'], $name)}
|
||||||
|
|
||||||
<a href="language?lg={$language['code']}&hash={urlencode($csrfToken)}" class="link_new" rel="nofollow">
|
<a href="language?lg={$language['code']}&hash={urlencode($csrfToken)}" class="link_new" rel="nofollow">
|
||||||
<center><img src="/assets/packages/static/openvk/img/flags/{$language['flag']}.gif"></center>
|
<center><img src="/assets/packages/static/openvk/img/flags/{$language['flag']}.gif" alt="{$language['native_name']}"></center>
|
||||||
<br>
|
<br>
|
||||||
{if $result == 1}
|
{if $result == 1}
|
||||||
{$name[1]}
|
{$name[1]}
|
||||||
|
|
|
@ -60,6 +60,14 @@
|
||||||
<a href="/admin/bannedLinks">{_admin_banned_links}</a>
|
<a href="/admin/bannedLinks">{_admin_banned_links}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<div class="aui-nav-heading">
|
||||||
|
<strong>Chandler</strong>
|
||||||
|
</div>
|
||||||
|
<ul class="aui-nav">
|
||||||
|
<li>
|
||||||
|
<a href="/admin/chandler/groups">{_c_groups}</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
<div class="aui-nav-heading">
|
<div class="aui-nav-heading">
|
||||||
<strong>{_admin_services}</strong>
|
<strong>{_admin_services}</strong>
|
||||||
</div>
|
</div>
|
||||||
|
|
177
Web/Presenters/templates/Admin/ChandlerGroup.xml
Normal file
177
Web/Presenters/templates/Admin/ChandlerGroup.xml
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
{extends "@layout.xml"}
|
||||||
|
|
||||||
|
{block title}
|
||||||
|
{$group->name}
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block heading}
|
||||||
|
<a href="/admin/chandler/groups">{_c_groups}</a>
|
||||||
|
» {$group->name}
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block content}
|
||||||
|
{var $isMain = $mode === 'main'}
|
||||||
|
{var $isPermissions = $mode === 'permissions'}
|
||||||
|
{var $isMembers = $mode === 'members'}
|
||||||
|
|
||||||
|
{if $isMain}
|
||||||
|
<div class="aui-tabs horizontal-tabs">
|
||||||
|
<nav class="aui-navgroup aui-navgroup-horizontal">
|
||||||
|
<div class="aui-navgroup-inner">
|
||||||
|
<div class="aui-navgroup-primary">
|
||||||
|
<ul class="aui-nav">
|
||||||
|
<li class="aui-nav-selected"><a href="?act=main">{_admin_tab_main}</a></li>
|
||||||
|
<li><a href="?act=permissions">{_c_group_permissions}</a></li>
|
||||||
|
<li><a href="?act=members">{_c_group_members}</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<form class="aui" method="POST">
|
||||||
|
<div class="field-group">
|
||||||
|
<label for="id">ID</label>
|
||||||
|
<input class="text medium-field" type="text" id="id" disabled value="{$group->id}" />
|
||||||
|
</div>
|
||||||
|
<div class="field-group">
|
||||||
|
<label for="first_name">{_name}</label>
|
||||||
|
<input class="text medium-field" type="text" id="name" name="name" value="{$group->name}" />
|
||||||
|
</div>
|
||||||
|
<div class="field-group">
|
||||||
|
<label for="first_name">{_c_color}</label>
|
||||||
|
<input class="text medium-field" type="text" id="color" name="color" value="{$group->color}" />
|
||||||
|
</div>
|
||||||
|
<div class="buttons-container">
|
||||||
|
<div class="buttons">
|
||||||
|
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||||
|
<input class="button submit" type="submit" value="{_save}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{elseif $isMembers}
|
||||||
|
<div class="aui-tabs horizontal-tabs">
|
||||||
|
<nav class="aui-navgroup aui-navgroup-horizontal">
|
||||||
|
<div class="aui-navgroup-inner">
|
||||||
|
<div class="aui-navgroup-primary">
|
||||||
|
<ul class="aui-nav">
|
||||||
|
<li><a href="?act=main">{_admin_tab_main}</a></li>
|
||||||
|
<li><a href="?act=permissions">{_c_group_permissions}</a></li>
|
||||||
|
<li class="aui-nav-selected"><a href="?act=members">{_c_group_members}</a></li>
|
||||||
|
<li>
|
||||||
|
<form class="aui" method="POST" style="display: flex;">
|
||||||
|
<div class="field-group">
|
||||||
|
<label for="uid">UID</label>
|
||||||
|
<input class="text" type="text" id="uid" name="uid" />
|
||||||
|
</div>
|
||||||
|
<div style="margin: 5px;">
|
||||||
|
<div class="buttons">
|
||||||
|
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||||
|
<input class="button submit" type="submit" value="{_add}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<table class="aui aui-table-list">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>UUID</th>
|
||||||
|
<th>{_admin_name}</th>
|
||||||
|
<th>{_gender}</th>
|
||||||
|
<th>{_admin_shortcode}</th>
|
||||||
|
<th>{_registration_date}</th>
|
||||||
|
<th>{_admin_actions}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr n:foreach="$members as $user">
|
||||||
|
<td>{$user->getId()}</td>
|
||||||
|
<td>{$user->getChandlerGUID()}</td>
|
||||||
|
<td>
|
||||||
|
<span class="aui-avatar aui-avatar-xsmall">
|
||||||
|
<span class="aui-avatar-inner">
|
||||||
|
<img src="{$user->getAvatarUrl('miniscule')}" alt="{$user->getCanonicalName()}" style="object-fit: cover;" role="presentation" />
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<a href="{$user->getURL()}">{$user->getCanonicalName()}</a>
|
||||||
|
|
||||||
|
<span n:if="$user->isBanned()" class="aui-lozenge aui-lozenge-subtle aui-lozenge-removed">{_admin_banned}</span>
|
||||||
|
</td>
|
||||||
|
<td>{$user->isFemale() ? tr("female") : tr("male")}</td>
|
||||||
|
<td>{$user->getShortCode() ?? "(" . tr("none") . ")"}</td>
|
||||||
|
<td>{$user->getRegistrationTime()}</td>
|
||||||
|
<td>
|
||||||
|
<a class="aui-button aui-button-primary" href="/admin/chandler/groups/{$group->id}?act=removeMember&uid={$user->getChandlerGUID()}">
|
||||||
|
<span class="aui-icon aui-icon-small aui-iconfont-delete">{_delete}</span>
|
||||||
|
</a>
|
||||||
|
<a class="aui-button aui-button-primary" href="/admin/users/id{$user->getId()}">
|
||||||
|
<span class="aui-icon aui-icon-small aui-iconfont-new-edit">{_edit}</span>
|
||||||
|
</a>
|
||||||
|
{if $thisUser->getChandlerUser()->can("substitute")->model('openvk\Web\Models\Entities\User')->whichBelongsTo(0)}
|
||||||
|
<a class="aui-button" href="/setSID/{$user->getChandlerUser()->getId()}?hash={rawurlencode($csrfToken)}">
|
||||||
|
<span class="aui-icon aui-icon-small aui-iconfont-sign-in">{_admin_loginas}</span>
|
||||||
|
</a>
|
||||||
|
{/if}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{elseif $isPermissions}
|
||||||
|
<div class="aui-tabs horizontal-tabs">
|
||||||
|
<nav class="aui-navgroup aui-navgroup-horizontal">
|
||||||
|
<div class="aui-navgroup-inner">
|
||||||
|
<div class="aui-navgroup-primary">
|
||||||
|
<ul class="aui-nav">
|
||||||
|
<li><a href="?act=main">{_admin_tab_main}</a></li>
|
||||||
|
<li class="aui-nav-selected"><a href="?act=permissions">{_c_group_permissions}</a></li>
|
||||||
|
<li><a href="?act=members">{_c_group_members}</a></li>
|
||||||
|
<li>
|
||||||
|
<form class="aui" method="POST" style="display: flex;">
|
||||||
|
<div class="field-group">
|
||||||
|
<label for="model">{_c_model}</label>
|
||||||
|
<input class="text" type="text" id="model" name="model" />
|
||||||
|
<input class="text" type="text" id="permission" name="permission" />
|
||||||
|
<label for="action">{_c_permission}</label>
|
||||||
|
</div>
|
||||||
|
<div style="margin: 5px;">
|
||||||
|
<div class="buttons">
|
||||||
|
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||||
|
<input class="button submit" type="submit" value="{_add}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<table class="aui aui-table-list">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{_c_model}</th>
|
||||||
|
<th>{_c_permission}</th>
|
||||||
|
<th>{_admin_actions}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr n:foreach="$perms as $perm">
|
||||||
|
<td>{$perm->model}</td>
|
||||||
|
<td>{$perm->permission}</td>
|
||||||
|
<td>
|
||||||
|
<a class="aui-button aui-button-primary" href="/admin/chandler/groups/{$perm->group}?act=removePermission&model={$perm->model}&perm={$perm->permission}">
|
||||||
|
<span class="aui-icon aui-icon-small aui-iconfont-delete">{_edit}</span>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/block}
|
59
Web/Presenters/templates/Admin/ChandlerGroups.xml
Normal file
59
Web/Presenters/templates/Admin/ChandlerGroups.xml
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
{extends "@layout.xml"}
|
||||||
|
|
||||||
|
{block title}
|
||||||
|
{_c_groups}
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block heading}
|
||||||
|
{_c_groups}
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block content}
|
||||||
|
<form class="aui" method="POST">
|
||||||
|
<div class="field-group" style="margin-left: -65px;">
|
||||||
|
<label for="uid">{_admin_title}</label>
|
||||||
|
<div style="display: flex;">
|
||||||
|
<input class="text" type="text" id="name" name="name" />
|
||||||
|
<div class="buttons" style="margin-left: 5px;">
|
||||||
|
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||||
|
<input class="button submit" type="submit" value="{_add}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<table class="aui aui-table-list">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>{_admin_title}</th>
|
||||||
|
<th>{_admin_actions}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr n:foreach="$groups as $group">
|
||||||
|
<td>
|
||||||
|
<a href="/admin/chandler/groups/{$group->id}">{$group->id}</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="aui-lozenge aui-lozenge-subtle" style="text-transform: none;">
|
||||||
|
{$group->name}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a class="aui-button aui-button-primary" href="/admin/chandler/groups/{$group->id}">
|
||||||
|
<span class="aui-icon aui-icon-small aui-iconfont-new-edit">{_edit}</span>
|
||||||
|
</a>
|
||||||
|
<a class="aui-button aui-button-primary" href="/admin/chandler/groups/{$group->id}?act=permissions">
|
||||||
|
<span class="aui-icon aui-icon-small aui-iconfont-book">{_c_permissions}</span>
|
||||||
|
</a>
|
||||||
|
<a class="aui-button aui-button-primary" href="/admin/chandler/groups/{$group->id}?act=members">
|
||||||
|
<span class="aui-icon aui-icon-small aui-iconfont-group">{_members}</span>
|
||||||
|
</a>
|
||||||
|
<a class="aui-button aui-button-secondary" href="/admin/chandler/groups/{$group->id}?act=delete">
|
||||||
|
<span class="aui-icon aui-icon-small aui-iconfont-delete">{_delete}</span>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{/block}
|
|
@ -68,6 +68,43 @@
|
||||||
<option value="2" {if $user->onlineStatus() == 2}selected{/if}>{_admin_user_online_deceased}</option>
|
<option value="2" {if $user->onlineStatus() == 2}selected{/if}>{_admin_user_online_deceased}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<hr/>
|
||||||
|
<h2>{_c_groups}</h2>
|
||||||
|
<div>
|
||||||
|
<div class="field-group">
|
||||||
|
<label for="add-to-group">{_c_add_to_group}</label>
|
||||||
|
<select class="select" name="add-to-group">
|
||||||
|
<option n:foreach="$c_groups_list as $group" value="{$group->id}">
|
||||||
|
{$group->name}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<table class="aui aui-table-list">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>{_admin_actions}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr n:foreach="$c_memberships as $membership">
|
||||||
|
<td>
|
||||||
|
<a href="/admin/chandler/groups/{$membership->group}?act=members">{$membership->group}</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a
|
||||||
|
class="aui-icon aui-icon-small aui-iconfont-cross"
|
||||||
|
href="/admin/chandler/groups/{$membership->group}?act=removeMember&uid={$user->getChandlerGUID()}"
|
||||||
|
style="margin: 0 50%;"
|
||||||
|
>
|
||||||
|
{_c_remove_from_group}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="buttons-container">
|
<div class="buttons-container">
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>ID</th>
|
<th>ID</th>
|
||||||
|
<th>UUID</th>
|
||||||
<th>{_admin_name}</th>
|
<th>{_admin_name}</th>
|
||||||
<th>{_gender}</th>
|
<th>{_gender}</th>
|
||||||
<th>{_admin_shortcode}</th>
|
<th>{_admin_shortcode}</th>
|
||||||
|
@ -31,6 +32,7 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr n:foreach="$users as $user">
|
<tr n:foreach="$users as $user">
|
||||||
<td>{$user->getId()}</td>
|
<td>{$user->getId()}</td>
|
||||||
|
<td>{$user->getChandlerGUID()}</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="aui-avatar aui-avatar-xsmall">
|
<span class="aui-avatar aui-avatar-xsmall">
|
||||||
<span class="aui-avatar-inner">
|
<span class="aui-avatar-inner">
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
<input class="text long-field" type="number" min="0" id="coins" name="coins" value="{$form->coins}" />
|
<input class="text long-field" type="number" min="0" id="coins" name="coins" value="{$form->coins}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="rating">{_admin_voucher_rating}</label>
|
<label for="rating">{_admin_voucher_rating_number}</label>
|
||||||
<input class="text long-field" type="number" min="0" id="rating" name="rating" value="{$form->rating}" />
|
<input class="text long-field" type="number" min="0" id="rating" name="rating" value="{$form->rating}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
|
|
|
@ -12,6 +12,11 @@
|
||||||
{_main}
|
{_main}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="tab">
|
||||||
|
<a href="/club{$club->getId()}/backdrop">
|
||||||
|
{_backdrop_short}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
<div class="tab">
|
<div class="tab">
|
||||||
<a href="/club{$club->getId()}/followers">
|
<a href="/club{$club->getId()}/followers">
|
||||||
{_followers}
|
{_followers}
|
||||||
|
|
63
Web/Presenters/templates/Group/EditBackdrop.xml
Normal file
63
Web/Presenters/templates/Group/EditBackdrop.xml
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
{extends "../@layout.xml"}
|
||||||
|
{var $backdrops = $club->getBackDropPictureURLs()}
|
||||||
|
|
||||||
|
{block title}{$club->getName()} | {_backdrop}{/block}
|
||||||
|
|
||||||
|
{block header}
|
||||||
|
<a href="{$club->getURL()}">{$club->getName()}</a> » {_backdrop}
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block content}
|
||||||
|
<div class="tabs">
|
||||||
|
<div class="tab">
|
||||||
|
<a href="/club{$club->getId()}/edit">
|
||||||
|
{_main}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div id="activetabs" class="tab">
|
||||||
|
<a id="act_tab_a" href="/club{$club->getId()}/backdrop">
|
||||||
|
{_backdrop_short}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="tab">
|
||||||
|
<a href="/club{$club->getId()}/followers">
|
||||||
|
{_followers}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="tab">
|
||||||
|
<a href="javascript:void(0)">
|
||||||
|
{_statistics}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container_gray">
|
||||||
|
<h4>{_backdrop}</h4>
|
||||||
|
<p>{_backdrop_desc}</p>
|
||||||
|
<form method="POST" enctype="multipart/form-data">
|
||||||
|
<div id="backdropEditor">
|
||||||
|
<div id="backdropFilePicker">
|
||||||
|
<input type="file" accept="image/*" name="backdrop1" />
|
||||||
|
<div id="spacer"></div>
|
||||||
|
<input type="file" accept="image/*" name="backdrop2" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<span class="nobold">{_backdrop_warn}</span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span class="nobold">{_backdrop_about_adding}</span>
|
||||||
|
</p>
|
||||||
|
<p><br/></p>
|
||||||
|
|
||||||
|
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||||
|
<div>
|
||||||
|
<center>
|
||||||
|
<button name="subact" value="save" class="button">{_backdrop_save}</button>
|
||||||
|
<button name="subact" value="remove" class="button">{_backdrop_remove}</button>
|
||||||
|
</center>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{/block}
|
|
@ -23,6 +23,11 @@
|
||||||
{_main}
|
{_main}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="tab">
|
||||||
|
<a href="/club{$club->getId()}/backdrop">
|
||||||
|
{_backdrop_short}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
<div id="activetabs" class="tab">
|
<div id="activetabs" class="tab">
|
||||||
<a id="act_tab_a" href="/club{$club->getId()}/followers">
|
<a id="act_tab_a" href="/club{$club->getId()}/followers">
|
||||||
{_followers}
|
{_followers}
|
||||||
|
|
|
@ -12,6 +12,11 @@
|
||||||
{_main}
|
{_main}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="tab">
|
||||||
|
<a href="/club{$club->getId()}/backdrop">
|
||||||
|
{_backdrop_short}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
<div class="tab">
|
<div class="tab">
|
||||||
<a href="/club{$club->getId()}/followers">
|
<a href="/club{$club->getId()}/followers">
|
||||||
{_followers}
|
{_followers}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
{extends "../@layout.xml"}
|
{extends "../@layout.xml"}
|
||||||
|
{var $backdrops = $club->getBackDropPictureURLs()}
|
||||||
|
|
||||||
{block title}{$club->getName()}{/block}
|
{block title}{$club->getName()}{/block}
|
||||||
|
|
||||||
|
|
20
Web/Presenters/templates/Maintenance/All.xml
Normal file
20
Web/Presenters/templates/Maintenance/All.xml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{extends "../@layout.xml"}
|
||||||
|
|
||||||
|
{block title}
|
||||||
|
{_global_maintenance}
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block header}
|
||||||
|
{_global_maintenance}
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block content}
|
||||||
|
<div class="container_gray">
|
||||||
|
<center style="background: white;border: #DEDEDE solid 1px;">
|
||||||
|
<img src="/assets/packages/static/openvk/img/oof.apng" style="width: 20%;" />
|
||||||
|
<span style="color: #707070;margin: 10px 0;display: block;">
|
||||||
|
{_undergoing_global_maintenance}
|
||||||
|
</span>
|
||||||
|
</center>
|
||||||
|
</div>
|
||||||
|
{/block}
|
20
Web/Presenters/templates/Maintenance/Section.xml
Normal file
20
Web/Presenters/templates/Maintenance/Section.xml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{extends "../@layout.xml"}
|
||||||
|
|
||||||
|
{block title}
|
||||||
|
{_section_maintenance}
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block header}
|
||||||
|
{_section_maintenance}
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block content}
|
||||||
|
<div class="container_gray">
|
||||||
|
<center style="background: white;border: #DEDEDE solid 1px;">
|
||||||
|
<img src="/assets/packages/static/openvk/img/oof.apng" style="width: 20%;" />
|
||||||
|
<span style="color: #707070;margin: 10px 0;display: block;">
|
||||||
|
{tr("undergoing_section_maintenance", $name)|noescape}
|
||||||
|
</span>
|
||||||
|
</center>
|
||||||
|
</div>
|
||||||
|
{/block}
|
|
@ -24,9 +24,14 @@
|
||||||
<table class="post post-divider" border="0" style="font-size: 11px;" n:foreach="$data as $dat">
|
<table class="post post-divider" border="0" style="font-size: 11px;" n:foreach="$data as $dat">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
|
{var $sxModel = $dat->getModel(1)}
|
||||||
|
{if !(method_exists($sxModel, "getURL") && method_exists($sxModel, "getAvatarUrl"))}
|
||||||
|
{var $sxModel = $dat->getModel(0)}
|
||||||
|
{/if}
|
||||||
|
|
||||||
<td width="54" valign="top">
|
<td width="54" valign="top">
|
||||||
<a href="/sysop">
|
<a href="/{$sxModel->getURL()}">
|
||||||
<img src="{$dat->getModel(1)->getAvatarUrl('miniscule')}" width=50 />
|
<img src="{$sxModel->getAvatarUrl('miniscule')}" width=50 />
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td width="100%" valign="top">
|
<td width="100%" valign="top">
|
||||||
|
|
44
Web/Presenters/templates/Poll/Poll.xml
Normal file
44
Web/Presenters/templates/Poll/Poll.xml
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
{if !isset($parentModule) || substr($parentModule, 0, 21) === 'libchandler:absolute.'}
|
||||||
|
<link rel="shortcut icon" href="/assets/packages/static/openvk/img/icon.ico" />
|
||||||
|
<meta n:ifset="$csrfToken" name="csrf" value="{$csrfToken}" />
|
||||||
|
<script src="/language/{getLanguage()}.js" crossorigin="anonymous"></script>
|
||||||
|
{script "js/node_modules/jquery/dist/jquery.min.js"}
|
||||||
|
{script "js/node_modules/umbrellajs/umbrella.min.js"}
|
||||||
|
{script "js/node_modules/msgpack-lite/dist/msgpack.min.js"}
|
||||||
|
{script "js/messagebox.js"}
|
||||||
|
{script "js/l10n.js"}
|
||||||
|
{script "js/al_api.js"}
|
||||||
|
{script "js/al_polls.js"}
|
||||||
|
{include "../_includeCSS.xml"}
|
||||||
|
|
||||||
|
<style>body { margin: 8px; }</style>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div class="poll">
|
||||||
|
<h4>{$title}</h4>
|
||||||
|
<form onsubmit="pollFormSubmit(event, this)" data-multi="{$multiple ? '1' : '0'}" data-pid="{$id}">
|
||||||
|
<div class="poll-options">
|
||||||
|
<div n:foreach="$options as $oid => $option" class="poll-option">
|
||||||
|
<label>
|
||||||
|
{if $multiple}
|
||||||
|
<input n:attr="disabled => is_null($thisUser)" type="checkbox" name="option{$oid}" onclick="pollCheckBoxPressed(this)" />
|
||||||
|
{else}
|
||||||
|
<input n:attr="disabled => is_null($thisUser)" type="radio" value="{$oid}" name="vote" onclick="pollRadioPressed(this)" />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{$option}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{if $multiple}
|
||||||
|
<br/>
|
||||||
|
<input type="submit" class="button" value="{_cast_vote}" disabled="disabled" />
|
||||||
|
{/if}
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="poll-meta">
|
||||||
|
{tr("poll_voter_count", $votes)|noescape}<br/>
|
||||||
|
<span class="nobold">{$meta}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
56
Web/Presenters/templates/Poll/PollResults.xml
Normal file
56
Web/Presenters/templates/Poll/PollResults.xml
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
{if !isset($parentModule) || substr($parentModule, 0, 21) === 'libchandler:absolute.'}
|
||||||
|
<link rel="shortcut icon" href="/assets/packages/static/openvk/img/icon.ico" />
|
||||||
|
<meta n:ifset="$csrfToken" name="csrf" value="{$csrfToken}" />
|
||||||
|
<script src="/language/{getLanguage()}.js" crossorigin="anonymous"></script>
|
||||||
|
{script "js/node_modules/jquery/dist/jquery.min.js"}
|
||||||
|
{script "js/node_modules/umbrellajs/umbrella.min.js"}
|
||||||
|
{script "js/node_modules/msgpack-lite/dist/msgpack.min.js"}
|
||||||
|
{script "js/messagebox.js"}
|
||||||
|
{script "js/l10n.js"}
|
||||||
|
{script "js/al_api.js"}
|
||||||
|
{script "js/al_polls.js"}
|
||||||
|
{include "../_includeCSS.xml"}
|
||||||
|
|
||||||
|
<style>body { margin: 8px; } .poll { border: 1px solid #e3e3e3; }</style>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div class="poll" data-id="{$id}">
|
||||||
|
<a n:if="$unlocked && $voted" href="javascript:pollRetractVote({$id})" class="poll-retract-vote">{_retract_vote}</a>
|
||||||
|
<h4>{$title}</h4>
|
||||||
|
<div class="poll-results">
|
||||||
|
<div n:foreach="$results->options as $option" class="poll-result">
|
||||||
|
{if $isAnon}
|
||||||
|
<a href="javascript:false">
|
||||||
|
{if $option->voted}
|
||||||
|
<b>{$option->name}</b>
|
||||||
|
{else}
|
||||||
|
{$option->name}
|
||||||
|
{/if}
|
||||||
|
</a>
|
||||||
|
{else}
|
||||||
|
<a href="/poll{$id}/voters?option={base_convert($option->id, 10, 32)}">
|
||||||
|
{if $option->voted}
|
||||||
|
<b>{$option->name}</b>
|
||||||
|
{else}
|
||||||
|
{$option->name}
|
||||||
|
{/if}
|
||||||
|
</a>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div class="poll-result-barspace">
|
||||||
|
<div class="poll-result-bar">
|
||||||
|
<span class="poll-result-count">{$option->votes}</span>
|
||||||
|
<div class="poll-result-bar-sub" style="width: {$option->pct}%"> </div>
|
||||||
|
</div>
|
||||||
|
<div class="poll-result-pct">
|
||||||
|
<strong>{$option->pct}%</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="poll-meta">
|
||||||
|
{tr("poll_voter_count", $votes)|noescape}<br/>
|
||||||
|
<span class="nobold">{$meta}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
40
Web/Presenters/templates/Poll/Voters.xml
Normal file
40
Web/Presenters/templates/Poll/Voters.xml
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
{extends "../@listView.xml"}
|
||||||
|
|
||||||
|
{block title}
|
||||||
|
{_poll_voters_list}
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block header}
|
||||||
|
{_poll_voters_list} »
|
||||||
|
{$option[1]}
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block tabs}
|
||||||
|
<div n:foreach="$options as $optionId => $optionName" class="tab" id="{$optionId == $option[0] ? 'activetabs' : 'ki'}">
|
||||||
|
<a id="{$optionId == $option[0] ? 'act_tab_a' : ''}" href="/poll{$pollId}/voters?option={base_convert($optionId, 10, 32)}">{$optionName}</a>
|
||||||
|
</div>
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{* BEGIN ELEMENTS DESCRIPTION *}
|
||||||
|
|
||||||
|
{block link|strip|stripHtml}
|
||||||
|
{$x->getURL()}
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block preview}
|
||||||
|
<img src="{$x->getAvatarUrl('miniscule')}" width="75" alt="Фотография пользователя" />
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block name}
|
||||||
|
{$x->getCanonicalName()}
|
||||||
|
<img n:if="$x->isVerified()"
|
||||||
|
class="name-checkmark"
|
||||||
|
src="/assets/packages/static/openvk/img/checkmark.png"
|
||||||
|
/>
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block description}
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block actions}
|
||||||
|
{/block}
|
92
Web/Presenters/templates/Support/Agent.xml
Normal file
92
Web/Presenters/templates/Support/Agent.xml
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
{extends "../@layout.xml"}
|
||||||
|
|
||||||
|
{block header}
|
||||||
|
{_helpdesk_agent_card}
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block content}
|
||||||
|
{var $isInfo = $mode === "info"}
|
||||||
|
{var $isEdit = $mode === "edit"}
|
||||||
|
|
||||||
|
{if $agent != NULL}
|
||||||
|
<div class="left_small_block">
|
||||||
|
<img src="{$agent->getAvatarURL()}" style="width:100%;" />
|
||||||
|
<div class="profile_links">
|
||||||
|
<div n:if="$agent_id == $thisUser->getId()" id="profile_link" style="width: 194px;">
|
||||||
|
<a href="?act=edit" class="link">{_edit_page}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="right_big_block">
|
||||||
|
<div class="page_info">
|
||||||
|
<div class="accountInfo clearFix">
|
||||||
|
<a href="/id{$agent->getAgentId()}">
|
||||||
|
<div class="profileName" style="display: flex;">
|
||||||
|
<h2>{$agent->getCanonicalName()}</h2>
|
||||||
|
<span class="nobold"> ({$agent->getRealName()})</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; justify-content: space-between; padding: 10px; font-size: 12px;">
|
||||||
|
<div style="text-align: center;">
|
||||||
|
<div>
|
||||||
|
<b style="color: green;">{$counters["good"]}</b>
|
||||||
|
</div>
|
||||||
|
<div>{_helpdesk_positive_answers}</div>
|
||||||
|
</div>
|
||||||
|
<div style="text-align: center;">
|
||||||
|
<div>
|
||||||
|
<b style="color: red;">{$counters["bad"]}</b>
|
||||||
|
</div>
|
||||||
|
<div>{_helpdesk_negative_answers}</div>
|
||||||
|
</div>
|
||||||
|
<div style="text-align: center;">
|
||||||
|
<div>
|
||||||
|
<b>{$counters["all"]}</b>
|
||||||
|
</div>
|
||||||
|
<div>{_helpdesk_all_answers}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{if $isEdit}
|
||||||
|
<h4>{_edit}</h4>
|
||||||
|
<br/>
|
||||||
|
<form method="post" action="/support/agent{$agent_id}/edit">
|
||||||
|
<label for="name">{_helpdesk_showing_name}</label>
|
||||||
|
<input name="name" type="text" value="{$agent->getCanonicalName()}" placeholder="{_helpdesk_agent} #777" />
|
||||||
|
<br/><br/>
|
||||||
|
<label for="number">{_helpdesk_show_number}?</label>
|
||||||
|
{$agent->isShowNumber()}
|
||||||
|
<select name="number">
|
||||||
|
<option value="1" n:attr="selected => $agent->isShowNumber() === 1 ? true : false">{_yes}</option>
|
||||||
|
<option value="0" n:attr="selected => $agent->isShowNumber() === 0 ? true : false">{_no}</option>
|
||||||
|
</select>
|
||||||
|
<br/><br/>
|
||||||
|
<label for="number">{_avatar}</label>
|
||||||
|
<input name="avatar" type="text" value="{$agent->getAvatarURL()}" placeholder="{_helpdesk_avatar_url}" />
|
||||||
|
<input type="hidden" value="{$csrfToken}" name="hash" />
|
||||||
|
<br/><br/>
|
||||||
|
<input type="submit" class="button" value="{_save}" />
|
||||||
|
</form>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{else}
|
||||||
|
<h4>Создать</h4>
|
||||||
|
<br/>
|
||||||
|
<form method="post" action="/support/agent{$agent_id}/edit">
|
||||||
|
<label for="name">{_helpdesk_showing_name}</label>
|
||||||
|
<input name="name" type="text" placeholder="{_helpdesk_agent} #777" />
|
||||||
|
<br/><br/>
|
||||||
|
<label for="number">{_helpdesk_show_number}?</span></label>
|
||||||
|
<select name="number">
|
||||||
|
<option value="1">{_yes}</option>
|
||||||
|
<option value="0">{_no}</option>
|
||||||
|
</select>
|
||||||
|
<br/><br/>
|
||||||
|
<label for="number">{_avatar}</label>
|
||||||
|
<input name="avatar" type="text" placeholder="{_helpdesk_avatar_url}" />
|
||||||
|
<input type="hidden" value="{$csrfToken}" name="hash" />
|
||||||
|
<input type="submit" class="button" value="{_save}" />
|
||||||
|
</form>
|
||||||
|
{/if}
|
||||||
|
{/block}
|
|
@ -66,7 +66,7 @@
|
||||||
</div>
|
</div>
|
||||||
{elseif ($comment->getUType() === 1)}
|
{elseif ($comment->getUType() === 1)}
|
||||||
<div class="post-author">
|
<div class="post-author">
|
||||||
<a><b>{$comment->getAuthorName()}</b></a>
|
<a n:attr="href => $thisUser->getChandlerUser()->can('write')->model('openvk\Web\Models\Entities\TicketReply')->whichBelongsTo(0) ? '/support/agent' . $comment->getUser()->getId() : ''"><b>{$comment->getAuthorName()}</b></a>
|
||||||
{if $thisUser->getChandlerUser()->can("write")->model('openvk\Web\Models\Entities\TicketReply')->whichBelongsTo(0)}
|
{if $thisUser->getChandlerUser()->can("write")->model('openvk\Web\Models\Entities\TicketReply')->whichBelongsTo(0)}
|
||||||
<a href="{$comment->getUser()->getURL()}">
|
<a href="{$comment->getUser()->getURL()}">
|
||||||
<span class="nobold">
|
<span class="nobold">
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
<a n:attr="id => ($isNew ? 'act_tab_a' : 'ki')" href="/support?act=new">{_support_new}</a>
|
<a n:attr="id => ($isNew ? 'act_tab_a' : 'ki')" href="/support?act=new">{_support_new}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
{if $isNew}
|
{if $isNew}
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
<div n:attr="id => ($act === 'closed' ? 'activetabs' : 'ki')" class="tab">
|
<div n:attr="id => ($act === 'closed' ? 'activetabs' : 'ki')" class="tab">
|
||||||
<a n:attr="id => ($act === 'closed' ? 'act_tab_a' : 'ki')" href="?act=closed">{_support_closed}</a>
|
<a n:attr="id => ($act === 'closed' ? 'act_tab_a' : 'ki')" href="?act=closed">{_support_closed}</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="tab">
|
||||||
|
<a href="/support/agent{$thisUser->getId()}">Мой профиль</a>
|
||||||
|
</div>
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
{* BEGIN ELEMENTS DESCRIPTION *}
|
{* BEGIN ELEMENTS DESCRIPTION *}
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
{extends "../@layout.xml"}
|
{extends "../@layout.xml"}
|
||||||
|
{if $mode === 'backdrop'}
|
||||||
|
{var $backdrops = $user->getBackDropPictureURLs()}
|
||||||
|
{/if}
|
||||||
|
|
||||||
{block title}{_edit_page}{/block}
|
{block title}{_edit_page}{/block}
|
||||||
|
|
||||||
{block header}
|
{block header}
|
||||||
|
@ -6,11 +10,12 @@
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
{block content}
|
{block content}
|
||||||
|
|
||||||
{var $isMain = $mode === 'main'}
|
{var $isMain = $mode === 'main'}
|
||||||
{var $isContacts = $mode === 'contacts'}
|
{var $isContacts = $mode === 'contacts'}
|
||||||
{var $isInterests = $mode === 'interests'}
|
{var $isInterests = $mode === 'interests'}
|
||||||
{var $isAvatar = $mode === 'avatar'}
|
{var $isAvatar = $mode === 'avatar'}
|
||||||
|
{var $isBackDrop = $mode === 'backdrop'}
|
||||||
|
|
||||||
<div n:if="$user->hasPendingNumberChange()" class="msg">
|
<div n:if="$user->hasPendingNumberChange()" class="msg">
|
||||||
<b>Подтверждение номера телефона</b><br/>
|
<b>Подтверждение номера телефона</b><br/>
|
||||||
Введите код для подтверждения смены номера: <a href="/edit/verify_phone">ввести код</a>.
|
Введите код для подтверждения смены номера: <a href="/edit/verify_phone">ввести код</a>.
|
||||||
|
@ -29,6 +34,9 @@
|
||||||
<div n:attr="id => ($isAvatar ? 'activetabs' : 'ki')" class="tab">
|
<div n:attr="id => ($isAvatar ? 'activetabs' : 'ki')" class="tab">
|
||||||
<a n:attr="id => ($isAvatar ? 'act_tab_a' : 'ki')" href="/edit?act=avatar">{_avatar}</a>
|
<a n:attr="id => ($isAvatar ? 'act_tab_a' : 'ki')" href="/edit?act=avatar">{_avatar}</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div n:attr="id => ($isBackDrop ? 'activetabs' : 'ki')" class="tab">
|
||||||
|
<a n:attr="id => ($isBackDrop ? 'act_tab_a' : 'ki')" href="/edit?act=backdrop">{_backdrop_short}</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container_gray">
|
<div class="container_gray">
|
||||||
|
@ -94,7 +102,7 @@
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<select name="marialstatus">
|
<select name="marialstatus">
|
||||||
<option n:foreach="range(0, 8) as $i" n:attr="selected: ($user->getMaritalStatus() == $i)" value="{$i}">
|
<option n:foreach="range(0, 8) as $i" n:attr="selected => ($user->getMaritalStatus() == $i)" value="{$i}">
|
||||||
{if $user->isFemale()}
|
{if $user->isFemale()}
|
||||||
{var $str = "relationship_$i"}
|
{var $str = "relationship_$i"}
|
||||||
{if tr($str . "_fem") == ("@$str" . "_fem")}
|
{if tr($str . "_fem") == ("@$str" . "_fem")}
|
||||||
|
@ -326,6 +334,36 @@
|
||||||
</table>
|
</table>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
{elseif $isBackDrop}
|
||||||
|
|
||||||
|
<h4>{_backdrop}</h4>
|
||||||
|
<p>{_backdrop_desc}</p>
|
||||||
|
<form method="POST" enctype="multipart/form-data">
|
||||||
|
<div id="backdropEditor">
|
||||||
|
<div id="backdropFilePicker">
|
||||||
|
<input type="file" accept="image/*" name="backdrop1" />
|
||||||
|
<div id="spacer"></div>
|
||||||
|
<input type="file" accept="image/*" name="backdrop2" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<span class="nobold">{_backdrop_warn}</span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span class="nobold">{_backdrop_about_adding}</span>
|
||||||
|
</p>
|
||||||
|
<p><br/></p>
|
||||||
|
|
||||||
|
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||||
|
<div>
|
||||||
|
<center>
|
||||||
|
<button name="subact" value="save" class="button">{_backdrop_save}</button>
|
||||||
|
<button name="subact" value="remove" class="button">{_backdrop_remove}</button>
|
||||||
|
</center>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
<div n:attr="id => ($act === 'online' ? 'activetabs' : 'ki')" class="tab">
|
<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>
|
<a n:attr="id => ($act === 'online' ? 'act_tab_a' : 'ki')" href="?act=online">{_online}</a>
|
||||||
</div>
|
</div>
|
||||||
<div n:attr="id => ($act === 'incoming' || $act === 'outcoming' ? 'activetabs' : 'ki')" class="tab">
|
<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>
|
<a n:attr="id => ($act === 'incoming' || $act === 'outcoming' ? 'act_tab_a' : 'ki')" href="?act=incoming">{_req}</a>
|
||||||
</div>
|
</div>
|
||||||
{/block}
|
{/block}
|
||||||
|
|
|
@ -79,9 +79,9 @@
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
{block actions}
|
{block actions}
|
||||||
|
<a href="{$x->getURL()}" class="profile_link">{_check_community}</a>
|
||||||
{if $x->canBeModifiedBy($thisUser ?? NULL)}
|
{if $x->canBeModifiedBy($thisUser ?? NULL)}
|
||||||
{var $clubPinned = $thisUser->isClubPinned($x)}
|
{var $clubPinned = $thisUser->isClubPinned($x)}
|
||||||
<a href="{$x->getURL()}" class="profile_link">{_check_community}</a>
|
|
||||||
<a href="/groups_pin?club={$x->getId()}&hash={rawurlencode($csrfToken)}" class="profile_link" n:if="$clubPinned || $thisUser->getPinnedClubCount() <= 10" id="_pinGroup" data-group-name="{$x->getName()}" data-group-url="{$x->getUrl()}">
|
<a href="/groups_pin?club={$x->getId()}&hash={rawurlencode($csrfToken)}" class="profile_link" n:if="$clubPinned || $thisUser->getPinnedClubCount() <= 10" id="_pinGroup" data-group-name="{$x->getName()}" data-group-url="{$x->getUrl()}">
|
||||||
{if $clubPinned}
|
{if $clubPinned}
|
||||||
{_remove_from_left_menu}
|
{_remove_from_left_menu}
|
||||||
|
@ -89,6 +89,7 @@
|
||||||
{_add_to_left_menu}
|
{_add_to_left_menu}
|
||||||
{/if}
|
{/if}
|
||||||
</a>
|
</a>
|
||||||
|
{/if}
|
||||||
{if $x->getSubscriptionStatus($thisUser) == false}
|
{if $x->getSubscriptionStatus($thisUser) == false}
|
||||||
<form class="profile_link_form" action="/setSub/club" method="post">
|
<form class="profile_link_form" action="/setSub/club" method="post">
|
||||||
<input type="hidden" name="act" value="add" />
|
<input type="hidden" name="act" value="add" />
|
||||||
|
@ -104,7 +105,6 @@
|
||||||
<input type="submit" class="profile_link" value="{_leave_community}" />
|
<input type="submit" class="profile_link" value="{_leave_community}" />
|
||||||
</form>
|
</form>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
{block bottom}
|
{block bottom}
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
{extends "../@layout.xml"}
|
{extends "../@layout.xml"}
|
||||||
|
|
||||||
|
{if !$user->isBanned()}
|
||||||
|
{var $backdrops = $user->getBackDropPictureURLs()}
|
||||||
|
{/if}
|
||||||
|
|
||||||
{block title}{$user->getCanonicalName()}{/block}
|
{block title}{$user->getCanonicalName()}{/block}
|
||||||
|
|
||||||
{block headIncludes}
|
{block headIncludes}
|
||||||
|
@ -60,7 +64,7 @@
|
||||||
{else}
|
{else}
|
||||||
|
|
||||||
<div class="left_small_block">
|
<div class="left_small_block">
|
||||||
<div>
|
<div style="margin-left: auto;margin-right: auto;display: table;">
|
||||||
<a href="{$user->getAvatarLink()|nocheck}">
|
<a href="{$user->getAvatarLink()|nocheck}">
|
||||||
<img src="{$user->getAvatarUrl('normal')}"
|
<img src="{$user->getAvatarUrl('normal')}"
|
||||||
alt="{$user->getCanonicalName()}"
|
alt="{$user->getCanonicalName()}"
|
||||||
|
@ -77,25 +81,25 @@
|
||||||
</div>
|
</div>
|
||||||
{else}
|
{else}
|
||||||
{if $thisUser->getChandlerUser()->can("substitute")->model('openvk\Web\Models\Entities\User')->whichBelongsTo(0)}
|
{if $thisUser->getChandlerUser()->can("substitute")->model('openvk\Web\Models\Entities\User')->whichBelongsTo(0)}
|
||||||
<a href="/setSID/{$user->getChandlerUser()->getId()}?hash={rawurlencode($csrfToken)}" class="profile_link">
|
<a href="/setSID/{$user->getChandlerUser()->getId()}?hash={rawurlencode($csrfToken)}" class="profile_link" style="width: 194px;">
|
||||||
{tr("login_as", $user->getFirstName())}
|
{tr("login_as", $user->getFirstName())}
|
||||||
</a>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{if $thisUser->getChandlerUser()->can("access")->model("admin")->whichBelongsTo(NULL)}
|
{if $thisUser->getChandlerUser()->can("access")->model("admin")->whichBelongsTo(NULL)}
|
||||||
<a href="/admin/users/id{$user->getId()}" class="profile_link">
|
<a href="/admin/users/id{$user->getId()}" class="profile_link" style="width: 194px;">
|
||||||
{_manage_user_action}
|
{_manage_user_action}
|
||||||
</a>
|
</a>
|
||||||
<a href="javascript:banUser()" class="profile_link">
|
<a href="javascript:banUser()" class="profile_link" style="width: 194px;">
|
||||||
{_ban_user_action}
|
{_ban_user_action}
|
||||||
</a>
|
</a>
|
||||||
<a href="javascript:warnUser()" class="profile_link">
|
<a href="javascript:warnUser()" class="profile_link" style="width: 194px;">
|
||||||
{_warn_user_action}
|
{_warn_user_action}
|
||||||
</a>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{if $thisUser->getChandlerUser()->can('write')->model('openvk\Web\Models\Entities\TicketReply')->whichBelongsTo(0)}
|
{if $thisUser->getChandlerUser()->can('write')->model('openvk\Web\Models\Entities\TicketReply')->whichBelongsTo(0)}
|
||||||
<a href="javascript:toggleBanInSupport()" class="profile_link">
|
<a href="javascript:toggleBanInSupport()" class="profile_link" style="width: 194px;">
|
||||||
{if $user->isBannedInSupport()}
|
{if $user->isBannedInSupport()}
|
||||||
{_unban_in_support_user_action}
|
{_unban_in_support_user_action}
|
||||||
{else}
|
{else}
|
||||||
|
@ -104,8 +108,8 @@
|
||||||
</a>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<a n:if="OPENVK_ROOT_CONF['openvk']['preferences']['commerce'] && $user->getGiftCount() == 0" href="/gifts?act=pick&user={$user->getId()}" class="profile_link">{_send_gift}</a>
|
<a style="width: 194px;" n:if="OPENVK_ROOT_CONF['openvk']['preferences']['commerce'] && $user->getGiftCount() == 0" href="/gifts?act=pick&user={$user->getId()}" class="profile_link">{_send_gift}</a>
|
||||||
<a n:if="$user->getPrivacyPermission('messages.write', $thisUser)" href="/im?sel={$user->getId()}" class="profile_link">{_send_message}</a>
|
<a style="width: 194px;" n:if="$user->getPrivacyPermission('messages.write', $thisUser)" href="/im?sel={$user->getId()}" class="profile_link">{_send_message}</a>
|
||||||
|
|
||||||
{var $subStatus = $user->getSubscriptionStatus($thisUser)}
|
{var $subStatus = $user->getSubscriptionStatus($thisUser)}
|
||||||
{if $subStatus === 0}
|
{if $subStatus === 0}
|
||||||
|
@ -113,32 +117,32 @@
|
||||||
<input type="hidden" name="act" value="add" />
|
<input type="hidden" name="act" value="add" />
|
||||||
<input type="hidden" name="id" value="{$user->getId()}" />
|
<input type="hidden" name="id" value="{$user->getId()}" />
|
||||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||||
<input type="submit" class="profile_link" value="{_friends_add}" />
|
<input type="submit" class="profile_link" value="{_friends_add}" style="width: 194px;" />
|
||||||
</form>
|
</form>
|
||||||
{elseif $subStatus === 1}
|
{elseif $subStatus === 1}
|
||||||
<form action="/setSub/user" method="post" class="profile_link_form">
|
<form action="/setSub/user" method="post" class="profile_link_form">
|
||||||
<input type="hidden" name="act" value="add" />
|
<input type="hidden" name="act" value="add" />
|
||||||
<input type="hidden" name="id" value="{$user->getId()}" />
|
<input type="hidden" name="id" value="{$user->getId()}" />
|
||||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||||
<input type="submit" class="profile_link" value="{_friends_accept}" />
|
<input type="submit" class="profile_link" value="{_friends_accept}" style="width: 194px;" />
|
||||||
</form>
|
</form>
|
||||||
{elseif $subStatus === 2}
|
{elseif $subStatus === 2}
|
||||||
<form action="/setSub/user" method="post" class="profile_link_form">
|
<form action="/setSub/user" method="post" class="profile_link_form">
|
||||||
<input type="hidden" name="act" value="rem" />
|
<input type="hidden" name="act" value="rem" />
|
||||||
<input type="hidden" name="id" value="{$user->getId()}" />
|
<input type="hidden" name="id" value="{$user->getId()}" />
|
||||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||||
<input type="submit" class="profile_link" value="{_friends_reject}" />
|
<input type="submit" class="profile_link" value="{_friends_reject}" style="width: 194px;" />
|
||||||
</form>
|
</form>
|
||||||
{elseif $subStatus === 3}
|
{elseif $subStatus === 3}
|
||||||
<form action="/setSub/user" method="post" class="profile_link_form">
|
<form action="/setSub/user" method="post" class="profile_link_form">
|
||||||
<input type="hidden" name="act" value="rem" />
|
<input type="hidden" name="act" value="rem" />
|
||||||
<input type="hidden" name="id" value="{$user->getId()}" />
|
<input type="hidden" name="id" value="{$user->getId()}" />
|
||||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||||
<input type="submit" class="profile_link" value="{_friends_delete}" />
|
<input type="submit" class="profile_link" value="{_friends_delete}" style="width: 194px;" />
|
||||||
</form>
|
</form>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
<a n:if="$user->getFollowersCount() > 0" href="/friends{$user->getId()}?act=incoming" class="profile_link">{tr("followers", $user->getFollowersCount())}</a>
|
<a style="width: 194px;" n:if="$user->getFollowersCount() > 0" href="/friends{$user->getId()}?act=incoming" class="profile_link">{tr("followers", $user->getFollowersCount())}</a>
|
||||||
</div>
|
</div>
|
||||||
<div n:if="isset($thisUser) && !$thisUser->prefersNotToSeeRating()" class="profile-hints">
|
<div n:if="isset($thisUser) && !$thisUser->prefersNotToSeeRating()" class="profile-hints">
|
||||||
{var $completeness = $user->getProfileCompletenessReport()}
|
{var $completeness = $user->getProfileCompletenessReport()}
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
<div style="width: 100%; min-height: 100px;">
|
<div style="width: 100%; min-height: 100px;">
|
||||||
<div style="float: left; min-height: 100px; width: 70%;">
|
<div style="float: left; min-height: 100px; width: 68%; margin-right: 2%;">
|
||||||
{include "../components/comments.xml",
|
{include "../components/comments.xml",
|
||||||
comments => $comments,
|
comments => $comments,
|
||||||
count => $cCount,
|
count => $cCount,
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div n:class="postFeedWrapper, $thisUser->hasMicroblogEnabled() ? postFeedWrapperMicroblog">
|
<div n:class="postFeedWrapper, $thisUser->hasMicroblogEnabled() ? postFeedWrapperMicroblog">
|
||||||
{include "../components/textArea.xml", route => "/wall" . $thisUser->getId() . "/makePost"}
|
{include "../components/textArea.xml", route => "/wall" . $thisUser->getId() . "/makePost", graffiti => true, polls => true}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{foreach $posts as $post}
|
{foreach $posts as $post}
|
||||||
|
|
52
Web/Presenters/templates/_includeCSS.xml
Normal file
52
Web/Presenters/templates/_includeCSS.xml
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
{ifset $thisUser}
|
||||||
|
{if $thisUser->getNsfwTolerance() < 2}
|
||||||
|
{css "css/nsfw-posts.css"}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{if $theme !== NULL}
|
||||||
|
{if $theme->inheritDefault()}
|
||||||
|
{css "css/style.css"}
|
||||||
|
{css "css/dialog.css"}
|
||||||
|
{css "css/notifications.css"}
|
||||||
|
|
||||||
|
{if $isXmas}
|
||||||
|
{css "css/xmas.css"}
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/themepack/{$theme->getId()}/{$theme->getVersion()}/stylesheet/styles.css" />
|
||||||
|
|
||||||
|
{if $isXmas}
|
||||||
|
<link rel="stylesheet" href="/themepack/{$theme->getId()}/{$theme->getVersion()}/resource/xmas.css" />
|
||||||
|
{/if}
|
||||||
|
{else}
|
||||||
|
{css "css/style.css"}
|
||||||
|
{css "css/dialog.css"}
|
||||||
|
{css "css/notifications.css"}
|
||||||
|
|
||||||
|
{if $isXmas}
|
||||||
|
{css "css/xmas.css"}
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{if $thisUser->getStyleAvatar() == 1}
|
||||||
|
{css "css/avatar.1.css"}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{if $thisUser->getStyleAvatar() == 2}
|
||||||
|
{css "css/avatar.2.css"}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{if $thisUser->hasMicroblogEnabled() == 1}
|
||||||
|
{css "css/microblog.css"}
|
||||||
|
{/if}
|
||||||
|
{else}
|
||||||
|
{css "css/style.css"}
|
||||||
|
{css "css/dialog.css"}
|
||||||
|
{css "css/nsfw-posts.css"}
|
||||||
|
{css "css/notifications.css"}
|
||||||
|
|
||||||
|
{if $isXmas}
|
||||||
|
{css "css/xmas.css"}
|
||||||
|
{/if}
|
||||||
|
{/ifset}
|
|
@ -11,6 +11,8 @@
|
||||||
{/if}
|
{/if}
|
||||||
{elseif $attachment instanceof \openvk\Web\Models\Entities\Video}
|
{elseif $attachment instanceof \openvk\Web\Models\Entities\Video}
|
||||||
<video class="media" src="{$attachment->getURL()}" controls="controls"></video>
|
<video class="media" src="{$attachment->getURL()}" controls="controls"></video>
|
||||||
|
{elseif $attachment instanceof \openvk\Web\Models\Entities\Poll}
|
||||||
|
{presenter "openvk!Poll->view", $attachment->getId()}
|
||||||
{elseif $attachment instanceof \openvk\Web\Models\Entities\Post}
|
{elseif $attachment instanceof \openvk\Web\Models\Entities\Post}
|
||||||
{php $GLOBALS["_nesAttGloCou"] = (isset($GLOBALS["_nesAttGloCou"]) ? $GLOBALS["_nesAttGloCou"] : 0) + 1}
|
{php $GLOBALS["_nesAttGloCou"] = (isset($GLOBALS["_nesAttGloCou"]) ? $GLOBALS["_nesAttGloCou"] : 0) + 1}
|
||||||
{if $GLOBALS["_nesAttGloCou"] > 2}
|
{if $GLOBALS["_nesAttGloCou"] > 2}
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
{var $user = $notification->getModel(0)}
|
||||||
|
{var $post = $notification->getModel(1)}
|
||||||
|
|
||||||
|
{_nt_you_were_mentioned_u} <a href="{$user->getURL()}"><b>{$user->getCanonicalName()}</b></a> {$notification->getDateTime()} <a href="/note{$post->getPrettyId()}"><b>{_nt_mention_in_note}</b></a>: "{$notification->getData()}"
|
|
@ -0,0 +1,4 @@
|
||||||
|
{var $user = $notification->getModel(0)}
|
||||||
|
{var $post = $notification->getModel(1)}
|
||||||
|
|
||||||
|
{_nt_you_were_mentioned_u} <a href="{$user->getURL()}"><b>{$user->getCanonicalName()}</b></a> {$notification->getDateTime()} <a href="/photo{$post->getURL()}"><b>{_nt_mention_in_photo}</b></a>: "{$notification->getData()}"
|
|
@ -0,0 +1,4 @@
|
||||||
|
{var $user = $notification->getModel(0)}
|
||||||
|
{var $post = $notification->getModel(1)}
|
||||||
|
|
||||||
|
{_nt_you_were_mentioned_u} <a href="{$user->getURL()}"><b>{$user->getCanonicalName()}</b></a> {$notification->getDateTime()} <a href="/wall{$post->getPrettyId()}"><b>{_nt_mention_in_post_or_comms}</b></a>: "{$notification->getData()}"
|
|
@ -0,0 +1,4 @@
|
||||||
|
{var $user = $notification->getModel(0)}
|
||||||
|
{var $post = $notification->getModel(1)}
|
||||||
|
|
||||||
|
{_nt_you_were_mentioned_u} <a href="{$user->getURL()}"><b>{$user->getCanonicalName()}</b></a> {$notification->getDateTime()} <a href="/video{$post->getPrettyId()}"><b>{_nt_mention_in_video}</b></a>: "{$notification->getData()}"
|
|
@ -0,0 +1,4 @@
|
||||||
|
{var $user = $notification->getModel(0)}
|
||||||
|
{var $post = $notification->getModel(1)}
|
||||||
|
|
||||||
|
{_nt_you_were_mentioned_u} <a href="{$user->getURL()}"><b>{$user->getCanonicalName()}</b></a> {$notification->getDateTime()} <a href="/topic{$post->getPrettyId()}"><b>{_nt_mention_in_topic}</b></a>: "{$notification->getData()}"
|
|
@ -0,0 +1,4 @@
|
||||||
|
{var $user = $notification->getModel(0)}
|
||||||
|
{var $post = $notification->getModel(1)}
|
||||||
|
|
||||||
|
{_nt_you_were_mentioned_g} <a href="{$user->getURL()}"><b>{$user->getCanonicalName()}</b></a> {$notification->getDateTime()} <a href="/note{$post->getPrettyId()}"><b>{_nt_mention_in_note}</b></a>: "{$notification->getData()}"
|
|
@ -0,0 +1,4 @@
|
||||||
|
{var $user = $notification->getModel(0)}
|
||||||
|
{var $post = $notification->getModel(1)}
|
||||||
|
|
||||||
|
{_nt_you_were_mentioned_g} <a href="{$user->getURL()}"><b>{$user->getCanonicalName()}</b></a> {$notification->getDateTime()} <a href="/photo{$post->getURL()}"><b>{_nt_mention_in_photo}</b></a>: "{$notification->getData()}"
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue