mirror of
https://github.com/openvk/openvk
synced 2025-02-13 18:23:09 +03:00
Merge branch 'master' into banned-links-fixed
This commit is contained in:
commit
2e8cb81970
483 changed files with 47733 additions and 11470 deletions
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
|
@ -1 +1 @@
|
|||
custom: "https://openvk.su/donate"
|
||||
custom: "https://ovk.to/donate"
|
||||
|
|
21
.github/workflows/build-base.yaml
vendored
21
.github/workflows/build-base.yaml
vendored
|
@ -2,11 +2,12 @@ name: Build base images
|
|||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
- cron: "0 0 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
BASE_IMAGE_NAME: php
|
||||
BASE_IMAGE_VERSION: "8.1"
|
||||
BASE_IMAGE_VERSION: "8.2"
|
||||
|
||||
jobs:
|
||||
build-cli:
|
||||
|
@ -24,12 +25,18 @@ jobs:
|
|||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Change repository string to lowercase
|
||||
id: repositorystring
|
||||
uses: Entepotenz/change-string-case-action-min-dependencies@v1.1.0
|
||||
with:
|
||||
string: ${{ github.repository }}
|
||||
|
||||
- name: Log into registry
|
||||
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
||||
|
||||
- name: Build cli image
|
||||
run: |
|
||||
IMAGE_NAME=ghcr.io/${{ github.repository }}/$BASE_IMAGE_NAME:$BASE_IMAGE_VERSION-cli
|
||||
IMAGE_NAME=ghcr.io/${{ steps.repositorystring.outputs.lowercase }}/$BASE_IMAGE_NAME:$BASE_IMAGE_VERSION-cli
|
||||
|
||||
docker buildx build --platform linux/amd64,linux/arm64 -t $IMAGE_NAME . --push -f install/automated/docker/base-php-cli.Dockerfile --build-arg VERSION=$BASE_IMAGE_VERSION
|
||||
|
||||
|
@ -48,11 +55,17 @@ jobs:
|
|||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Change repository string to lowercase
|
||||
id: repositorystring
|
||||
uses: Entepotenz/change-string-case-action-min-dependencies@v1.1.0
|
||||
with:
|
||||
string: ${{ github.repository }}
|
||||
|
||||
- name: Log into registry
|
||||
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
||||
|
||||
- name: Build apache image
|
||||
run: |
|
||||
IMAGE_NAME=ghcr.io/${{ github.repository }}/$BASE_IMAGE_NAME:$BASE_IMAGE_VERSION-apache
|
||||
IMAGE_NAME=ghcr.io/${{ steps.repositorystring.outputs.lowercase }}/$BASE_IMAGE_NAME:$BASE_IMAGE_VERSION-apache
|
||||
|
||||
docker buildx build --platform linux/amd64,linux/arm64 -t $IMAGE_NAME . --push -f install/automated/docker/base-php-apache.Dockerfile --build-arg VERSION=$BASE_IMAGE_VERSION
|
||||
|
|
166
.github/workflows/build.yaml
vendored
166
.github/workflows/build.yaml
vendored
|
@ -1,64 +1,154 @@
|
|||
name: Build images
|
||||
|
||||
on:
|
||||
push:
|
||||
# Publish `master` as Docker `latest` image.
|
||||
branches:
|
||||
- master
|
||||
|
||||
# Publish `v1.2.3` tags as releases.
|
||||
tags:
|
||||
- v*
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
BASE_IMAGE_NAME: openvk
|
||||
DB_IMAGE_NAME: mariadb
|
||||
EVENT_IMAGE_NAME: mariadb
|
||||
DB_VERSION: "10.9"
|
||||
DB_VERSION: '10.9'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
buildbase:
|
||||
name: Build base images
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
arch: ['x86_64']
|
||||
|
||||
if: github.event_name == 'push'
|
||||
# 'push' runs on inner branches, 'pull_request' will run only on outer PRs
|
||||
if: >
|
||||
github.event_name == 'push'
|
||||
|| (github.event_name == 'pull_request'
|
||||
&& github.event.pull_request.head.repo.full_name != github.repository)
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
lfs: false
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
||||
- name: Change repository string to lowercase
|
||||
id: repositorystring
|
||||
uses: Entepotenz/change-string-case-action-min-dependencies@v1.1.0
|
||||
with:
|
||||
string: ${{ github.repository }}
|
||||
|
||||
- name: Base image meta
|
||||
id: basemeta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
ghcr.io/${{ steps.repositorystring.outputs.lowercase }}/${{env.BASE_IMAGE_NAME}}
|
||||
labels: |
|
||||
org.opencontainers.image.documentation=https://github.com/OpenVK/openvk/blob/master/install/automated/docker/Readme.md
|
||||
tags: |
|
||||
type=sha
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=ref,event=tag
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
|
||||
- name: Log into registry
|
||||
if: github.event_name != 'pull_request'
|
||||
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
||||
|
||||
- name: Build base image
|
||||
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
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
file: install/automated/docker/openvk.Dockerfile
|
||||
tags: ${{ steps.basemeta.outputs.tags }}
|
||||
labels: ${{ steps.basemeta.outputs.labels }}
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
build-args: |
|
||||
GITREPO=${{ steps.repositorystring.outputs.lowercase }}
|
||||
|
||||
docker buildx build --platform linux/amd64,linux/arm64 -t $IMAGE_ID:$VERSION . --push -f install/automated/docker/openvk.Dockerfile --build-arg GITREPO=${{ github.repository }}
|
||||
builddb:
|
||||
name: Build DB images
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# 'push' runs on inner branches, 'pull_request' will run only on outer PRs
|
||||
if: >
|
||||
github.event_name == 'push'
|
||||
|| (github.event_name == 'pull_request'
|
||||
&& github.event.pull_request.head.repo.full_name != github.repository)
|
||||
|
||||
steps:
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
||||
- name: Change repository string to lowercase
|
||||
id: repositorystring
|
||||
uses: Entepotenz/change-string-case-action-min-dependencies@v1.1.0
|
||||
with:
|
||||
string: ${{ github.repository }}
|
||||
|
||||
- name: MariaDB primary meta
|
||||
id: db-primarymeta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
ghcr.io/${{ steps.repositorystring.outputs.lowercase }}/${{env.DB_IMAGE_NAME}}
|
||||
labels: |
|
||||
org.opencontainers.image.title=OpenVK MariaDB (Primary)
|
||||
org.opencontainers.image.description=OpenVK's image for MariaDB for primary database.
|
||||
org.opencontainers.image.documentation=https://github.com/OpenVK/openvk/blob/master/install/automated/docker/Readme.md
|
||||
tags: |
|
||||
type=sha,prefix=${{env.DB_VERSION}}-primary-sha-
|
||||
type=ref,event=branch,prefix=${{env.DB_VERSION}}-primary-
|
||||
type=ref,event=pr,prefix=${{env.DB_VERSION}}-primary-pr-
|
||||
type=ref,event=tag,prefix=${{env.DB_VERSION}}-primary-
|
||||
type=raw,value=${{env.DB_VERSION}}-primary,enable={{is_default_branch}}
|
||||
|
||||
- name: MariaDB event meta
|
||||
id: db-eventmeta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
ghcr.io/${{ steps.repositorystring.outputs.lowercase }}/${{env.DB_IMAGE_NAME}}
|
||||
labels: |
|
||||
org.opencontainers.image.title=OpenVK MariaDB (EventDB)
|
||||
org.opencontainers.image.description=OpenVK's image for MariaDB for event database.
|
||||
org.opencontainers.image.documentation=https://github.com/OpenVK/openvk/blob/master/install/automated/docker/Readme.md
|
||||
tags: |
|
||||
type=sha,prefix=${{env.DB_VERSION}}-eventdb-sha-
|
||||
type=ref,event=branch,prefix=${{env.DB_VERSION}}-eventdb-
|
||||
type=ref,event=pr,prefix=${{env.DB_VERSION}}-eventdb-pr-
|
||||
type=ref,event=tag,prefix=${{env.DB_VERSION}}-eventdb-
|
||||
type=raw,value=${{env.DB_VERSION}}-eventdb,enable={{is_default_branch}}
|
||||
|
||||
- name: Log into registry
|
||||
if: github.event_name != 'pull_request'
|
||||
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
||||
|
||||
- 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
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
file: install/automated/docker/mariadb-primary.Dockerfile
|
||||
tags: ${{ steps.db-primarymeta.outputs.tags }}
|
||||
labels: ${{ steps.db-primarymeta.outputs.labels }}
|
||||
build-args: |
|
||||
VERSION=${{env.DB_VERSION}}
|
||||
|
||||
- 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
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
file: install/automated/docker/mariadb-eventdb.Dockerfile
|
||||
tags: ${{ steps.db-eventmeta.outputs.tags }}
|
||||
labels: ${{ steps.db-eventmeta.outputs.labels }}
|
||||
build-args: |
|
||||
VERSION=${{env.DB_VERSION}}
|
||||
|
|
35
.github/workflows/lint.yaml
vendored
Normal file
35
.github/workflows/lint.yaml
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
name: Lint
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
# 'push' runs on inner branches, 'pull_request' will run only on outer PRs
|
||||
if: >
|
||||
github.event_name == 'push'
|
||||
|| (github.event_name == 'pull_request'
|
||||
&& github.event.pull_request.head.repo.full_name != github.repository)
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Code Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: "8.2"
|
||||
extensions: gd, zip, intl, yaml, pdo_mysql, rdkafka, imagick
|
||||
tools: composer:v2
|
||||
coverage: none
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer install --no-interaction --no-progress --no-suggest --prefer-dist
|
||||
|
||||
- name: PHP CS Fixer
|
||||
run: vendor/bin/php-cs-fixer fix --dry-run --diff
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -16,3 +16,4 @@ storage/*
|
|||
!storage/.gitkeep
|
||||
|
||||
.idea
|
||||
.php-cs-fixer.cache
|
||||
|
|
15
.php-cs-fixer.dist.php
Normal file
15
.php-cs-fixer.dist.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
$finder = (new PhpCsFixer\Finder())
|
||||
->in(__DIR__)
|
||||
->name('openvkctl')
|
||||
;
|
||||
|
||||
return (new PhpCsFixer\Config())
|
||||
->setRules([
|
||||
'@PER-CS2.0' => true,
|
||||
'@PHP82Migration' => true,
|
||||
])
|
||||
->setFinder($finder)
|
||||
->setParallelConfig(PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect())
|
||||
;
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\CLI;
|
||||
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
use openvk\Web\Models\Repositories\Users;
|
||||
use openvk\Web\Models\Entities\Notifications\CoinsTransferNotification;
|
||||
|
@ -17,7 +21,7 @@ class FetchToncoinTransactions extends Command
|
|||
|
||||
protected static $defaultName = "fetch-ton";
|
||||
|
||||
function __construct()
|
||||
public function __construct()
|
||||
{
|
||||
$this->transactions = DatabaseConnection::i()->getContext()->table("cryptotransactions");
|
||||
|
||||
|
@ -40,7 +44,7 @@ class FetchToncoinTransactions extends Command
|
|||
"",
|
||||
]);
|
||||
|
||||
if(!OPENVK_ROOT_CONF["openvk"]["preferences"]["ton"]["enabled"]) {
|
||||
if (!OPENVK_ROOT_CONF["openvk"]["preferences"]["ton"]["enabled"]) {
|
||||
$header->writeln("Sorry, but you handn't enabled the TON support in your config file yet.");
|
||||
|
||||
return Command::FAILURE;
|
||||
|
@ -52,45 +56,45 @@ class FetchToncoinTransactions extends Command
|
|||
$opts = [
|
||||
"http" => [
|
||||
"method" => "GET",
|
||||
"header" => "Accept: application/json"
|
||||
]
|
||||
"header" => "Accept: application/json",
|
||||
],
|
||||
];
|
||||
|
||||
$selection = $this->transactions->select('hash, lt')->order("id DESC")->limit(1)->fetch();
|
||||
$trHash = $selection->hash ?? NULL;
|
||||
$trLt = $selection->lt ?? NULL;
|
||||
$trHash = $selection->hash ?? null;
|
||||
$trLt = $selection->lt ?? null;
|
||||
|
||||
$data = http_build_query([
|
||||
"address" => OPENVK_ROOT_CONF["openvk"]["preferences"]["ton"]["address"],
|
||||
"limit" => 100,
|
||||
"hash" => $trHash,
|
||||
"to_lt" => $trLt
|
||||
"to_lt" => $trLt,
|
||||
]);
|
||||
|
||||
$response = file_get_contents($url . $data, false, stream_context_create($opts));
|
||||
$response = json_decode($response, true);
|
||||
|
||||
$header->writeln("Gonna up the balance of users");
|
||||
foreach($response["result"] as $transfer) {
|
||||
foreach ($response["result"] as $transfer) {
|
||||
$outputArray;
|
||||
preg_match('/' . OPENVK_ROOT_CONF["openvk"]["preferences"]["ton"]["regex"] . '/', $transfer["in_msg"]["message"], $outputArray);
|
||||
$userId = ctype_digit($outputArray[1]) ? intval($outputArray[1]) : NULL;
|
||||
if(is_null($userId)) {
|
||||
$userId = ctype_digit($outputArray[1]) ? intval($outputArray[1]) : null;
|
||||
if (is_null($userId)) {
|
||||
$header->writeln("Well, that's a donation. Thanks! XD");
|
||||
} else {
|
||||
$user = (new Users)->get($userId);
|
||||
if(!$user) {
|
||||
$user = (new Users())->get($userId);
|
||||
if (!$user) {
|
||||
$header->writeln("Well, that's a donation. Thanks! XD");
|
||||
} else {
|
||||
$value = ($transfer["in_msg"]["value"] / NANOTON) / OPENVK_ROOT_CONF["openvk"]["preferences"]["ton"]["rate"];
|
||||
$user->setCoins($user->getCoins() + $value);
|
||||
$user->save();
|
||||
(new CoinsTransferNotification($user, (new Users)->get(OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["adminAccount"]), (int) $value, "Via TON cryptocurrency"))->emit();
|
||||
(new CoinsTransferNotification($user, (new Users())->get(OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["adminAccount"]), (int) $value, "Via TON cryptocurrency"))->emit();
|
||||
$header->writeln($value . " coins are added to " . $user->getId() . " user id");
|
||||
$this->transactions->insert([
|
||||
"id" => NULL,
|
||||
"id" => null,
|
||||
"hash" => $transfer["transaction_id"]["hash"],
|
||||
"lt" => $transfer["transaction_id"]["lt"]
|
||||
"lt" => $transfer["transaction_id"]["lt"],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\CLI;
|
||||
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
use openvk\Web\Models\Repositories\Photos;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
|
@ -14,7 +18,7 @@ class RebuildImagesCommand extends Command
|
|||
|
||||
protected static $defaultName = "build-images";
|
||||
|
||||
function __construct()
|
||||
public function __construct()
|
||||
{
|
||||
$this->images = DatabaseConnection::i()->getContext()->table("photos");
|
||||
|
||||
|
@ -40,8 +44,9 @@ class RebuildImagesCommand extends Command
|
|||
]);
|
||||
|
||||
$filter = ["deleted" => false];
|
||||
if($input->getOption("upgrade-only"))
|
||||
$filter["sizes"] = NULL;
|
||||
if ($input->getOption("upgrade-only")) {
|
||||
$filter["sizes"] = null;
|
||||
}
|
||||
|
||||
$selection = $this->images->select("id")->where($filter);
|
||||
$totalPics = $selection->count();
|
||||
|
@ -52,24 +57,25 @@ class RebuildImagesCommand extends Command
|
|||
|
||||
$errors = 0;
|
||||
$count = 0;
|
||||
$avgTime = NULL;
|
||||
$avgTime = null;
|
||||
$begin = new \DateTimeImmutable("now");
|
||||
foreach($selection as $idHolder) {
|
||||
foreach ($selection as $idHolder) {
|
||||
$start = microtime(true);
|
||||
|
||||
try {
|
||||
$photo = (new Photos)->get($idHolder->id);
|
||||
$photo = (new Photos())->get($idHolder->id);
|
||||
$photo->getSizes(true, true);
|
||||
$photo->getDimensions();
|
||||
} catch(ImageException $ex) {
|
||||
} catch (ImageException $ex) {
|
||||
$errors++;
|
||||
}
|
||||
|
||||
$timeConsumed = microtime(true) - $start;
|
||||
if(!$avgTime)
|
||||
if (!$avgTime) {
|
||||
$avgTime = $timeConsumed;
|
||||
else
|
||||
} else {
|
||||
$avgTime = ($avgTime + $timeConsumed) / 2;
|
||||
}
|
||||
|
||||
$eta = $begin->getTimestamp() + ceil($totalPics * $avgTime);
|
||||
$int = (new \DateTimeImmutable("now"))->diff(new \DateTimeImmutable("@$eta"));
|
||||
|
|
277
CODE_STYLE.md
277
CODE_STYLE.md
|
@ -1,277 +0,0 @@
|
|||
# Names
|
||||
## Namespace Names
|
||||
Namespaces should be written in PascalCase.
|
||||
|
||||
## File Names
|
||||
Code directories should have their name written in PascalCase. Code files should contain only one class and have the name of that class.
|
||||
In case of multiple class definitions in one file, it's name should be the same as the "primary" class name.
|
||||
Non-code directories, non-class and non-code files should be named in lisp-case.
|
||||
|
||||
## Variable Names
|
||||
Variable names should be written in camelCase. This also applies to function arguments, class instance names and methods.
|
||||
|
||||
## Constant Names
|
||||
Constants are written in SCREAMING_SNAKE_CASE, but should be declared case-insensetive.
|
||||
|
||||
## Class Names
|
||||
Classes in OpenVK should belong to `openvk\` namespace and be in the corresponding directory (according to PSR-4). Names of classes should be written in PascalCase.
|
||||
|
||||
## Function Names
|
||||
camelCase and snake_case are allowed, but first one is the recommended way. This rule does not apply to class methods, which are written in camelCase only.
|
||||
|
||||
---
|
||||
|
||||
# Coding Rules
|
||||
## File header
|
||||
All OpenVK files must start with `<?php` open-tag followed by `declare(strict_types=1);` on the same line. The next line must contain namespace.
|
||||
The lines after must contain use-declarations, each on it's own line (usage of {} operator is OK), if there is any. Then there must be an empty line. Example:
|
||||
```php
|
||||
<?php declare(strict_types=1);
|
||||
namespace openvk;
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
use Nette\Utils\{Image, FileSystem};
|
||||
|
||||
class ...
|
||||
```
|
||||
|
||||
## NULL
|
||||
Null should be written as constant, all-uppercase: `NULL`.
|
||||
|
||||
## Nullable (optional) pointer arguments
|
||||
Optional pointer arguments should default to `nullptr`: `function something(&int? $myPointer = nullptr)`. `nullptr` must be written in lisp-case (lowercase).
|
||||
|
||||
## Comparing to NULL
|
||||
In OpenVK `is_null` is the preferred way to check for equality to NULL. `??` must be used in assignments and where else possible.
|
||||
In case if value can either be NULL or truthy, "boolean not" should be used to check if value is not null: `if(!$var)`.
|
||||
|
||||
## Arrays
|
||||
Arrays must be defined with modern syntax: `[1, 2, 3]` (NOT `array(1, 2, 3)`).
|
||||
Same applies to `list` construction: use `[$a, , $b] = $arr;` instead of `list($a, , $b) = $arr;`
|
||||
|
||||
## Casts
|
||||
Typecasts must be done with modern syntax where possible: `(type) $var`. Int-to-string, string-to-int, etc conversions should also be dont with modern casting
|
||||
syntax where possible, but should use `ctype_` functions where needed. `gettype`, `settype` should be used in dynamic programming only.
|
||||
|
||||
## Goto
|
||||
```goto``` should be avoided.
|
||||
|
||||
## `continue n; `
|
||||
It is preferable to use `continue n`, `break n` instead of guarding flags:
|
||||
```php
|
||||
# COOL AND GOOD
|
||||
foreach($a as $b)
|
||||
foreach($b as $c)
|
||||
if($b == $c)
|
||||
break 2;
|
||||
|
||||
# BRUH
|
||||
foreach($a as $b) {
|
||||
$shouldBreak = false;
|
||||
foreach($b as $c)
|
||||
if($b == $c)
|
||||
$shouldBreak = true;
|
||||
|
||||
if($shouldBreak)
|
||||
break;
|
||||
}
|
||||
```
|
||||
|
||||
## Comments
|
||||
In OpenVK we use Perl-style `#` for single-line comments.
|
||||
|
||||
---
|
||||
|
||||
# Formatting
|
||||
## Variables
|
||||
It is preferable to declare only one variable per line in the code.
|
||||
|
||||
## Indentation
|
||||
All things in OpenVK must be properly indented by a sequence of 4 spaces. Not tabs. \
|
||||
When there are several variable declarations listed together, line up the variables:
|
||||
```php
|
||||
# OK
|
||||
$photos = (new Photos)->where("meow", true);
|
||||
$photo = $photos->fetch();
|
||||
$arr = [
|
||||
"a" => 10,
|
||||
"bb" => true,
|
||||
];
|
||||
|
||||
# NOT OK
|
||||
$photos = (new Photos)->where("meow", true);
|
||||
$photo = $photos->fetch();
|
||||
$arr = [
|
||||
"a" => 10,
|
||||
"bb" => true,
|
||||
];
|
||||
```
|
||||
|
||||
## Tab/Space
|
||||
+ **Do not use tabs**. Use spaces, as tabs are defined differently for different editors and printers.
|
||||
+ Put one space after a comma and semicolons: `exp(1, 2)` `for($i = 1; $i < 100; $i++)`
|
||||
+ Put one space around assignment operators: `$a = 1`
|
||||
+ Always put a space around conditional operators: `$a = ($a > $b) ? $a : $b`
|
||||
+ Do not put spaces between unary operators and their operands, primary operators and keywords:
|
||||
```php
|
||||
# OK
|
||||
-$a;
|
||||
$a++;
|
||||
$b[1] = $a;
|
||||
fun($b);
|
||||
if($a) { ... }
|
||||
|
||||
# NOT OK
|
||||
- $a;
|
||||
$a ++;
|
||||
$b [1] = $a;
|
||||
fun ($b);
|
||||
if ($a) { ... }
|
||||
```
|
||||
|
||||
## Blank Lines
|
||||
+ Use blank lines to create paragraphs in the code or comments to make the code more understandable
|
||||
+ Use blank lines before `return` statement if it isn't the only statement in the block
|
||||
+ Use blank lines after shorthand if/else/etc
|
||||
```php
|
||||
# OK
|
||||
if($a)
|
||||
return $x;
|
||||
|
||||
doSomething();
|
||||
|
||||
return "yay";
|
||||
|
||||
# NOT OK
|
||||
if($a) return $x; # return must be on separate line
|
||||
doSomething(); # doSomething must be separated by an extra blank line after short if/else
|
||||
return "yay"; # do use blank lines before return statement
|
||||
```
|
||||
|
||||
|
||||
## Method/Function Arguments
|
||||
+ When all arguments for a function do not fit on one line, try to line up the first argument in each line:
|
||||
![image](https://user-images.githubusercontent.com/34442450/167248563-21fb01be-181d-48b9-ac0c-dc953c0a12cf.png)
|
||||
|
||||
+ If the argument lists are still too long to fit on the line, you may line up the arguments with the method name instead.
|
||||
|
||||
## Maximum characters per line
|
||||
Lines should be no more than 80 characters long.
|
||||
|
||||
## Usage of curly braces
|
||||
+ Curly braces should be on separate line for class, method, and function definitions.
|
||||
+ In loops, if/else, try/catch, switch constructions the opening brace should be on the same line as the operator.
|
||||
+ Braces must be ommited if the block contains only one statement **AND** the related blocks are also single statemented.
|
||||
+ Nested single-statement+operator blocks must not be surrounded by braces.
|
||||
```php
|
||||
# OK
|
||||
class A
|
||||
{
|
||||
function doSomethingFunny(): int
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
if(true) {
|
||||
doSomething();
|
||||
doSomethingElse();
|
||||
} else {
|
||||
doSomethingFunny();
|
||||
}
|
||||
|
||||
if($a)
|
||||
return false;
|
||||
else
|
||||
doSomething();
|
||||
|
||||
foreach($b as $c => $d)
|
||||
if($c == $d)
|
||||
unset($b[$c]);
|
||||
|
||||
# NOT OK
|
||||
class A {
|
||||
function doSomethingFunny(): int {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
if(true) {
|
||||
doSomething();
|
||||
doSomethingElse();
|
||||
} else
|
||||
doSomethingFunny(); # why?
|
||||
|
||||
if($a) {
|
||||
return false;
|
||||
} else {
|
||||
doSomething();
|
||||
}
|
||||
|
||||
foreach($b as $c => $d) {
|
||||
if($c == $d)
|
||||
unset($b[$c]);
|
||||
}
|
||||
|
||||
# lmao
|
||||
if($a) { doSomething(); } else doSomethingElse();
|
||||
```
|
||||
|
||||
## if/else, try/catch
|
||||
+ Operators must not be indented with space from their operands but must have 1-space margin from braces:
|
||||
```php
|
||||
# OK
|
||||
if($a) {
|
||||
doSomething();
|
||||
doSomethingElse();
|
||||
} else if($b) {
|
||||
try {
|
||||
nukeSaintPetersburg('😈');
|
||||
} finally {
|
||||
return PEACE;
|
||||
}
|
||||
}
|
||||
|
||||
# NOT OK
|
||||
if ($a) { # do not add space between control flow operator IF and it's operand
|
||||
doSomething();
|
||||
doSomethingElse();
|
||||
}elseif($b){ # do add margin from braces; also ELSE and IF should be separate here
|
||||
try{
|
||||
nukeSaintPetersburg('😈');
|
||||
}finally{
|
||||
return PEACE;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Switches
|
||||
+ `break` must be on same indentation level as the code of le case (not the case definiton itself)
|
||||
+ If there is no need to `break` a comment `# NOTICE falling through` must be places instead
|
||||
```php
|
||||
# OK
|
||||
switch($a) {
|
||||
case 1:
|
||||
echo $a;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
echo $a++;
|
||||
# NOTICE falling through
|
||||
|
||||
default:
|
||||
echo "c";
|
||||
}
|
||||
|
||||
# NOT OK
|
||||
switch($a) {
|
||||
case 1:
|
||||
echo $a;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
echo $a++;
|
||||
|
||||
default:
|
||||
echo "c";
|
||||
}
|
||||
```
|
148
DBEntity.updated.php
Normal file
148
DBEntity.updated.php
Normal file
|
@ -0,0 +1,148 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chandler\Database;
|
||||
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
use Nette\Database\Table\Selection;
|
||||
use Nette\Database\Table\ActiveRow;
|
||||
use Nette\InvalidStateException as ISE;
|
||||
use openvk\Web\Models\Repositories\CurrentUser;
|
||||
use openvk\Web\Models\Repositories\Logs;
|
||||
|
||||
abstract class DBEntity
|
||||
{
|
||||
use \Nette\SmartObject;
|
||||
protected $record;
|
||||
protected $changes;
|
||||
protected $deleted;
|
||||
protected $user;
|
||||
|
||||
protected $tableName;
|
||||
|
||||
public function __construct(?ActiveRow $row = null)
|
||||
{
|
||||
if (is_null($row)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$_table = $row->getTable()->getName();
|
||||
if ($_table !== $this->tableName) {
|
||||
throw new ISE("Invalid data supplied for model: table $_table is not compatible with table" . $this->tableName);
|
||||
}
|
||||
|
||||
$this->record = $row;
|
||||
}
|
||||
|
||||
public function __call(string $fName, array $args)
|
||||
{
|
||||
if (substr($fName, 0, 3) === "set") {
|
||||
$field = mb_strtolower(substr($fName, 3));
|
||||
$this->stateChanges($field, $args[0]);
|
||||
} else {
|
||||
throw new \Error("Call to undefined method " . get_class($this) . "::$fName");
|
||||
}
|
||||
}
|
||||
|
||||
private function getTable(): Selection
|
||||
{
|
||||
return DatabaseConnection::i()->getContext()->table($this->tableName);
|
||||
}
|
||||
|
||||
protected function getRecord(): ?ActiveRow
|
||||
{
|
||||
return $this->record;
|
||||
}
|
||||
|
||||
protected function stateChanges(string $column, $value): void
|
||||
{
|
||||
if (!is_null($this->record)) {
|
||||
$t = $this->record->{$column};
|
||||
} #Test if column exists
|
||||
|
||||
$this->changes[$column] = $value;
|
||||
}
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return $this->getRecord()->id;
|
||||
}
|
||||
|
||||
public function isDeleted(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->deleted;
|
||||
}
|
||||
|
||||
public function unwrap(): object
|
||||
{
|
||||
return (object) $this->getRecord()->toArray();
|
||||
}
|
||||
|
||||
public function delete(bool $softly = true): void
|
||||
{
|
||||
$user = CurrentUser::i()->getUser();
|
||||
$user_id = is_null($user) ? (int) OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["adminAccount"] : $user->getId();
|
||||
|
||||
if (is_null($this->record)) {
|
||||
throw new ISE("Can't delete a model, that hasn't been flushed to DB. Have you forgotten to call save() first?");
|
||||
}
|
||||
|
||||
(new Logs())->create($user_id, $this->getTable()->getName(), get_class($this), 2, $this->record->toArray(), $this->changes);
|
||||
|
||||
if ($softly) {
|
||||
$this->record = $this->getTable()->where("id", $this->record->id)->update(["deleted" => true]);
|
||||
} else {
|
||||
$this->record->delete();
|
||||
$this->deleted = true;
|
||||
}
|
||||
}
|
||||
|
||||
public function undelete(): void
|
||||
{
|
||||
if (is_null($this->record)) {
|
||||
throw new ISE("Can't undelete a model, that hasn't been flushed to DB. Have you forgotten to call save() first?");
|
||||
}
|
||||
|
||||
$user = CurrentUser::i()->getUser();
|
||||
$user_id = is_null($user) ? (int) OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["adminAccount"] : $user->getId();
|
||||
|
||||
(new Logs())->create($user_id, $this->getTable()->getName(), get_class($this), 3, $this->record->toArray(), ["deleted" => false]);
|
||||
|
||||
$this->getTable()->where("id", $this->record->id)->update(["deleted" => false]);
|
||||
}
|
||||
|
||||
public function save(?bool $log = true): void
|
||||
{
|
||||
if ($log) {
|
||||
$user = CurrentUser::i();
|
||||
$user_id = is_null($user) ? (int) OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["adminAccount"] : $user->getUser()->getId();
|
||||
}
|
||||
|
||||
if (is_null($this->record)) {
|
||||
$this->record = $this->getTable()->insert($this->changes);
|
||||
|
||||
if ($log && $this->getTable()->getName() !== "logs") {
|
||||
(new Logs())->create($user_id, $this->getTable()->getName(), get_class($this), 0, $this->record->toArray(), $this->changes);
|
||||
}
|
||||
} else {
|
||||
if ($log && $this->getTable()->getName() !== "logs") {
|
||||
(new Logs())->create($user_id, $this->getTable()->getName(), get_class($this), 1, $this->record->toArray(), $this->changes);
|
||||
}
|
||||
|
||||
if ($this->deleted) {
|
||||
$this->record = $this->getTable()->insert((array) $this->record);
|
||||
} else {
|
||||
$this->getTable()->get($this->record->id)->update($this->changes);
|
||||
$this->record = $this->getTable()->get($this->record->id);
|
||||
}
|
||||
}
|
||||
|
||||
$this->changes = [];
|
||||
}
|
||||
|
||||
public function getTableName(): string
|
||||
{
|
||||
return $this->getTable()->getName();
|
||||
}
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 9.7 KiB |
|
@ -53,9 +53,6 @@
|
|||
<table class="row">
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<img src="pictures/lock.jpeg" align="center" class="float-center" width=128 height=128 />
|
||||
</center>
|
||||
|
||||
<table class="spacer">
|
||||
<tr>
|
||||
|
@ -94,7 +91,7 @@
|
|||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<a href="http://{$_SERVER['HTTP_HOST']}/settings/change_email?key={rawurlencode($key)}" align="center" class="float-center">Подтвердить Email!</a>
|
||||
<a href="https://{$_SERVER['HTTP_HOST']}/settings/change_email?key={rawurlencode($key)}" align="center" class="float-center">Подтвердить Email!</a>
|
||||
</center>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -118,8 +115,8 @@
|
|||
<table class="callout">
|
||||
<tr>
|
||||
<th class="callout-inner primary">
|
||||
<a href="http://{$_SERVER['HTTP_HOST']}/settings/change_email?key={$key}" style="color: #000; text-decoration: none;">
|
||||
http://{$_SERVER['HTTP_HOST']}/settings/change_email?key={$key}
|
||||
<a href="https://{$_SERVER['HTTP_HOST']}/settings/change_email?key={$key}" style="color: #000; text-decoration: none;">
|
||||
https://{$_SERVER['HTTP_HOST']}/settings/change_email?key={$key}
|
||||
</a>
|
||||
</th>
|
||||
</tr>
|
||||
|
@ -130,7 +127,7 @@
|
|||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Передавать другим людям (даже друзьям, питомцам, соседам, любимым девушкам)</li>
|
||||
<li>Передавать другим людям (даже друзьям, питомцам, соседям, любимым девушкам)</li>
|
||||
<li>Использовать, если прошло более двух дней с её генерации</li>
|
||||
</ul>
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<tr>
|
||||
<td class="float-center" align="center" valign="top">
|
||||
<center>
|
||||
Добро пожаловать в OpenVK! Приятного времяприпровождения, надеюсь вам понравится.<br><br>Если появились вопросы, касаемые нашего сайта, пишите <a href="https://openvk.su/support?act=new">сюда</a>
|
||||
Добро пожаловать в OpenVK! Приятного времяприпровождения, надеюсь вам понравится.<br><br>Если появились вопросы, касаемые нашего сайта, пишите <a href="https://{$_SERVER['HTTP_HOST']}/support?act=new">сюда</a>
|
||||
</center>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -53,9 +53,6 @@
|
|||
<table class="row">
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<img src="pictures/lock.jpeg" align="center" class="float-center" width=128 height=128 />
|
||||
</center>
|
||||
|
||||
<table class="spacer">
|
||||
<tr>
|
||||
|
@ -94,7 +91,7 @@
|
|||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<a href="http://{$_SERVER['HTTP_HOST']}/restore?act=finish&key={rawurlencode($key)}" align="center" class="float-center">Сбросить пароль!</a>
|
||||
<a href="https://{$_SERVER['HTTP_HOST']}/restore?act=finish&key={rawurlencode($key)}" align="center" class="float-center">Сбросить пароль!</a>
|
||||
</center>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -118,8 +115,8 @@
|
|||
<table class="callout">
|
||||
<tr>
|
||||
<th class="callout-inner primary">
|
||||
<a href="http://{$_SERVER['HTTP_HOST']}/restore?act=finish&key={$key}" style="color: #000; text-decoration: none;">
|
||||
http://{$_SERVER['HTTP_HOST']}/restore?act=finish&key={$key}
|
||||
<a href="https://{$_SERVER['HTTP_HOST']}/restore?act=finish&key={$key}" style="color: #000; text-decoration: none;">
|
||||
https://{$_SERVER['HTTP_HOST']}/restore?act=finish&key={$key}
|
||||
</a>
|
||||
</th>
|
||||
</tr>
|
||||
|
@ -130,7 +127,7 @@
|
|||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Передавать другим людям (даже друзьям, питомцам, соседам, любимым девушкам)</li>
|
||||
<li>Передавать другим людям (даже друзьям, питомцам, соседям, любимым девушкам)</li>
|
||||
<li>Использовать, если прошло более двух дней с её генерации</li>
|
||||
</ul>
|
||||
|
||||
|
|
|
@ -53,9 +53,6 @@
|
|||
<table class="row">
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<img src="pictures/lock.jpeg" align="center" class="float-center" width=128 height=128 />
|
||||
</center>
|
||||
|
||||
<table class="spacer">
|
||||
<tr>
|
||||
|
@ -94,7 +91,7 @@
|
|||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<a href="http://{$_SERVER['HTTP_HOST']}/regFinish?key={rawurlencode($key)}" align="center" class="float-center">Подтвердить Email!</a>
|
||||
<a href="https://{$_SERVER['HTTP_HOST']}/regFinish?key={rawurlencode($key)}" align="center" class="float-center">Подтвердить Email!</a>
|
||||
</center>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -118,8 +115,8 @@
|
|||
<table class="callout">
|
||||
<tr>
|
||||
<th class="callout-inner primary">
|
||||
<a href="http://{$_SERVER['HTTP_HOST']}/regFinish?key={$key}" style="color: #000; text-decoration: none;">
|
||||
http://{$_SERVER['HTTP_HOST']}/regFinish?key={$key}
|
||||
<a href="https://{$_SERVER['HTTP_HOST']}/regFinish?key={$key}" style="color: #000; text-decoration: none;">
|
||||
https://{$_SERVER['HTTP_HOST']}/regFinish?key={$key}
|
||||
</a>
|
||||
</th>
|
||||
</tr>
|
||||
|
@ -130,7 +127,7 @@
|
|||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Передавать другим людям (даже друзьям, питомцам, соседам, любимым девушкам)</li>
|
||||
<li>Передавать другим людям (даже друзьям, питомцам, соседям, любимым девушкам)</li>
|
||||
<li>Использовать, если прошло более двух дней с её генерации</li>
|
||||
</ul>
|
||||
|
||||
|
|
30
README.md
30
README.md
|
@ -1,12 +1,14 @@
|
|||
# <img align="right" src="https://github.com/openvk/openvk/raw/master/Web/static/img/logo_shadow.png" alt="openvk" title="openvk" width="15%">OpenVK
|
||||
# <img align="right" src="/Web/static/img/logo_shadow.png" alt="openvk" title="openvk" width="15%">OpenVK
|
||||
|
||||
_[Русский](README_RU.md)_
|
||||
|
||||
**OpenVK** is an attempt to create a simple CMS that ~~cosplays~~ imitates old VKontakte. Code provided here is not stable yet.
|
||||
|
||||
VKontakte belongs to Pavel Durov and VK Group.
|
||||
This is fan project, not affiliated in any way with VKontakte and it's company VK Ltd. Below is the same message in russian.
|
||||
|
||||
To be honest, we don't know whether if it even works. However, this version is maintained and we will be happy to accept your bugreports [in our bug tracker](https://github.com/openvk/openvk/projects/1). You should also be able to submit them using [ticketing system](https://openvk.su/support?act=new) (you will need an OpenVK account for this).
|
||||
OpenVK является любительской разработкой и никак не связан с ВКонтакте и компанией ООО "VK"
|
||||
|
||||
To be honest, we don't know whether if it even works. However, this version is maintained and we will be happy to accept your bugreports [in our bug tracker](https://github.com/openvk/openvk/projects/1). You should also be able to submit them using [ticketing system](https://ovk.to/support?act=new) (you will need an OpenVK account for this).
|
||||
|
||||
## When's the release?
|
||||
|
||||
|
@ -26,11 +28,19 @@ However, OVK makes use of Chandler Application Server. This software requires ex
|
|||
|
||||
If you want, you can add your instance to the list above so that people can register there.
|
||||
|
||||
### System requirements
|
||||
|
||||
Here is our minimum hardware recommendation:
|
||||
|
||||
* **CPU: Recent** (AMD Zen2 or equivalent) quad-core 2GHz+ CPU
|
||||
* **RAM:** At least 2GB RAM (we recommend 6GB or 8GB for OpenVK with Kafka)
|
||||
* **Minimum database space:** 10GB
|
||||
|
||||
### Installation procedure
|
||||
|
||||
1. Install PHP 7.4, web-server, Composer, Node.js, Yarn and [Chandler](https://github.com/openvk/chandler)
|
||||
1. Install PHP 8.2, web-server, Composer, Node.js, NPM and [Chandler](https://github.com/openvk/chandler)
|
||||
|
||||
* PHP 8.1 is supported too, however it was not tested carefully, so be aware.
|
||||
* PHP 8 is still being tested; the functionality of the engine on this version of PHP is not yet guaranteed.
|
||||
|
||||
2. Install MySQL-compatible database.
|
||||
|
||||
|
@ -57,7 +67,7 @@ ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions
|
|||
7. Copy `openvk-example.yml` to `openvk.yml` and change options to your liking
|
||||
8. Run `composer install` in OpenVK directory
|
||||
9. Run `composer install` in commitcaptcha directory
|
||||
10. Move to `Web/static/js` and execute `yarn install`
|
||||
10. Move to `Web/static/js` and execute `npm install`
|
||||
11. Set `openvk` as your root app in `chandler.yml`
|
||||
|
||||
Once you are done, you can login as a system administrator on the network itself (no registration required):
|
||||
|
@ -66,12 +76,12 @@ Once you are done, you can login as a system administrator on the network itself
|
|||
* **Password**: `admin`
|
||||
* It is recommended to change the password of the built-in account or disable it.
|
||||
|
||||
💡Confused? Full installation walkthrough is available [here](https://docs.openvk.uk/openvk_engine/centos8_installation/) (CentOS 8 [and](https://almalinux.org/) [family](https://yum.oracle.com/oracle-linux-isos.html)).
|
||||
💡 Confused? Full installation walkthrough is available [here](https://docs.ovk.to/openvk_engine/centos8_installation/) (CentOS 8 [and](https://almalinux.org/) [family](https://yum.oracle.com/oracle-linux-isos.html)).
|
||||
|
||||
### Looking for Docker or Kubernetes deployment?
|
||||
See `install/automated/docker/README.md` and `install/automated/kubernetes/README.md` for Docker and Kubernetes deployment instructions.
|
||||
|
||||
### If my website uses OpenVK, should I release it's sources?
|
||||
### If my website uses OpenVK, should I release its sources?
|
||||
|
||||
It depends. You can keep the sources to yourself if you do not plan to distribute your website binaries. If your website software must be distributed, it can stay non-OSS provided the OpenVK is not used as a primary application and is not modified. If you modified OpenVK for your needs or your work is based on it and you are planning to redistribute this, then you should license it under terms of any LGPL-compatible license (like OSL, GPL, LGPL etc).
|
||||
|
||||
|
@ -80,13 +90,13 @@ It depends. You can keep the sources to yourself if you do not plan to distribut
|
|||
You may reach out to us via:
|
||||
|
||||
* [Bug Tracker](https://github.com/openvk/openvk/projects/1)
|
||||
* [Ticketing System](https://openvk.su/support?act=new)
|
||||
* [Ticketing System](https://ovk.to/support?act=new)
|
||||
* Telegram Chat: Go to [our channel](https://t.me/openvkenglish) and open discussion in our channel menu.
|
||||
* [Reddit](https://www.reddit.com/r/openvk/)
|
||||
* [GitHub Discussions](https://github.com/openvk/openvk/discussions)
|
||||
* Matrix Chat: #openvk:matrix.org
|
||||
|
||||
**Attention**: bug tracker, board, Telegram and Matrix chat are public places, ticketing system is being served by volunteers. If you need to report something that should not be immediately disclosed to general public (for instance, a vulnerability), please contact us directly via this email: **openvk [at] tutanota [dot] com**
|
||||
**Attention**: bug tracker, board, Telegram and Matrix chat are public places, ticketing system is being served by volunteers. If you need to report something that should not be immediately disclosed to general public (for instance, a vulnerability), please contact us directly via this email: **contact [at] ovk [dot] to**
|
||||
|
||||
<a href="https://codeberg.org/OpenVK/openvk">
|
||||
<img alt="Get it on Codeberg" src="https://codeberg.org/Codeberg/GetItOnCodeberg/media/branch/main/get-it-on-blue-on-white.png" height="60">
|
||||
|
|
16
README_RU.md
16
README_RU.md
|
@ -1,12 +1,12 @@
|
|||
# <img align="right" src="https://github.com/openvk/openvk/raw/master/Web/static/img/logo_shadow.png" alt="openvk" title="openvk" width="15%">OpenVK
|
||||
# <img align="right" src="/Web/static/img/logo_shadow.png" alt="openvk" title="openvk" width="15%">OpenVK
|
||||
|
||||
_[English](README.md)_
|
||||
|
||||
**OpenVK** — это попытка создать простую CMS, которая ~~косплеит~~ имитирует старый ВКонтакте. На данный момент, представленный здесь исходный код проекта пока не является стабильным.
|
||||
|
||||
ВКонтакте принадлежит Павлу Дурову и VK Group.
|
||||
**OpenVK является любительской разработкой и никак не связан с ВКонтакте и компанией ООО "ВК"**
|
||||
|
||||
Честно говоря, мы даже не знаем, работает ли она вообще. Однако, эта версия поддерживается, и мы будем рады принять ваши сообщения об ошибках [в нашем баг-трекере](https://github.com/openvk/openvk/projects/1). Вы также можете отправлять их через [вкладку "Помощь"](https://openvk.su/support?act=new) (для этого вам понадобится учетная запись OpenVK).
|
||||
Честно говоря, мы даже не знаем, работает ли она вообще. Однако, эта версия поддерживается, и мы будем рады принять ваши сообщения об ошибках [в нашем баг-трекере](https://github.com/openvk/openvk/projects/1). Вы также можете отправлять их через [вкладку "Помощь"](https://ovk.to/support?act=new) (для этого вам понадобится учетная запись OpenVK).
|
||||
|
||||
## Когда выйдет релизная версия?
|
||||
|
||||
|
@ -28,9 +28,9 @@ _[English](README.md)_
|
|||
|
||||
### Процедура установки
|
||||
|
||||
1. Установите PHP 7.4, веб-сервер, Composer, Node.js, Yarn и [Chandler](https://github.com/openvk/chandler)
|
||||
1. Установите PHP 8.2, веб-сервер, Composer, Node.js, NPM и [Chandler](https://github.com/openvk/chandler)
|
||||
|
||||
* PHP 8 еще **не** тестировался, поэтому не стоит ожидать, что он будет работать (UPD: он не работает).
|
||||
* PHP 8 пока ещё тестируется, работоспособность движка на этой версии PHP пока не гарантируется.
|
||||
|
||||
2. Установите MySQL-совместимую базу данных.
|
||||
|
||||
|
@ -57,7 +57,7 @@ ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions
|
|||
7. Скопируйте `openvk-example.yml` в `openvk.yml` и измените параметры под свои нужды
|
||||
8. Запустите `composer install` в директории OpenVK
|
||||
9. Запустите `composer install` в директории commitcaptcha
|
||||
10. Перейдите в `Web/static/js` и выполните `yarn install`
|
||||
10. Перейдите в `Web/static/js` и выполните `npm install`
|
||||
11. Установите `openvk` в качестве корневого приложения в файле `chandler.yml`
|
||||
|
||||
После этого вы можете войти как системный администратор в саму сеть (регистрация не требуется):
|
||||
|
@ -66,7 +66,7 @@ ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions
|
|||
* **Пароль**: `admin`
|
||||
* Перед использованием встроенной учетной записи рекомендуется сменить пароль или отключить её.
|
||||
|
||||
💡Запутались? Полное руководство по установке доступно [здесь](https://docs.openvk.uk/openvk_engine/centos8_installation/) (CentOS 8 [и](https://almalinux.org/ru/) [семейство](https://yum.oracle.com/oracle-linux-isos.html)).
|
||||
💡Запутались? Полное руководство по установке доступно [здесь](https://docs.ovk.to/openvk_engine/centos8_installation/) (CentOS 8 [и](https://almalinux.org/ru/) [семейство](https://yum.oracle.com/oracle-linux-isos.html)).
|
||||
|
||||
# Установка в Docker/Kubernetes
|
||||
Подробные иструкции можно найти в `install/automated/docker/README.md` и `install/automated/kubernetes/README.md` соответственно.
|
||||
|
@ -80,7 +80,7 @@ ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions
|
|||
Вы можете связаться с нами через:
|
||||
|
||||
* [Баг-трекер](https://github.com/openvk/openvk/projects/1)
|
||||
* [Помощь в OVK](https://openvk.su/support?act=new)
|
||||
* [Помощь в OVK](https://ovk.to/support?act=new)
|
||||
* Telegram-чат: Перейдите на [наш канал](https://t.me/openvk) и откройте обсуждение в меню нашего канала.
|
||||
* [Reddit](https://www.reddit.com/r/openvk/)
|
||||
* [GitHub Discussions](https://github.com/openvk/openvk/discussions)
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\ServiceAPI;
|
||||
|
||||
use openvk\Web\Models\Entities\APIToken;
|
||||
use openvk\Web\Models\Entities\User;
|
||||
use openvk\Web\Models\Repositories\APITokens;
|
||||
use openvk\Web\Models\Repositories\Applications;
|
||||
use WhichBrowser;
|
||||
|
||||
class Apps implements Handler
|
||||
{
|
||||
|
@ -12,10 +18,10 @@ class Apps implements Handler
|
|||
public function __construct(?User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->apps = new Applications;
|
||||
$this->apps = new Applications();
|
||||
}
|
||||
|
||||
function getUserInfo(callable $resolve, callable $reject): void
|
||||
public function getUserInfo(callable $resolve, callable $reject): void
|
||||
{
|
||||
$hexId = dechex($this->user->getId());
|
||||
$sign = hash_hmac("sha512/224", $hexId, CHANDLER_ROOT_CONF["security"]["secret"], true);
|
||||
|
@ -33,35 +39,36 @@ class Apps implements Handler
|
|||
]);
|
||||
}
|
||||
|
||||
function updatePermission(int $app, string $perm, string $state, callable $resolve, callable $reject): void
|
||||
public function updatePermission(int $app, string $perm, string $state, callable $resolve, callable $reject): void
|
||||
{
|
||||
$app = $this->apps->get($app);
|
||||
if(!$app || !$app->isEnabled()) {
|
||||
if (!$app || !$app->isEnabled()) {
|
||||
$reject("No application with this id found");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!$app->setPermission($this->user, $perm, $state == "yes"))
|
||||
if (!$app->setPermission($this->user, $perm, $state == "yes")) {
|
||||
$reject("Invalid permission $perm");
|
||||
}
|
||||
|
||||
$resolve(1);
|
||||
}
|
||||
|
||||
function pay(int $appId, float $amount, callable $resolve, callable $reject): void
|
||||
public function pay(int $appId, float $amount, callable $resolve, callable $reject): void
|
||||
{
|
||||
$app = $this->apps->get($appId);
|
||||
if(!$app || !$app->isEnabled()) {
|
||||
if (!$app || !$app->isEnabled()) {
|
||||
$reject("No application with this id found");
|
||||
return;
|
||||
}
|
||||
|
||||
if($amount < 0) {
|
||||
if ($amount < 0) {
|
||||
$reject(552, "Payment amount is invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
$coinsLeft = $this->user->getCoins() - $amount;
|
||||
if($coinsLeft < 0) {
|
||||
if ($coinsLeft < 0) {
|
||||
$reject(41, "Not enough money");
|
||||
return;
|
||||
}
|
||||
|
@ -74,13 +81,13 @@ class Apps implements Handler
|
|||
$resolve($t . "," . hash_hmac("whirlpool", "$appId:$amount:$t", CHANDLER_ROOT_CONF["security"]["secret"]));
|
||||
}
|
||||
|
||||
function withdrawFunds(int $appId, callable $resolve, callable $reject): void
|
||||
public function withdrawFunds(int $appId, callable $resolve, callable $reject): void
|
||||
{
|
||||
$app = $this->apps->get($appId);
|
||||
if(!$app) {
|
||||
if (!$app) {
|
||||
$reject("No application with this id found");
|
||||
return;
|
||||
} else if($app->getOwner()->getId() != $this->user->getId()) {
|
||||
} elseif ($app->getOwner()->getId() != $this->user->getId()) {
|
||||
$reject("You don't have rights to edit this app");
|
||||
return;
|
||||
}
|
||||
|
@ -89,4 +96,26 @@ class Apps implements Handler
|
|||
$app->withdrawCoins();
|
||||
$resolve($coins);
|
||||
}
|
||||
|
||||
public function getRegularToken(string $clientName, bool $acceptsStale, callable $resolve, callable $reject): void
|
||||
{
|
||||
$token = null;
|
||||
$stale = true;
|
||||
if ($acceptsStale) {
|
||||
$token = (new APITokens())->getStaleByUser($this->user->getId(), $clientName);
|
||||
}
|
||||
|
||||
if (is_null($token)) {
|
||||
$stale = false;
|
||||
$token = new APIToken();
|
||||
$token->setUser($this->user);
|
||||
$token->setPlatform($clientName ?? (new WhichBrowser\Parser(getallheaders()))->toString());
|
||||
$token->save();
|
||||
}
|
||||
|
||||
$resolve([
|
||||
'is_stale' => $stale,
|
||||
'token' => $token->getFormattedToken(),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\ServiceAPI;
|
||||
|
||||
use openvk\Web\Models\Entities\User;
|
||||
use openvk\Web\Models\Repositories\Clubs;
|
||||
|
||||
|
@ -8,29 +12,29 @@ class Groups implements Handler
|
|||
protected $user;
|
||||
protected $groups;
|
||||
|
||||
function __construct(?User $user)
|
||||
public function __construct(?User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->groups = new Clubs;
|
||||
$this->groups = new Clubs();
|
||||
}
|
||||
|
||||
function getWriteableClubs(callable $resolve, callable $reject)
|
||||
public function getWriteableClubs(callable $resolve, callable $reject)
|
||||
{
|
||||
$clubs = [];
|
||||
$wclubs = $this->groups->getWriteableClubs($this->user->getId());
|
||||
$count = $this->groups->getWriteableClubsCount($this->user->getId());
|
||||
|
||||
if(!$count) {
|
||||
if (!$count) {
|
||||
$reject("You don't have any groups with write access");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach($wclubs as $club) {
|
||||
foreach ($wclubs as $club) {
|
||||
$clubs[] = [
|
||||
"name" => $club->getName(),
|
||||
"id" => $club->getId(),
|
||||
"avatar" => $club->getAvatarUrl() # если в овк когда-нибудь появится крутой список с аватарками, то можно использовать это поле
|
||||
"avatar" => $club->getAvatarUrl(), # если в овк когда-нибудь появится крутой список с аватарками, то можно использовать это поле
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\ServiceAPI;
|
||||
|
||||
use openvk\Web\Models\Entities\User;
|
||||
|
||||
interface Handler
|
||||
{
|
||||
function __construct(?User $user);
|
||||
public function __construct(?User $user);
|
||||
}
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\ServiceAPI;
|
||||
|
||||
use openvk\Web\Models\Entities\User;
|
||||
use openvk\Web\Models\Repositories\{Users, Clubs};
|
||||
|
||||
|
@ -7,16 +11,16 @@ class Mentions implements Handler
|
|||
{
|
||||
protected $user;
|
||||
|
||||
function __construct(?User $user)
|
||||
public function __construct(?User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
function resolve(int $id, callable $resolve, callable $reject): void
|
||||
public function resolve(int $id, callable $resolve, callable $reject): void
|
||||
{
|
||||
if($id > 0) {
|
||||
$user = (new Users)->get($id);
|
||||
if(!$user) {
|
||||
if ($id > 0) {
|
||||
$user = (new Users())->get($id);
|
||||
if (!$user) {
|
||||
$reject("Not found");
|
||||
return;
|
||||
}
|
||||
|
@ -32,8 +36,8 @@ class Mentions implements Handler
|
|||
return;
|
||||
}
|
||||
|
||||
$club = (new Clubs)->get(abs($id));
|
||||
if(!$club) {
|
||||
$club = (new Clubs())->get(abs($id));
|
||||
if (!$club) {
|
||||
$reject("Not found");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
|
||||
namespace openvk\ServiceAPI;
|
||||
|
||||
use openvk\Web\Models\Entities\User;
|
||||
use openvk\Web\Models\Repositories\Notes as NoteRepo;
|
||||
|
||||
|
@ -9,22 +10,28 @@ class Notes implements Handler
|
|||
protected $user;
|
||||
protected $notes;
|
||||
|
||||
function __construct(?User $user)
|
||||
public function __construct(?User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->notes = new NoteRepo;
|
||||
$this->notes = new NoteRepo();
|
||||
}
|
||||
|
||||
function getNote(int $noteId, callable $resolve, callable $reject): void
|
||||
public function getNote(int $noteId, callable $resolve, callable $reject): void
|
||||
{
|
||||
$note = $this->notes->get($noteId);
|
||||
if(!$note || $note->isDeleted())
|
||||
if (!$note || $note->isDeleted()) {
|
||||
$reject(83, "Note is gone");
|
||||
}
|
||||
|
||||
$noteOwner = $note->getOwner();
|
||||
assert($noteOwner instanceof User);
|
||||
if(!$noteOwner->getPrivacyPermission("notes.read", $this->user))
|
||||
if (!$noteOwner->getPrivacyPermission("notes.read", $this->user)) {
|
||||
$reject(160, "You don't have permission to access this note");
|
||||
}
|
||||
|
||||
if (!$note->canBeViewedBy($this->user)) {
|
||||
$reject(15, "Access to note denied");
|
||||
}
|
||||
|
||||
$resolve([
|
||||
"title" => $note->getName(),
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\ServiceAPI;
|
||||
|
||||
use Latte\Engine as TemplatingEngine;
|
||||
use RdKafka\{Conf as RDKConf, KafkaConsumer};
|
||||
use openvk\Web\Models\Entities\User;
|
||||
|
@ -10,23 +14,23 @@ class Notifications implements Handler
|
|||
protected $user;
|
||||
protected $notifs;
|
||||
|
||||
function __construct(?User $user)
|
||||
public function __construct(?User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->notifs = new N;
|
||||
$this->notifs = new N();
|
||||
}
|
||||
|
||||
function ack(callable $resolve, callable $reject): void
|
||||
public function ack(callable $resolve, callable $reject): void
|
||||
{
|
||||
$this->user->updateNotificationOffset();
|
||||
$this->user->save();
|
||||
$resolve("OK");
|
||||
}
|
||||
|
||||
function fetch(callable $resolve, callable $reject): void
|
||||
public function fetch(callable $resolve, callable $reject): void
|
||||
{
|
||||
$kafkaConf = OPENVK_ROOT_CONF["openvk"]["credentials"]["notificationsBroker"];
|
||||
if(!$kafkaConf["enable"]) {
|
||||
if (!$kafkaConf["enable"]) {
|
||||
$reject(1999, "Disabled");
|
||||
return;
|
||||
}
|
||||
|
@ -41,23 +45,23 @@ class Notifications implements Handler
|
|||
$consumer = new KafkaConsumer($conf);
|
||||
$consumer->subscribe([ $kafkaConf["topic"] ]);
|
||||
|
||||
while(true) {
|
||||
$message = $consumer->consume(30*1000);
|
||||
while (true) {
|
||||
$message = $consumer->consume(30 * 1000);
|
||||
switch ($message->err) {
|
||||
case RD_KAFKA_RESP_ERR_NO_ERROR:
|
||||
$descriptor = $message->payload;
|
||||
[,$user,] = explode(",", $descriptor);
|
||||
if(((int) $user) === $this->user->getId()) {
|
||||
if (((int) $user) === $this->user->getId()) {
|
||||
$data = (object) [];
|
||||
$notification = $this->notifs->fromDescriptor($descriptor, $data);
|
||||
if(!$notification) {
|
||||
if (!$notification) {
|
||||
$reject(1982, "Server Error");
|
||||
return;
|
||||
}
|
||||
|
||||
$tplDir = __DIR__ . "/../Web/Presenters/templates/components/notifications/";
|
||||
$tplId = "$tplDir$data->actionCode/_$data->originModelType" . "_" . $data->targetModelType . "_.xml";
|
||||
$latte = new TemplatingEngine;
|
||||
$latte = new TemplatingEngine();
|
||||
$latte->setTempDirectory(CHANDLER_ROOT . "/tmp/cache/templates");
|
||||
$latte->addFilter("translate", fn($trId) => tr($trId));
|
||||
$resolve([
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?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};
|
||||
|
@ -11,10 +15,10 @@ class Polls implements Handler
|
|||
protected $user;
|
||||
protected $polls;
|
||||
|
||||
function __construct(?User $user)
|
||||
public function __construct(?User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->polls = new PollRepo;
|
||||
$this->polls = new PollRepo();
|
||||
}
|
||||
|
||||
private function getPollHtml(int $poll): string
|
||||
|
@ -22,10 +26,10 @@ class Polls implements Handler
|
|||
return Router::i()->execute("/poll$poll", "SAPI");
|
||||
}
|
||||
|
||||
function vote(int $pollId, string $options, callable $resolve, callable $reject): void
|
||||
public function vote(int $pollId, string $options, callable $resolve, callable $reject): void
|
||||
{
|
||||
$poll = $this->polls->get($pollId);
|
||||
if(!$poll) {
|
||||
if (!$poll) {
|
||||
$reject("Poll not found");
|
||||
return;
|
||||
}
|
||||
|
@ -33,16 +37,16 @@ class Polls implements Handler
|
|||
try {
|
||||
$options = explode(",", $options);
|
||||
$poll->vote($this->user, $options);
|
||||
} catch(AlreadyVotedException $ex) {
|
||||
} catch (AlreadyVotedException $ex) {
|
||||
$reject("Poll state changed: user has already voted.");
|
||||
return;
|
||||
} catch(PollLockedException $ex) {
|
||||
} catch (PollLockedException $ex) {
|
||||
$reject("Poll state changed: poll has ended.");
|
||||
return;
|
||||
} catch(InvalidOptionException $ex) {
|
||||
} catch (InvalidOptionException $ex) {
|
||||
$reject("Foreign options passed.");
|
||||
return;
|
||||
} catch(UnexpectedValueException $ex) {
|
||||
} catch (UnexpectedValueException $ex) {
|
||||
$reject("Too much options passed.");
|
||||
return;
|
||||
}
|
||||
|
@ -50,17 +54,17 @@ class Polls implements Handler
|
|||
$resolve(["html" => $this->getPollHtml($pollId)]);
|
||||
}
|
||||
|
||||
function unvote(int $pollId, callable $resolve, callable $reject): void
|
||||
public function unvote(int $pollId, callable $resolve, callable $reject): void
|
||||
{
|
||||
$poll = $this->polls->get($pollId);
|
||||
if(!$poll) {
|
||||
if (!$poll) {
|
||||
$reject("Poll not found");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$poll->revokeVote($this->user);
|
||||
} catch(PollLockedException $ex) {
|
||||
} catch (PollLockedException $ex) {
|
||||
$reject("Votes can't be revoked from this poll.");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\ServiceAPI;
|
||||
use openvk\Web\Models\Entities\{User, Club};
|
||||
use openvk\Web\Models\Repositories\{Users, Clubs, Videos};
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
|
||||
class Search implements Handler
|
||||
{
|
||||
protected $user;
|
||||
private $users;
|
||||
private $clubs;
|
||||
private $videos;
|
||||
|
||||
function __construct(?User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->users = new Users;
|
||||
$this->clubs = new Clubs;
|
||||
$this->videos = new Videos;
|
||||
}
|
||||
|
||||
function fastSearch(string $query, string $type = "users", callable $resolve, callable $reject)
|
||||
{
|
||||
if($query == "" || strlen($query) < 3)
|
||||
$reject(12, "No input or input < 3");
|
||||
|
||||
$repo;
|
||||
$sort;
|
||||
|
||||
switch($type) {
|
||||
default:
|
||||
case "users":
|
||||
$repo = (new Users);
|
||||
$sort = "rating DESC";
|
||||
|
||||
break;
|
||||
case "groups":
|
||||
$repo = (new Clubs);
|
||||
$sort = "id ASC";
|
||||
|
||||
break;
|
||||
case "videos":
|
||||
$repo = (new Videos);
|
||||
$sort = "created ASC";
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$res = $repo->find($query, ["doNotSearchMe" => $this->user->getId()], $sort);
|
||||
|
||||
$results = array_slice(iterator_to_array($res), 0, 5);
|
||||
|
||||
$count = sizeof($results);
|
||||
|
||||
$arr = [
|
||||
"count" => $count,
|
||||
"items" => []
|
||||
];
|
||||
|
||||
if(sizeof($results) < 1) {
|
||||
$reject(2, "No results");
|
||||
}
|
||||
|
||||
foreach($results as $res) {
|
||||
$arr["items"][] = [
|
||||
"id" => $res->getId(),
|
||||
"name" => $type == "users" ? $res->getCanonicalName() : $res->getName(),
|
||||
"avatar" => $type != "videos" ? $res->getAvatarUrl() : $res->getThumbnailURL(),
|
||||
"url" => $type != "videos" ? $res->getUrl() : "/video".$res->getPrettyId(),
|
||||
"description" => ovk_proc_strtr($res->getDescription() ?? "...", 40)
|
||||
];
|
||||
}
|
||||
|
||||
$resolve($arr);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\ServiceAPI;
|
||||
|
||||
use openvk\Web\Models\Entities\User;
|
||||
use openvk\Web\Util\DateTime;
|
||||
|
||||
|
@ -7,17 +11,17 @@ class Service implements Handler
|
|||
{
|
||||
protected $user;
|
||||
|
||||
function __construct(?User $user)
|
||||
public function __construct(?User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
function getTime(callable $resolve, callable $reject): void
|
||||
public function getTime(callable $resolve, callable $reject): void
|
||||
{
|
||||
$resolve(trim((new DateTime)->format("%e %B %G" . tr("time_at_sp") . "%X")));
|
||||
$resolve(trim((new DateTime())->format("%e %B %G" . tr("time_at_sp") . "%X")));
|
||||
}
|
||||
|
||||
function getServerVersion(callable $resolve, callable $reject): void
|
||||
public function getServerVersion(callable $resolve, callable $reject): void
|
||||
{
|
||||
$resolve("OVK " . OPENVK_VERSION);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\ServiceAPI;
|
||||
|
||||
use openvk\Web\Models\Entities\Post;
|
||||
use openvk\Web\Models\Entities\User;
|
||||
use openvk\Web\Models\Repositories\{Posts, Notes};
|
||||
use openvk\Web\Models\Repositories\{Posts, Notes, Videos};
|
||||
|
||||
class Wall implements Handler
|
||||
{
|
||||
|
@ -10,18 +14,28 @@ class Wall implements Handler
|
|||
protected $posts;
|
||||
protected $notes;
|
||||
|
||||
function __construct(?User $user)
|
||||
public function __construct(?User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->posts = new Posts;
|
||||
$this->notes = new Notes;
|
||||
$this->posts = new Posts();
|
||||
$this->notes = new Notes();
|
||||
$this->videos = new Videos();
|
||||
}
|
||||
|
||||
function getPost(int $id, callable $resolve, callable $reject): void
|
||||
public function getPost(int $id, callable $resolve, callable $reject): void
|
||||
{
|
||||
$post = $this->posts->get($id);
|
||||
if(!$post || $post->isDeleted())
|
||||
$reject("No post with id=$id");
|
||||
if (!$post || $post->isDeleted()) {
|
||||
$reject(53, "No post with id=$id");
|
||||
}
|
||||
|
||||
if ($post->getSuggestionType() != 0) {
|
||||
$reject(25, "Can't get suggested post");
|
||||
}
|
||||
|
||||
if (!$post->canBeViewedBy($this->user)) {
|
||||
$reject(12, "Access denied");
|
||||
}
|
||||
|
||||
$res = (object) [];
|
||||
$res->id = $post->getId();
|
||||
|
@ -30,8 +44,9 @@ class Wall implements Handler
|
|||
? ($owner->getId())
|
||||
: ($owner->getId() * -1);
|
||||
|
||||
if($post->isSigned())
|
||||
if ($post->isSigned()) {
|
||||
$res->signedOffBy = $post->getOwnerPost();
|
||||
}
|
||||
|
||||
$res->pinned = $post->isPinned();
|
||||
$res->sponsored = $post->isAd();
|
||||
|
@ -43,7 +58,7 @@ class Wall implements Handler
|
|||
"hasLike" => $post->hasLikeFrom($this->user),
|
||||
"likedBy" => [],
|
||||
];
|
||||
foreach($post->getLikers() as $liker) {
|
||||
foreach ($post->getLikers() as $liker) {
|
||||
$res->likes["likedBy"][] = [
|
||||
"id" => $liker->getId(),
|
||||
"url" => $liker->getURL(),
|
||||
|
@ -59,9 +74,9 @@ class Wall implements Handler
|
|||
$resolve((array) $res);
|
||||
}
|
||||
|
||||
function newStatus(string $text, callable $resolve, callable $reject): void
|
||||
public function newStatus(string $text, callable $resolve, callable $reject): void
|
||||
{
|
||||
$post = new Post;
|
||||
$post = new Post();
|
||||
$post->setOwner($this->user->getId());
|
||||
$post->setWall($this->user->getId());
|
||||
$post->setCreated(time());
|
||||
|
@ -73,26 +88,4 @@ class Wall implements Handler
|
|||
|
||||
$resolve($post->getId());
|
||||
}
|
||||
|
||||
function getMyNotes(callable $resolve, callable $reject)
|
||||
{
|
||||
$count = $this->notes->getUserNotesCount($this->user);
|
||||
$myNotes = $this->notes->getUserNotes($this->user, 1, $count);
|
||||
|
||||
$arr = [
|
||||
"count" => $count,
|
||||
"closed" => $this->user->getPrivacySetting("notes.read"),
|
||||
"items" => [],
|
||||
];
|
||||
|
||||
foreach($myNotes as $note) {
|
||||
$arr["items"][] = [
|
||||
"id" => $note->getId(),
|
||||
"name" => ovk_proc_strtr($note->getName(), 30),
|
||||
#"preview" => $note->getPreview()
|
||||
];
|
||||
}
|
||||
|
||||
$resolve($arr);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\VKAPI\Exceptions;
|
||||
|
||||
class APIErrorException extends \Exception
|
||||
{}
|
||||
class APIErrorException extends \Exception {}
|
||||
|
|
|
@ -1,28 +1,46 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
|
||||
use openvk\Web\Models\Exceptions\InvalidUserNameException;
|
||||
|
||||
final class Account extends VKAPIRequestHandler
|
||||
{
|
||||
function getProfileInfo(): object
|
||||
public function getProfileInfo(): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
return (object) [
|
||||
"first_name" => $this->getUser()->getFirstName(),
|
||||
"id" => $this->getUser()->getId(),
|
||||
"last_name" => $this->getUser()->getLastName(),
|
||||
"home_town" => $this->getUser()->getHometown(),
|
||||
"status" => $this->getUser()->getStatus(),
|
||||
"bdate" => is_null($this->getUser()->getBirthday()) ? '01.01.1970' : $this->getUser()->getBirthday()->format('%e.%m.%Y'),
|
||||
"bdate_visibility" => $this->getUser()->getBirthdayPrivacy(),
|
||||
$user = $this->getUser();
|
||||
$return_object = (object) [
|
||||
"first_name" => $user->getFirstName(),
|
||||
"photo_200" => $user->getAvatarURL("normal"),
|
||||
"nickname" => $user->getPseudo(),
|
||||
"is_service_account" => false,
|
||||
"id" => $user->getId(),
|
||||
"is_verified" => $user->isVerified(),
|
||||
"verification_status" => $user->isVerified() ? 'verified' : 'unverified',
|
||||
"last_name" => $user->getLastName(),
|
||||
"home_town" => $user->getHometown(),
|
||||
"status" => $user->getStatus(),
|
||||
"bdate" => is_null($user->getBirthday()) ? '01.01.1970' : $user->getBirthday()->format('%e.%m.%Y'),
|
||||
"bdate_visibility" => $user->getBirthdayPrivacy(),
|
||||
"phone" => "+420 ** *** 228", # TODO
|
||||
"relation" => $this->getUser()->getMaritalStatus(),
|
||||
"sex" => $this->getUser()->isFemale() ? 1 : 2
|
||||
"relation" => $user->getMaritalStatus(),
|
||||
"screen_name" => $user->getShortCode(),
|
||||
"sex" => $user->isFemale() ? 1 : 2,
|
||||
#"email" => $user->getEmail(),
|
||||
];
|
||||
|
||||
$audio_status = $user->getCurrentAudioStatus();
|
||||
if (!is_null($audio_status)) {
|
||||
$return_object->audio_status = $audio_status->toVkApiStruct($user);
|
||||
}
|
||||
|
||||
function getInfo(): object
|
||||
return $return_object;
|
||||
}
|
||||
|
||||
public function getInfo(): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
|
@ -37,11 +55,11 @@ final class Account extends VKAPIRequestHandler
|
|||
"is_new_live_streaming_enabled" => false,
|
||||
"lang" => 1,
|
||||
"no_wall_replies" => 0,
|
||||
"own_posts_default" => 0
|
||||
"own_posts_default" => 0,
|
||||
];
|
||||
}
|
||||
|
||||
function setOnline(): int
|
||||
public function setOnline(): int
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
|
@ -50,7 +68,7 @@ final class Account extends VKAPIRequestHandler
|
|||
return 1;
|
||||
}
|
||||
|
||||
function setOffline(): int
|
||||
public function setOffline(): int
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
|
@ -59,25 +77,25 @@ final class Account extends VKAPIRequestHandler
|
|||
return 1;
|
||||
}
|
||||
|
||||
function getAppPermissions(): int
|
||||
public function getAppPermissions(): int
|
||||
{
|
||||
return 9355263;
|
||||
}
|
||||
|
||||
function getCounters(string $filter = ""): object
|
||||
public function getCounters(string $filter = ""): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
return (object) [
|
||||
"friends" => $this->getUser()->getFollowersCount(),
|
||||
"notifications" => $this->getUser()->getNotificationsCount(),
|
||||
"messages" => $this->getUser()->getUnreadMessagesCount()
|
||||
"messages" => $this->getUser()->getUnreadMessagesCount(),
|
||||
];
|
||||
|
||||
# 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
|
||||
public 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();
|
||||
$this->willExecuteWriteAction();
|
||||
|
@ -88,7 +106,7 @@ final class Account extends VKAPIRequestHandler
|
|||
"changed" => 0,
|
||||
];
|
||||
|
||||
if(!empty($first_name) || !empty($last_name)) {
|
||||
if (!empty($first_name) || !empty($last_name)) {
|
||||
$output["name_request"] = [
|
||||
"id" => random_int(1, 2048), # For compatibility with original VK API
|
||||
"status" => "success",
|
||||
|
@ -97,37 +115,44 @@ final class Account extends VKAPIRequestHandler
|
|||
];
|
||||
|
||||
try {
|
||||
if(!empty($first_name))
|
||||
if (!empty($first_name)) {
|
||||
$user->setFirst_name($first_name);
|
||||
if(!empty($last_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))
|
||||
if (!empty($screen_name)) {
|
||||
if (!$user->setShortCode($screen_name)) {
|
||||
$this->fail(1260, "Invalid screen name");
|
||||
}
|
||||
}
|
||||
|
||||
# For compatibility with original VK API
|
||||
if($sex > 0)
|
||||
if ($sex > 0) {
|
||||
$user->setSex($sex == 1 ? 1 : 0);
|
||||
}
|
||||
|
||||
if($relation > -1)
|
||||
if ($relation > -1) {
|
||||
$user->setMarital_Status($relation);
|
||||
}
|
||||
|
||||
if(!empty($bdate)) {
|
||||
if (!empty($bdate)) {
|
||||
$birthday = strtotime($bdate);
|
||||
if (!is_int($birthday))
|
||||
if (!is_int($birthday)) {
|
||||
$this->fail(100, "invalid value of bdate.");
|
||||
}
|
||||
|
||||
$user->setBirthday($birthday);
|
||||
}
|
||||
|
||||
# For compatibility with original VK API
|
||||
switch($bdate_visibility) {
|
||||
switch ($bdate_visibility) {
|
||||
case 0:
|
||||
$this->fail(946, "Hiding date of birth is not implemented.");
|
||||
break;
|
||||
|
@ -138,17 +163,214 @@ final class Account extends VKAPIRequestHandler
|
|||
$user->setBirthday_privacy(1);
|
||||
}
|
||||
|
||||
if(!empty($home_town))
|
||||
if (!empty($home_town)) {
|
||||
$user->setHometown($home_town);
|
||||
}
|
||||
|
||||
if(!empty($status))
|
||||
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")) {
|
||||
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;
|
||||
}
|
||||
|
||||
public function getBalance(): object
|
||||
{
|
||||
$this->requireUser();
|
||||
if (!OPENVK_ROOT_CONF['openvk']['preferences']['commerce']) {
|
||||
$this->fail(105, "Commerce is disabled on this instance");
|
||||
}
|
||||
|
||||
return (object) ['votes' => $this->getUser()->getCoins()];
|
||||
}
|
||||
|
||||
public function getOvkSettings(): object
|
||||
{
|
||||
$this->requireUser();
|
||||
$user = $this->getUser();
|
||||
|
||||
$settings_list = (object) [
|
||||
'avatar_style' => $user->getStyleAvatar(),
|
||||
'style' => $user->getStyle(),
|
||||
'show_rating' => !$user->prefersNotToSeeRating(),
|
||||
'nsfw_tolerance' => $user->getNsfwTolerance(),
|
||||
'post_view' => $user->hasMicroblogEnabled() ? 'microblog' : 'old',
|
||||
'main_page' => $user->getMainPage() == 0 ? 'my_page' : 'news',
|
||||
];
|
||||
|
||||
return $settings_list;
|
||||
}
|
||||
|
||||
public function sendVotes(int $receiver, int $value, string $message = ""): object
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if (!OPENVK_ROOT_CONF["openvk"]["preferences"]["commerce"]) {
|
||||
$this->fail(-105, "Commerce is disabled on this instance");
|
||||
}
|
||||
|
||||
if ($receiver < 0) {
|
||||
$this->fail(-248, "Invalid receiver id");
|
||||
}
|
||||
|
||||
if ($value < 1) {
|
||||
$this->fail(-248, "Invalid value");
|
||||
}
|
||||
|
||||
if (iconv_strlen($message) > 255) {
|
||||
$this->fail(-249, "Message is too long");
|
||||
}
|
||||
|
||||
if ($this->getUser()->getCoins() < $value) {
|
||||
$this->fail(-252, "Not enough votes");
|
||||
}
|
||||
|
||||
$receiver_entity = (new \openvk\Web\Models\Repositories\Users())->get($receiver);
|
||||
if (!$receiver_entity || $receiver_entity->isDeleted() || !$receiver_entity->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(-250, "Invalid receiver");
|
||||
}
|
||||
|
||||
if ($receiver_entity->getId() === $this->getUser()->getId()) {
|
||||
$this->fail(-251, "Can't transfer votes to yourself");
|
||||
}
|
||||
|
||||
$this->getUser()->setCoins($this->getUser()->getCoins() - $value);
|
||||
$this->getUser()->save();
|
||||
|
||||
$receiver_entity->setCoins($receiver_entity->getCoins() + $value);
|
||||
$receiver_entity->save();
|
||||
|
||||
(new \openvk\Web\Models\Entities\Notifications\CoinsTransferNotification($receiver_entity, $this->getUser(), $value, $message))->emit();
|
||||
|
||||
return (object) ['votes' => $this->getUser()->getCoins()];
|
||||
}
|
||||
|
||||
public function ban(int $owner_id): int
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if ($owner_id < 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($owner_id == $this->getUser()->getId()) {
|
||||
$this->fail(15, "Access denied: cannot blacklist yourself");
|
||||
}
|
||||
|
||||
$config_limit = OPENVK_ROOT_CONF['openvk']['preferences']['blacklists']['limit'] ?? 100;
|
||||
$user_blocks = $this->getUser()->getBlacklistSize();
|
||||
if (($user_blocks + 1) > $config_limit) {
|
||||
$this->fail(-7856, "Blacklist limit exceeded");
|
||||
}
|
||||
|
||||
$entity = get_entity_by_id($owner_id);
|
||||
if (!$entity || $entity->isDeleted()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($entity->isBlacklistedBy($this->getUser())) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->getUser()->addToBlacklist($entity);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function unban(int $owner_id): int
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if ($owner_id < 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($owner_id == $this->getUser()->getId()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
$entity = get_entity_by_id($owner_id);
|
||||
if (!$entity) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!$entity->isBlacklistedBy($this->getUser())) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->getUser()->removeFromBlacklist($entity);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function getBanned(int $offset = 0, int $count = 100, string $fields = ""): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$result = (object) [
|
||||
'count' => $this->getUser()->getBlacklistSize(),
|
||||
'items' => [],
|
||||
];
|
||||
$banned = $this->getUser()->getBlacklist($offset, $count);
|
||||
foreach ($banned as $ban) {
|
||||
if (!$ban) {
|
||||
continue;
|
||||
}
|
||||
$result->items[] = $ban->toVkApiStruct($this->getUser(), $fields);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function saveInterestsInfo(
|
||||
string $interests = null,
|
||||
string $fav_music = null,
|
||||
string $fav_films = null,
|
||||
string $fav_shows = null,
|
||||
string $fav_books = null,
|
||||
string $fav_quote = null,
|
||||
string $fav_games = null,
|
||||
string $about = null,
|
||||
) {
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$user = $this->getUser();
|
||||
$changes = 0;
|
||||
$changes_array = [
|
||||
"interests" => $interests,
|
||||
"fav_music" => $fav_music,
|
||||
"fav_films" => $fav_films,
|
||||
"fav_books" => $fav_books,
|
||||
"fav_shows" => $fav_shows,
|
||||
"fav_quote" => $fav_quote,
|
||||
"fav_games" => $fav_games,
|
||||
"about" => $about,
|
||||
];
|
||||
|
||||
foreach ($changes_array as $change_name => $change_value) {
|
||||
$set_name = "set" . ucfirst($change_name);
|
||||
$get_name = "get" . str_replace("Fav", "Favorite", str_replace("_", "", ucfirst($change_name)));
|
||||
if (!is_null($change_value) && $change_value !== $user->$get_name()) {
|
||||
$user->$set_name(ovk_proc_strtr($change_value, 1000));
|
||||
$changes += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ($changes > 0) {
|
||||
$user->save();
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"changed" => (int) ($changes > 0),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,865 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
use openvk\Web\Models\Entities\Audio as AEntity;
|
||||
use openvk\Web\Models\Entities\Playlist;
|
||||
use openvk\Web\Models\Repositories\Audios;
|
||||
use openvk\Web\Models\Repositories\Clubs;
|
||||
use openvk\Web\Models\Repositories\Util\EntityStream;
|
||||
|
||||
final class Audio extends VKAPIRequestHandler
|
||||
{
|
||||
function get(): object
|
||||
private function toSafeAudioStruct(?AEntity $audio, ?string $hash = null, bool $need_user = false): object
|
||||
{
|
||||
$serverUrl = ovk_scheme(true) . $_SERVER["SERVER_NAME"];
|
||||
if (!$audio) {
|
||||
$this->fail(0o404, "Audio not found");
|
||||
} elseif (!$audio->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(201, "Access denied to audio(" . $audio->getPrettyId() . ")");
|
||||
}
|
||||
|
||||
# рофлан ебало
|
||||
$privApi = $hash && $GLOBALS["csrfCheck"];
|
||||
$audioObj = $audio->toVkApiStruct($this->getUser());
|
||||
if (!$privApi) {
|
||||
$audioObj->manifest = false;
|
||||
$audioObj->keys = false;
|
||||
}
|
||||
|
||||
if ($need_user) {
|
||||
$user = (new \openvk\Web\Models\Repositories\Users())->get($audio->getOwner()->getId());
|
||||
$audioObj->user = (object) [
|
||||
"id" => $user->getId(),
|
||||
"photo" => $user->getAvatarUrl(),
|
||||
"name" => $user->getCanonicalName(),
|
||||
"name_gen" => $user->getCanonicalName(),
|
||||
];
|
||||
}
|
||||
|
||||
return $audioObj;
|
||||
}
|
||||
|
||||
private function streamToResponse(EntityStream $es, int $offset, int $count, ?string $hash = null): object
|
||||
{
|
||||
$items = [];
|
||||
foreach ($es->offsetLimit($offset, $count) as $audio) {
|
||||
$items[] = $this->toSafeAudioStruct($audio, $hash);
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"count" => sizeof($items),
|
||||
"items" => $items,
|
||||
];
|
||||
}
|
||||
|
||||
private function validateGenre(?string& $genre_str, ?int $genre_id): void
|
||||
{
|
||||
if (!is_null($genre_str)) {
|
||||
if (!in_array($genre_str, AEntity::genres)) {
|
||||
$this->fail(8, "Invalid genre_str");
|
||||
}
|
||||
} elseif (!is_null($genre_id)) {
|
||||
$genre_str = array_flip(AEntity::vkGenres)[$genre_id] ?? null;
|
||||
if (!$genre_str) {
|
||||
$this->fail(8, "Invalid genre ID $genre_id");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function audioFromAnyId(string $id): ?AEntity
|
||||
{
|
||||
$descriptor = explode("_", $id);
|
||||
if (sizeof($descriptor) === 1) {
|
||||
if (ctype_digit($descriptor[0])) {
|
||||
$audio = (new Audios())->get((int) $descriptor[0]);
|
||||
} else {
|
||||
$aid = base64_decode($descriptor[0], true);
|
||||
if (!$aid) {
|
||||
$this->fail(8, "Invalid audio $id");
|
||||
}
|
||||
|
||||
$audio = (new Audios())->get((int) $aid);
|
||||
}
|
||||
} elseif (sizeof($descriptor) === 2) {
|
||||
$audio = (new Audios())->getByOwnerAndVID((int) $descriptor[0], (int) $descriptor[1]);
|
||||
} else {
|
||||
$this->fail(8, "Invalid audio $id");
|
||||
}
|
||||
|
||||
return $audio;
|
||||
}
|
||||
|
||||
public function getById(string $audios, ?string $hash = null, int $need_user = 0): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$audioIds = array_unique(explode(",", $audios));
|
||||
if (sizeof($audioIds) === 1) {
|
||||
$audio = $this->audioFromAnyId($audioIds[0]);
|
||||
|
||||
return (object) [
|
||||
"count" => 1,
|
||||
"items" => [(object) [
|
||||
"id" => 1,
|
||||
"owner_id" => 1,
|
||||
"artist" => "В ОВК ПОКА НЕТ МУЗЫКИ",
|
||||
"title" => "ЖДИТЕ :)))",
|
||||
"duration" => 22,
|
||||
"url" => $serverUrl . "/assets/packages/static/openvk/audio/nomusic.mp3"
|
||||
]]
|
||||
"items" => [
|
||||
$this->toSafeAudioStruct($audio, $hash, (bool) $need_user),
|
||||
],
|
||||
];
|
||||
} elseif (sizeof($audioIds) > 6000) {
|
||||
$this->fail(1980, "Can't get more than 6000 audios at once");
|
||||
}
|
||||
|
||||
$audios = [];
|
||||
foreach ($audioIds as $id) {
|
||||
$audios[] = $this->getById($id, $hash)->items[0];
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"count" => sizeof($audios),
|
||||
"items" => $audios,
|
||||
];
|
||||
}
|
||||
|
||||
public function isLagtrain(string $audio_id): int
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$audio = $this->audioFromAnyId($audio_id);
|
||||
if (!$audio) {
|
||||
$this->fail(0o404, "Audio not found");
|
||||
}
|
||||
|
||||
# Possible information disclosure risks are acceptable :D
|
||||
return (int) (strpos($audio->getName(), "Lagtrain") !== false);
|
||||
}
|
||||
|
||||
// TODO stub
|
||||
public function getRecommendations(): object
|
||||
{
|
||||
return (object) [
|
||||
"count" => 0,
|
||||
"items" => [],
|
||||
];
|
||||
}
|
||||
|
||||
public function getPopular(?int $genre_id = null, ?string $genre_str = null, int $offset = 0, int $count = 100, ?string $hash = null): object
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->validateGenre($genre_str, $genre_id);
|
||||
|
||||
$results = (new Audios())->getGlobal(Audios::ORDER_POPULAR, $genre_str);
|
||||
|
||||
return $this->streamToResponse($results, $offset, $count, $hash);
|
||||
}
|
||||
|
||||
public function getFeed(?int $genre_id = null, ?string $genre_str = null, int $offset = 0, int $count = 100, ?string $hash = null): object
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->validateGenre($genre_str, $genre_id);
|
||||
|
||||
$results = (new Audios())->getGlobal(Audios::ORDER_NEW, $genre_str);
|
||||
|
||||
return $this->streamToResponse($results, $offset, $count, $hash);
|
||||
}
|
||||
|
||||
public function search(string $q, int $auto_complete = 0, int $lyrics = 0, int $performer_only = 0, int $sort = 2, int $search_own = 0, int $offset = 0, int $count = 30, ?string $hash = null): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
if (($auto_complete + $search_own) != 0) {
|
||||
$this->fail(10, "auto_complete and search_own are not supported");
|
||||
} elseif ($count > 300 || $count < 1) {
|
||||
$this->fail(8, "count is invalid: $count");
|
||||
}
|
||||
|
||||
$results = (new Audios())->search($q, $sort, (bool) $performer_only, (bool) $lyrics);
|
||||
|
||||
return $this->streamToResponse($results, $offset, $count, $hash);
|
||||
}
|
||||
|
||||
public function getCount(int $owner_id, int $uploaded_only = 0): int
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
if ($owner_id < 0) {
|
||||
$owner_id *= -1;
|
||||
$group = (new Clubs())->get($owner_id);
|
||||
if (!$group) {
|
||||
$this->fail(0o404, "Group not found");
|
||||
}
|
||||
|
||||
return (new Audios())->getClubCollectionSize($group);
|
||||
}
|
||||
|
||||
$user = (new \openvk\Web\Models\Repositories\Users())->get($owner_id);
|
||||
if (!$user) {
|
||||
$this->fail(0o404, "User not found");
|
||||
}
|
||||
|
||||
if (!$user->getPrivacyPermission("audios.read", $this->getUser())) {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
if ($uploaded_only) {
|
||||
return DatabaseConnection::i()->getContext()->table("audios")
|
||||
->where([
|
||||
"deleted" => false,
|
||||
"owner" => $owner_id,
|
||||
])->count();
|
||||
}
|
||||
|
||||
return (new Audios())->getUserCollectionSize($user);
|
||||
}
|
||||
|
||||
public function get(int $owner_id = 0, int $album_id = 0, string $audio_ids = '', int $need_user = 1, int $offset = 0, int $count = 100, int $uploaded_only = 0, int $need_seed = 0, ?string $shuffle_seed = null, int $shuffle = 0, ?string $hash = null): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$shuffleSeed = null;
|
||||
$shuffleSeedStr = null;
|
||||
if ($shuffle == 1) {
|
||||
if (!$shuffle_seed) {
|
||||
if ($need_seed == 1) {
|
||||
$shuffleSeed = openssl_random_pseudo_bytes(6);
|
||||
$shuffleSeedStr = base64_encode($shuffleSeed);
|
||||
$shuffleSeed = hexdec(bin2hex($shuffleSeed));
|
||||
} else {
|
||||
$hOffset = ((int) date("i") * 60) + (int) date("s");
|
||||
$thisHour = time() - $hOffset;
|
||||
$shuffleSeed = $thisHour + $this->getUser()->getId();
|
||||
$shuffleSeedStr = base64_encode(hex2bin(dechex($shuffleSeed)));
|
||||
}
|
||||
} else {
|
||||
$shuffleSeed = hexdec(bin2hex(base64_decode($shuffle_seed)));
|
||||
$shuffleSeedStr = $shuffle_seed;
|
||||
}
|
||||
}
|
||||
|
||||
if ($album_id != 0) {
|
||||
$album = (new Audios())->getPlaylist($album_id);
|
||||
if (!$album) {
|
||||
$this->fail(0o404, "album_id invalid");
|
||||
} elseif (!$album->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(600, "Can't open this album for reading");
|
||||
}
|
||||
|
||||
$songs = [];
|
||||
$list = $album->getAudios($offset, $count, $shuffleSeed);
|
||||
|
||||
foreach ($list as $song) {
|
||||
$songs[] = $this->toSafeAudioStruct($song, $hash, $need_user == 1);
|
||||
}
|
||||
|
||||
$response = (object) [
|
||||
"count" => sizeof($songs),
|
||||
"items" => $songs,
|
||||
];
|
||||
if (!is_null($shuffleSeed)) {
|
||||
$response->shuffle_seed = $shuffleSeedStr;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
if (!empty($audio_ids)) {
|
||||
$audio_ids = explode(",", $audio_ids);
|
||||
if (!$audio_ids) {
|
||||
$this->fail(10, "Audio::get@L0d186:explode(string): Unknown error");
|
||||
} elseif (sizeof($audio_ids) < 1) {
|
||||
$this->fail(8, "Invalid audio_ids syntax");
|
||||
}
|
||||
|
||||
if (!is_null($shuffleSeed)) {
|
||||
$audio_ids = knuth_shuffle($audio_ids, $shuffleSeed);
|
||||
}
|
||||
|
||||
$obj = $this->getById(implode(",", $audio_ids), $hash, $need_user);
|
||||
if (!is_null($shuffleSeed)) {
|
||||
$obj->shuffle_seed = $shuffleSeedStr;
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
$dbCtx = DatabaseConnection::i()->getContext();
|
||||
if ($uploaded_only == 1) {
|
||||
if ($owner_id <= 0) {
|
||||
$this->fail(8, "uploaded_only can only be used with owner_id > 0");
|
||||
}
|
||||
|
||||
$user = (new \openvk\Web\Models\Repositories\Users())->get($owner_id);
|
||||
|
||||
if (!$user) {
|
||||
$this->fail(0o602, "Invalid user");
|
||||
}
|
||||
|
||||
if (!$user->getPrivacyPermission("audios.read", $this->getUser())) {
|
||||
$this->fail(15, "Access denied: this user chose to hide his audios");
|
||||
}
|
||||
|
||||
if (!is_null($shuffleSeed)) {
|
||||
$audio_ids = [];
|
||||
$query = $dbCtx->table("audios")->select("virtual_id")->where([
|
||||
"owner" => $owner_id,
|
||||
"deleted" => 0,
|
||||
]);
|
||||
|
||||
foreach ($query as $res) {
|
||||
$audio_ids[] = $res->virtual_id;
|
||||
}
|
||||
|
||||
$audio_ids = knuth_shuffle($audio_ids, $shuffleSeed);
|
||||
$audio_ids = array_slice($audio_ids, $offset, $count);
|
||||
$audio_q = ""; # audio.getById query
|
||||
foreach ($audio_ids as $aid) {
|
||||
$audio_q .= ",$owner_id" . "_$aid";
|
||||
}
|
||||
|
||||
$obj = $this->getById(substr($audio_q, 1), $hash, $need_user);
|
||||
$obj->shuffle_seed = $shuffleSeedStr;
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
$res = (new Audios())->getByUploader((new \openvk\Web\Models\Repositories\Users())->get($owner_id));
|
||||
|
||||
return $this->streamToResponse($res, $offset, $count, $hash, $need_user);
|
||||
}
|
||||
|
||||
$query = $dbCtx->table("audio_relations")->select("audio")->where("entity", $owner_id);
|
||||
if (!is_null($shuffleSeed)) {
|
||||
$audio_ids = [];
|
||||
foreach ($query as $aid) {
|
||||
$audio_ids[] = $aid->audio;
|
||||
}
|
||||
|
||||
$audio_ids = knuth_shuffle($audio_ids, $shuffleSeed);
|
||||
$audio_ids = array_slice($audio_ids, $offset, $count);
|
||||
$audio_q = "";
|
||||
foreach ($audio_ids as $aid) {
|
||||
$audio_q .= ",$aid";
|
||||
}
|
||||
|
||||
$obj = $this->getById(substr($audio_q, 1), $hash, $need_user);
|
||||
$obj->shuffle_seed = $shuffleSeedStr;
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
$items = [];
|
||||
|
||||
if ($owner_id > 0) {
|
||||
$user = (new \openvk\Web\Models\Repositories\Users())->get($owner_id);
|
||||
|
||||
if (!$user) {
|
||||
$this->fail(50, "Invalid user");
|
||||
}
|
||||
|
||||
if (!$user->getPrivacyPermission("audios.read", $this->getUser())) {
|
||||
$this->fail(15, "Access denied: this user chose to hide his audios");
|
||||
}
|
||||
}
|
||||
|
||||
$audios = (new Audios())->getByEntityID($owner_id, $offset, $count);
|
||||
foreach ($audios as $audio) {
|
||||
$items[] = $this->toSafeAudioStruct($audio, $hash, $need_user == 1);
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"count" => sizeof($items),
|
||||
"items" => $items,
|
||||
];
|
||||
}
|
||||
|
||||
public function getLyrics(int $lyrics_id): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$audio = (new Audios())->get($lyrics_id);
|
||||
if (!$audio || !$audio->getLyrics()) {
|
||||
$this->fail(0o404, "Not found");
|
||||
}
|
||||
|
||||
if (!$audio->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(201, "Access denied to lyrics");
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"lyrics_id" => $lyrics_id,
|
||||
"text" => preg_replace("%\r\n?%", "\n", $audio->getLyrics()),
|
||||
];
|
||||
}
|
||||
|
||||
public function beacon(int $aid, ?int $gid = null): int
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$audio = (new Audios())->get($aid);
|
||||
if (!$audio) {
|
||||
$this->fail(0o404, "Not Found");
|
||||
} elseif (!$audio->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(201, "Insufficient permissions to listen this audio");
|
||||
}
|
||||
|
||||
$group = null;
|
||||
if (!is_null($gid)) {
|
||||
$group = (new Clubs())->get($gid);
|
||||
if (!$group) {
|
||||
$this->fail(0o404, "Not Found");
|
||||
} elseif (!$group->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(203, "Insufficient rights to this group");
|
||||
}
|
||||
}
|
||||
|
||||
return (int) $audio->listen($group ?? $this->getUser());
|
||||
}
|
||||
|
||||
public function setBroadcast(string $audio, string $target_ids): array
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
[$owner, $aid] = explode("_", $audio);
|
||||
$song = (new Audios())->getByOwnerAndVID((int) $owner, (int) $aid);
|
||||
$ids = [];
|
||||
foreach (explode(",", $target_ids) as $id) {
|
||||
$id = (int) $id;
|
||||
if ($id > 0) {
|
||||
if ($id != $this->getUser()->getId()) {
|
||||
$this->fail(600, "Can't listen on behalf of $id");
|
||||
} else {
|
||||
$ids[] = $id;
|
||||
$this->beacon($song->getId());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$group = (new Clubs())->get($id * -1);
|
||||
if (!$group) {
|
||||
$this->fail(0o404, "Not Found");
|
||||
} elseif (!$group->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(203, "Insufficient rights to this group");
|
||||
}
|
||||
|
||||
$ids[] = $id;
|
||||
$this->beacon($song ? $song->getId() : 0, $id * -1);
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
public function getBroadcastList(string $filter = "all", int $active = 0, ?string $hash = null): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
if (!in_array($filter, ["all", "friends", "groups"])) {
|
||||
$this->fail(8, "Invalid filter $filter");
|
||||
}
|
||||
|
||||
$broadcastList = $this->getUser()->getBroadcastList($filter);
|
||||
$items = [];
|
||||
foreach ($broadcastList as $res) {
|
||||
$struct = $res->toVkApiStruct();
|
||||
$status = $res->getCurrentAudioStatus();
|
||||
|
||||
$struct->status_audio = $status ? $this->toSafeAudioStruct($status) : null;
|
||||
$items[] = $struct;
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"count" => sizeof($items),
|
||||
"items" => $items,
|
||||
];
|
||||
}
|
||||
|
||||
public function edit(int $owner_id, int $audio_id, ?string $artist = null, ?string $title = null, ?string $text = null, ?int $genre_id = null, ?string $genre_str = null, int $no_search = 0): int
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$audio = (new Audios())->getByOwnerAndVID($owner_id, $audio_id);
|
||||
if (!$audio) {
|
||||
$this->fail(0o404, "Not Found");
|
||||
} elseif (!$audio->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(201, "Insufficient permissions to edit this audio");
|
||||
}
|
||||
|
||||
if (!is_null($genre_id)) {
|
||||
$genre = array_flip(AEntity::vkGenres)[$genre_id] ?? null;
|
||||
if (!$genre) {
|
||||
$this->fail(8, "Invalid genre ID $genre_id");
|
||||
}
|
||||
|
||||
$audio->setGenre($genre);
|
||||
} elseif (!is_null($genre_str)) {
|
||||
if (!in_array($genre_str, AEntity::genres)) {
|
||||
$this->fail(8, "Invalid genre ID $genre_str");
|
||||
}
|
||||
|
||||
$audio->setGenre($genre_str);
|
||||
}
|
||||
|
||||
$lyrics = 0;
|
||||
if (!is_null($text)) {
|
||||
$audio->setLyrics($text);
|
||||
$lyrics = $audio->getId();
|
||||
}
|
||||
|
||||
if (!is_null($artist)) {
|
||||
$audio->setPerformer($artist);
|
||||
}
|
||||
|
||||
if (!is_null($title)) {
|
||||
$audio->setName($title);
|
||||
}
|
||||
|
||||
$audio->setSearchability(!((bool) $no_search));
|
||||
$audio->setEdited(time());
|
||||
$audio->save();
|
||||
|
||||
return $lyrics;
|
||||
}
|
||||
|
||||
public function add(int $audio_id, int $owner_id, ?int $group_id = null, ?int $album_id = null): string
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if (!is_null($album_id)) {
|
||||
$this->fail(10, "album_id not implemented");
|
||||
}
|
||||
|
||||
// TODO get rid of dups
|
||||
$to = $this->getUser();
|
||||
if (!is_null($group_id)) {
|
||||
$group = (new Clubs())->get($group_id);
|
||||
if (!$group) {
|
||||
$this->fail(0o404, "Invalid group_id");
|
||||
} elseif (!$group->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(203, "Insufficient rights to this group");
|
||||
}
|
||||
|
||||
$to = $group;
|
||||
}
|
||||
|
||||
$audio = (new Audios())->getByOwnerAndVID($owner_id, $audio_id);
|
||||
if (!$audio) {
|
||||
$this->fail(0o404, "Not found");
|
||||
} elseif (!$audio->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(201, "Access denied to audio(owner=$owner_id, vid=$audio_id)");
|
||||
}
|
||||
|
||||
try {
|
||||
$audio->add($to);
|
||||
} catch (\OverflowException $ex) {
|
||||
$this->fail(300, "Album is full");
|
||||
}
|
||||
|
||||
return $audio->getPrettyId();
|
||||
}
|
||||
|
||||
public function delete(int $audio_id, int $owner_id, ?int $group_id = null): int
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$from = $this->getUser();
|
||||
if (!is_null($group_id)) {
|
||||
$group = (new Clubs())->get($group_id);
|
||||
if (!$group) {
|
||||
$this->fail(0o404, "Invalid group_id");
|
||||
} elseif (!$group->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(203, "Insufficient rights to this group");
|
||||
}
|
||||
|
||||
$from = $group;
|
||||
}
|
||||
|
||||
$audio = (new Audios())->getByOwnerAndVID($owner_id, $audio_id);
|
||||
if (!$audio) {
|
||||
$this->fail(0o404, "Not found");
|
||||
}
|
||||
|
||||
$audio->remove($from);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function restore(int $audio_id, int $owner_id, ?int $group_id = null, ?string $hash = null): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$vid = $this->add($audio_id, $owner_id, $group_id);
|
||||
|
||||
return $this->getById($vid, $hash)->items[0];
|
||||
}
|
||||
|
||||
public function getAlbums(int $owner_id = 0, int $offset = 0, int $count = 50, int $drop_private = 1): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$owner_id = $owner_id == 0 ? $this->getUser()->getId() : $owner_id;
|
||||
$playlists = [];
|
||||
|
||||
if ($owner_id > 0 && $owner_id != $this->getUser()->getId()) {
|
||||
$user = (new \openvk\Web\Models\Repositories\Users())->get($owner_id);
|
||||
|
||||
if (!$user->getPrivacyPermission("audios.read", $this->getUser())) {
|
||||
$this->fail(50, "Access to playlists denied");
|
||||
}
|
||||
}
|
||||
|
||||
foreach ((new Audios())->getPlaylistsByEntityId($owner_id, $offset, $count) as $playlist) {
|
||||
if (!$playlist->canBeViewedBy($this->getUser())) {
|
||||
if ($drop_private == 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$playlists[] = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
$playlists[] = $playlist->toVkApiStruct($this->getUser());
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"count" => sizeof($playlists),
|
||||
"items" => $playlists,
|
||||
];
|
||||
}
|
||||
|
||||
public function searchAlbums(string $query = '', int $offset = 0, int $limit = 25, int $drop_private = 0, int $order = 0, int $from_me = 0): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$playlists = [];
|
||||
$params = [];
|
||||
$order_str = (['id', 'length', 'listens'][$order] ?? 'id');
|
||||
if ($from_me === 1) {
|
||||
$params['from_me'] = $this->getUser()->getId();
|
||||
}
|
||||
|
||||
$search = (new Audios())->findPlaylists($query, $params, ['type' => $order_str, 'invert' => false]);
|
||||
foreach ($search->offsetLimit($offset, $limit) as $playlist) {
|
||||
if (!$playlist->canBeViewedBy($this->getUser())) {
|
||||
if ($drop_private == 0) {
|
||||
$playlists[] = null;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$playlists[] = $playlist->toVkApiStruct($this->getUser());
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"count" => $search->size(),
|
||||
"items" => $playlists,
|
||||
];
|
||||
}
|
||||
|
||||
public function addAlbum(string $title, ?string $description = null, int $group_id = 0): int
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$group = null;
|
||||
if ($group_id != 0) {
|
||||
$group = (new Clubs())->get($group_id);
|
||||
if (!$group) {
|
||||
$this->fail(0o404, "Invalid group_id");
|
||||
} elseif (!$group->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(600, "Insufficient rights to this group");
|
||||
}
|
||||
}
|
||||
|
||||
$album = new Playlist();
|
||||
$album->setName($title);
|
||||
if (!is_null($group)) {
|
||||
$album->setOwner($group_id * -1);
|
||||
} else {
|
||||
$album->setOwner($this->getUser()->getId());
|
||||
}
|
||||
|
||||
if (!is_null($description)) {
|
||||
$album->setDescription($description);
|
||||
}
|
||||
|
||||
$album->save();
|
||||
if (!is_null($group)) {
|
||||
$album->bookmark($group);
|
||||
} else {
|
||||
$album->bookmark($this->getUser());
|
||||
}
|
||||
|
||||
return $album->getId();
|
||||
}
|
||||
|
||||
public function editAlbum(int $album_id, ?string $title = null, ?string $description = null): int
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$album = (new Audios())->getPlaylist($album_id);
|
||||
if (!$album) {
|
||||
$this->fail(0o404, "Album not found");
|
||||
} elseif (!$album->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(600, "Insufficient rights to this album");
|
||||
}
|
||||
|
||||
if (!is_null($title)) {
|
||||
$album->setName($title);
|
||||
}
|
||||
|
||||
if (!is_null($description)) {
|
||||
$album->setDescription($description);
|
||||
}
|
||||
|
||||
$album->setEdited(time());
|
||||
$album->save();
|
||||
|
||||
return (int) !(!$title && !$description);
|
||||
}
|
||||
|
||||
public function deleteAlbum(int $album_id): int
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$album = (new Audios())->getPlaylist($album_id);
|
||||
if (!$album) {
|
||||
$this->fail(0o404, "Album not found");
|
||||
} elseif (!$album->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(600, "Insufficient rights to this album");
|
||||
}
|
||||
|
||||
$album->delete();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function moveToAlbum(int $album_id, string $audio_ids): int
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$album = (new Audios())->getPlaylist($album_id);
|
||||
if (!$album) {
|
||||
$this->fail(0o404, "Album not found");
|
||||
} elseif (!$album->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(600, "Insufficient rights to this album");
|
||||
}
|
||||
|
||||
$audios = [];
|
||||
$audio_ids = array_unique(explode(",", $audio_ids));
|
||||
if (sizeof($audio_ids) < 1 || sizeof($audio_ids) > 1000) {
|
||||
$this->fail(8, "audio_ids must contain at least 1 audio and at most 1000");
|
||||
}
|
||||
|
||||
foreach ($audio_ids as $audio_id) {
|
||||
$audio = $this->audioFromAnyId($audio_id);
|
||||
if (!$audio) {
|
||||
continue;
|
||||
} elseif (!$audio->canBeViewedBy($this->getUser())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$audios[] = $audio;
|
||||
}
|
||||
|
||||
if (sizeof($audios) < 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$res = 1;
|
||||
try {
|
||||
foreach ($audios as $audio) {
|
||||
$res = min($res, (int) $album->add($audio));
|
||||
}
|
||||
} catch (\OutOfBoundsException $ex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function removeFromAlbum(int $album_id, string $audio_ids): int
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$album = (new Audios())->getPlaylist($album_id);
|
||||
if (!$album) {
|
||||
$this->fail(0o404, "Album not found");
|
||||
} elseif (!$album->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(600, "Insufficient rights to this album");
|
||||
}
|
||||
|
||||
$audios = [];
|
||||
$audio_ids = array_unique(explode(",", $audio_ids));
|
||||
if (sizeof($audio_ids) < 1 || sizeof($audio_ids) > 1000) {
|
||||
$this->fail(8, "audio_ids must contain at least 1 audio and at most 1000");
|
||||
}
|
||||
|
||||
foreach ($audio_ids as $audio_id) {
|
||||
$audio = $this->audioFromAnyId($audio_id);
|
||||
if (!$audio) {
|
||||
continue;
|
||||
} elseif ($audio->canBeViewedBy($this->getUser())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$audios[] = $audio;
|
||||
}
|
||||
|
||||
if (sizeof($audios) < 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
foreach ($audios as $audio) {
|
||||
$album->remove($audio);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function copyToAlbum(int $album_id, string $audio_ids): int
|
||||
{
|
||||
return $this->moveToAlbum($album_id, $audio_ids);
|
||||
}
|
||||
|
||||
public function bookmarkAlbum(int $id): int
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$album = (new Audios())->getPlaylist($id);
|
||||
if (!$album) {
|
||||
$this->fail(0o404, "Not found");
|
||||
}
|
||||
|
||||
if (!$album->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(600, "Access error");
|
||||
}
|
||||
|
||||
return (int) $album->bookmark($this->getUser());
|
||||
}
|
||||
|
||||
public function unBookmarkAlbum(int $id): int
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$album = (new Audios())->getPlaylist($id);
|
||||
if (!$album) {
|
||||
$this->fail(0o404, "Not found");
|
||||
}
|
||||
|
||||
if (!$album->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(600, "Access error");
|
||||
}
|
||||
|
||||
return (int) $album->unbookmark($this->getUser());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
|
||||
use openvk\VKAPI\Handlers\Wall;
|
||||
use openvk\Web\Models\Repositories\Topics as TopicsRepo;
|
||||
use openvk\Web\Models\Repositories\Clubs as ClubsRepo;
|
||||
|
@ -11,27 +15,28 @@ use openvk\Web\Models\Entities\{Topic, Comment, User, Photo, Video};
|
|||
final class Board extends VKAPIRequestHandler
|
||||
{
|
||||
# 13/13
|
||||
function addTopic(int $group_id, string $title, string $text = "", bool $from_group = true, string $attachments = "")
|
||||
public function addTopic(int $group_id, string $title, string $text = "", bool $from_group = true, string $attachments = "")
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$club = (new ClubsRepo)->get($group_id);
|
||||
$club = (new ClubsRepo())->get($group_id);
|
||||
|
||||
if(!$club) {
|
||||
if (!$club) {
|
||||
$this->fail(403, "Invalid club");
|
||||
}
|
||||
|
||||
if(!$club->canBeModifiedBy($this->getUser()) && !$club->isEveryoneCanCreateTopics()) {
|
||||
if (!$club->canBeModifiedBy($this->getUser()) && !$club->isEveryoneCanCreateTopics()) {
|
||||
$this->fail(403, "Access to club denied");
|
||||
}
|
||||
|
||||
$flags = 0;
|
||||
|
||||
if($from_group == true && $club->canBeModifiedBy($this->getUser()))
|
||||
if ($from_group == true && $club->canBeModifiedBy($this->getUser())) {
|
||||
$flags |= 0b10000000;
|
||||
}
|
||||
|
||||
$topic = new Topic;
|
||||
$topic = new Topic();
|
||||
$topic->setGroup($club->getId());
|
||||
$topic->setOwner($this->getUser()->getId());
|
||||
$topic->setTitle(ovk_proc_strtr($title, 127));
|
||||
|
@ -39,8 +44,8 @@ final class Board extends VKAPIRequestHandler
|
|||
$topic->setFlags($flags);
|
||||
$topic->save();
|
||||
|
||||
if(!empty($text)) {
|
||||
$comment = new Comment;
|
||||
if (!empty($text)) {
|
||||
$comment = new Comment();
|
||||
$comment->setOwner($this->getUser()->getId());
|
||||
$comment->setModel(get_class($topic));
|
||||
$comment->setTarget($topic->getId());
|
||||
|
@ -49,44 +54,50 @@ final class Board extends VKAPIRequestHandler
|
|||
$comment->setFlags($flags);
|
||||
$comment->save();
|
||||
|
||||
if(!empty($attachments)) {
|
||||
if (!empty($attachments)) {
|
||||
$attachmentsArr = explode(",", $attachments);
|
||||
# блин а мне это везде копировать типа
|
||||
|
||||
if(sizeof($attachmentsArr) > 10)
|
||||
if (sizeof($attachmentsArr) > 10) {
|
||||
$this->fail(50, "Error: too many attachments");
|
||||
}
|
||||
|
||||
foreach($attachmentsArr as $attac) {
|
||||
$attachmentType = NULL;
|
||||
foreach ($attachmentsArr as $attac) {
|
||||
$attachmentType = null;
|
||||
|
||||
if(str_contains($attac, "photo"))
|
||||
if (str_contains($attac, "photo")) {
|
||||
$attachmentType = "photo";
|
||||
elseif(str_contains($attac, "video"))
|
||||
} elseif (str_contains($attac, "video")) {
|
||||
$attachmentType = "video";
|
||||
else
|
||||
} else {
|
||||
$this->fail(205, "Unknown attachment type");
|
||||
}
|
||||
|
||||
$attachment = str_replace($attachmentType, "", $attac);
|
||||
|
||||
$attachmentOwner = (int)explode("_", $attachment)[0];
|
||||
$attachmentId = (int)end(explode("_", $attachment));
|
||||
$attachmentOwner = (int) explode("_", $attachment)[0];
|
||||
$attachmentId = (int) end(explode("_", $attachment));
|
||||
|
||||
$attacc = NULL;
|
||||
$attacc = null;
|
||||
|
||||
if($attachmentType == "photo") {
|
||||
$attacc = (new PhotosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if(!$attacc || $attacc->isDeleted())
|
||||
if ($attachmentType == "photo") {
|
||||
$attacc = (new PhotosRepo())->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if (!$attacc || $attacc->isDeleted()) {
|
||||
$this->fail(100, "Photo does not exists");
|
||||
if($attacc->getOwner()->getId() != $this->getUser()->getId())
|
||||
}
|
||||
if ($attacc->getOwner()->getId() != $this->getUser()->getId()) {
|
||||
$this->fail(43, "You do not have access to this photo");
|
||||
}
|
||||
|
||||
$comment->attach($attacc);
|
||||
} elseif($attachmentType == "video") {
|
||||
$attacc = (new VideosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if(!$attacc || $attacc->isDeleted())
|
||||
} elseif ($attachmentType == "video") {
|
||||
$attacc = (new VideosRepo())->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if (!$attacc || $attacc->isDeleted()) {
|
||||
$this->fail(100, "Video does not exists");
|
||||
if($attacc->getOwner()->getId() != $this->getUser()->getId())
|
||||
}
|
||||
if ($attacc->getOwner()->getId() != $this->getUser()->getId()) {
|
||||
$this->fail(43, "You do not have access to this video");
|
||||
}
|
||||
|
||||
$comment->attach($attacc);
|
||||
}
|
||||
|
@ -100,18 +111,18 @@ final class Board extends VKAPIRequestHandler
|
|||
return $topic->getId();
|
||||
}
|
||||
|
||||
function closeTopic(int $group_id, int $topic_id)
|
||||
public function closeTopic(int $group_id, int $topic_id)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$topic = (new TopicsRepo)->getTopicById($group_id, $topic_id);
|
||||
$topic = (new TopicsRepo())->getTopicById($group_id, $topic_id);
|
||||
|
||||
if(!$topic || !$topic->getClub() || !$topic->getClub()->canBeModifiedBy($this->getUser())) {
|
||||
if (!$topic || !$topic->getClub() || !$topic->getClub()->canBeModifiedBy($this->getUser())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!$topic->isClosed()) {
|
||||
if (!$topic->isClosed()) {
|
||||
$topic->setClosed(1);
|
||||
$topic->save();
|
||||
}
|
||||
|
@ -119,31 +130,32 @@ final class Board extends VKAPIRequestHandler
|
|||
return 1;
|
||||
}
|
||||
|
||||
function createComment(int $group_id, int $topic_id, string $message = "", string $attachments = "", bool $from_group = true)
|
||||
public function createComment(int $group_id, int $topic_id, string $message = "", string $attachments = "", bool $from_group = true)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if(empty($message) && empty($attachments)) {
|
||||
if (empty($message) && empty($attachments)) {
|
||||
$this->fail(100, "Required parameter 'message' missing.");
|
||||
}
|
||||
|
||||
$topic = (new TopicsRepo)->getTopicById($group_id, $topic_id);
|
||||
$topic = (new TopicsRepo())->getTopicById($group_id, $topic_id);
|
||||
|
||||
if(!$topic || $topic->isDeleted() || $topic->isClosed()) {
|
||||
if (!$topic || $topic->isDeleted() || $topic->isClosed()) {
|
||||
$this->fail(100, "Topic is deleted, closed or invalid.");
|
||||
}
|
||||
|
||||
$flags = 0;
|
||||
|
||||
if($from_group != 0 && !is_null($topic->getClub()) && $topic->getClub()->canBeModifiedBy($this->user))
|
||||
if ($from_group != 0 && !is_null($topic->getClub()) && $topic->getClub()->canBeModifiedBy($this->user)) {
|
||||
$flags |= 0b10000000;
|
||||
}
|
||||
|
||||
if(strlen($message) > 300) {
|
||||
if (strlen($message) > 300) {
|
||||
$this->fail(20, "Comment is too long.");
|
||||
}
|
||||
|
||||
$comment = new Comment;
|
||||
$comment = new Comment();
|
||||
$comment->setOwner($this->getUser()->getId());
|
||||
$comment->setModel(get_class($topic));
|
||||
$comment->setTarget($topic->getId());
|
||||
|
@ -152,43 +164,49 @@ final class Board extends VKAPIRequestHandler
|
|||
$comment->setFlags($flags);
|
||||
$comment->save();
|
||||
|
||||
if(!empty($attachments)) {
|
||||
if (!empty($attachments)) {
|
||||
$attachmentsArr = explode(",", $attachments);
|
||||
|
||||
if(sizeof($attachmentsArr) > 10)
|
||||
if (sizeof($attachmentsArr) > 10) {
|
||||
$this->fail(50, "Error: too many attachments");
|
||||
}
|
||||
|
||||
foreach($attachmentsArr as $attac) {
|
||||
$attachmentType = NULL;
|
||||
foreach ($attachmentsArr as $attac) {
|
||||
$attachmentType = null;
|
||||
|
||||
if(str_contains($attac, "photo"))
|
||||
if (str_contains($attac, "photo")) {
|
||||
$attachmentType = "photo";
|
||||
elseif(str_contains($attac, "video"))
|
||||
} elseif (str_contains($attac, "video")) {
|
||||
$attachmentType = "video";
|
||||
else
|
||||
} else {
|
||||
$this->fail(205, "Unknown attachment type");
|
||||
}
|
||||
|
||||
$attachment = str_replace($attachmentType, "", $attac);
|
||||
|
||||
$attachmentOwner = (int)explode("_", $attachment)[0];
|
||||
$attachmentId = (int)end(explode("_", $attachment));
|
||||
$attachmentOwner = (int) explode("_", $attachment)[0];
|
||||
$attachmentId = (int) end(explode("_", $attachment));
|
||||
|
||||
$attacc = NULL;
|
||||
$attacc = null;
|
||||
|
||||
if($attachmentType == "photo") {
|
||||
$attacc = (new PhotosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if(!$attacc || $attacc->isDeleted())
|
||||
if ($attachmentType == "photo") {
|
||||
$attacc = (new PhotosRepo())->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if (!$attacc || $attacc->isDeleted()) {
|
||||
$this->fail(100, "Photo does not exists");
|
||||
if($attacc->getOwner()->getId() != $this->getUser()->getId())
|
||||
}
|
||||
if ($attacc->getOwner()->getId() != $this->getUser()->getId()) {
|
||||
$this->fail(43, "You do not have access to this photo");
|
||||
}
|
||||
|
||||
$comment->attach($attacc);
|
||||
} elseif($attachmentType == "video") {
|
||||
$attacc = (new VideosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if(!$attacc || $attacc->isDeleted())
|
||||
} elseif ($attachmentType == "video") {
|
||||
$attacc = (new VideosRepo())->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if (!$attacc || $attacc->isDeleted()) {
|
||||
$this->fail(100, "Video does not exists");
|
||||
if($attacc->getOwner()->getId() != $this->getUser()->getId())
|
||||
}
|
||||
if ($attacc->getOwner()->getId() != $this->getUser()->getId()) {
|
||||
$this->fail(43, "You do not have access to this video");
|
||||
}
|
||||
|
||||
$comment->attach($attacc);
|
||||
}
|
||||
|
@ -198,29 +216,30 @@ final class Board extends VKAPIRequestHandler
|
|||
return $comment->getId();
|
||||
}
|
||||
|
||||
function deleteComment(int $comment_id, int $group_id = 0, int $topic_id = 0)
|
||||
public function deleteComment(int $comment_id, int $group_id = 0, int $topic_id = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$comment = (new CommentsRepo)->get($comment_id);
|
||||
$comment = (new CommentsRepo())->get($comment_id);
|
||||
|
||||
if($comment->isDeleted() || !$comment || !$comment->canBeDeletedBy($this->getUser()))
|
||||
if ($comment->isDeleted() || !$comment || !$comment->canBeDeletedBy($this->getUser())) {
|
||||
$this->fail(403, "Access to comment denied");
|
||||
}
|
||||
|
||||
$comment->delete();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function deleteTopic(int $group_id, int $topic_id)
|
||||
public function deleteTopic(int $group_id, int $topic_id)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$topic = (new TopicsRepo)->getTopicById($group_id, $topic_id);
|
||||
$topic = (new TopicsRepo())->getTopicById($group_id, $topic_id);
|
||||
|
||||
if(!$topic || !$topic->getClub() || $topic->isDeleted() || !$topic->getClub()->canBeModifiedBy($this->getUser())) {
|
||||
if (!$topic || !$topic->getClub() || $topic->isDeleted() || !$topic->getClub()->canBeModifiedBy($this->getUser())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -229,7 +248,7 @@ final class Board extends VKAPIRequestHandler
|
|||
return 1;
|
||||
}
|
||||
|
||||
function editComment(int $comment_id, int $group_id = 0, int $topic_id = 0, string $message, string $attachments)
|
||||
public function editComment(int $comment_id, int $group_id = 0, int $topic_id = 0, string $message, string $attachments)
|
||||
{
|
||||
/*
|
||||
$this->requireUser();
|
||||
|
@ -247,14 +266,14 @@ final class Board extends VKAPIRequestHandler
|
|||
return 1;
|
||||
}
|
||||
|
||||
function editTopic(int $group_id, int $topic_id, string $title)
|
||||
public function editTopic(int $group_id, int $topic_id, string $title)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$topic = (new TopicsRepo)->getTopicById($group_id, $topic_id);
|
||||
$topic = (new TopicsRepo())->getTopicById($group_id, $topic_id);
|
||||
|
||||
if(!$topic || !$topic->getClub() || $topic->isDeleted() || !$topic->getClub()->canBeModifiedBy($this->getUser())) {
|
||||
if (!$topic || !$topic->getClub() || $topic->isDeleted() || !$topic->getClub()->canBeModifiedBy($this->getUser())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -265,14 +284,14 @@ final class Board extends VKAPIRequestHandler
|
|||
return 1;
|
||||
}
|
||||
|
||||
function fixTopic(int $group_id, int $topic_id)
|
||||
public function fixTopic(int $group_id, int $topic_id)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$topic = (new TopicsRepo)->getTopicById($group_id, $topic_id);
|
||||
$topic = (new TopicsRepo())->getTopicById($group_id, $topic_id);
|
||||
|
||||
if(!$topic || !$topic->getClub() || !$topic->getClub()->canBeModifiedBy($this->getUser())) {
|
||||
if (!$topic || !$topic->getClub() || !$topic->getClub()->canBeModifiedBy($this->getUser())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -283,32 +302,31 @@ final class Board extends VKAPIRequestHandler
|
|||
return 1;
|
||||
}
|
||||
|
||||
function getComments(int $group_id, int $topic_id, bool $need_likes = false, int $start_comment_id = 0, int $offset = 0, int $count = 40, bool $extended = false, string $sort = "asc")
|
||||
public function getComments(int $group_id, int $topic_id, bool $need_likes = false, int $start_comment_id = 0, int $offset = 0, int $count = 40, bool $extended = false, string $sort = "asc")
|
||||
{
|
||||
# start_comment_id ne robit
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$topic = (new TopicsRepo)->getTopicById($group_id, $topic_id);
|
||||
$topic = (new TopicsRepo())->getTopicById($group_id, $topic_id);
|
||||
|
||||
if(!$topic || !$topic->getClub() || $topic->isDeleted()) {
|
||||
if (!$topic || !$topic->getClub() || $topic->isDeleted()) {
|
||||
$this->fail(5, "Invalid topic");
|
||||
}
|
||||
|
||||
$arr = [
|
||||
"items" => []
|
||||
"items" => [],
|
||||
];
|
||||
|
||||
$comms = array_slice(iterator_to_array($topic->getComments(1, $count + $offset)), $offset);
|
||||
foreach($comms as $comm) {
|
||||
foreach ($comms as $comm) {
|
||||
$arr["items"][] = $this->getApiBoardComment($comm, $need_likes);
|
||||
|
||||
if($extended) {
|
||||
if($comm->getOwner() instanceof \openvk\Web\Models\Entities\User) {
|
||||
if ($extended) {
|
||||
if ($comm->getOwner() instanceof \openvk\Web\Models\Entities\User) {
|
||||
$arr["profiles"][] = $comm->getOwner()->toVkApiStruct();
|
||||
}
|
||||
|
||||
if($comm->getOwner() instanceof \openvk\Web\Models\Entities\Club) {
|
||||
if ($comm->getOwner() instanceof \openvk\Web\Models\Entities\Club) {
|
||||
$arr["groups"][] = $comm->getOwner()->toVkApiStruct();
|
||||
}
|
||||
}
|
||||
|
@ -317,35 +335,36 @@ final class Board extends VKAPIRequestHandler
|
|||
return $arr;
|
||||
}
|
||||
|
||||
function getTopics(int $group_id, string $topic_ids = "", int $order = 1, int $offset = 0, int $count = 40, bool $extended = false, int $preview = 0, int $preview_length = 90)
|
||||
public function getTopics(int $group_id, string $topic_ids = "", int $order = 1, int $offset = 0, int $count = 40, bool $extended = false, int $preview = 0, int $preview_length = 90)
|
||||
{
|
||||
# order и extended ничё не делают
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$arr = [];
|
||||
$club = (new ClubsRepo)->get($group_id);
|
||||
$club = (new ClubsRepo())->get($group_id);
|
||||
|
||||
$topics = array_slice(iterator_to_array((new TopicsRepo)->getClubTopics($club, 1, $count + $offset)), $offset);
|
||||
$arr["count"] = (new TopicsRepo)->getClubTopicsCount($club);
|
||||
$topics = array_slice(iterator_to_array((new TopicsRepo())->getClubTopics($club, 1, $count + $offset)), $offset);
|
||||
$arr["count"] = (new TopicsRepo())->getClubTopicsCount($club);
|
||||
$arr["items"] = [];
|
||||
$arr["default_order"] = $order;
|
||||
$arr["can_add_topics"] = $club->canBeModifiedBy($this->getUser()) ? true : $club->isEveryoneCanCreateTopics() ? true : false;
|
||||
$arr["can_add_topics"] = $club->canBeModifiedBy($this->getUser()) ? true : ($club->isEveryoneCanCreateTopics() ? true : false);
|
||||
$arr["profiles"] = [];
|
||||
|
||||
if(empty($topic_ids)) {
|
||||
foreach($topics as $topic) {
|
||||
if($topic->isDeleted()) continue;
|
||||
if (empty($topic_ids)) {
|
||||
foreach ($topics as $topic) {
|
||||
if ($topic->isDeleted()) {
|
||||
continue;
|
||||
}
|
||||
$arr["items"][] = $topic->toVkApiStruct($preview, $preview_length > 1 ? $preview_length : 90);
|
||||
}
|
||||
} else {
|
||||
$topics = explode(',', $topic_ids);
|
||||
|
||||
foreach($topics as $topic) {
|
||||
foreach ($topics as $topic) {
|
||||
$id = explode("_", $topic);
|
||||
$topicy = (new TopicsRepo)->getTopicById((int)$id[0], (int)$id[1]);
|
||||
$topicy = (new TopicsRepo())->getTopicById((int) $id[0], (int) $id[1]);
|
||||
|
||||
if($topicy && !$topicy->isDeleted()) {
|
||||
if ($topicy && !$topicy->isDeleted()) {
|
||||
$arr["items"][] = $topicy->toVkApiStruct($preview, $preview_length > 1 ? $preview_length : 90);
|
||||
}
|
||||
}
|
||||
|
@ -354,18 +373,18 @@ final class Board extends VKAPIRequestHandler
|
|||
return $arr;
|
||||
}
|
||||
|
||||
function openTopic(int $group_id, int $topic_id)
|
||||
public function openTopic(int $group_id, int $topic_id)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$topic = (new TopicsRepo)->getTopicById($group_id, $topic_id);
|
||||
$topic = (new TopicsRepo())->getTopicById($group_id, $topic_id);
|
||||
|
||||
if(!$topic || !$topic->getClub() || !$topic->isDeleted() || !$topic->getClub()->canBeModifiedBy($this->getUser())) {
|
||||
if (!$topic || !$topic->getClub() || !$topic->isDeleted() || !$topic->getClub()->canBeModifiedBy($this->getUser())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if($topic->isClosed()) {
|
||||
if ($topic->isClosed()) {
|
||||
$topic->setClosed(0);
|
||||
$topic->save();
|
||||
}
|
||||
|
@ -373,23 +392,23 @@ final class Board extends VKAPIRequestHandler
|
|||
return 1;
|
||||
}
|
||||
|
||||
function restoreComment(int $group_id, int $topic_id, int $comment_id)
|
||||
public function restoreComment(int $group_id, int $topic_id, int $comment_id)
|
||||
{
|
||||
$this->fail(501, "Not implemented");
|
||||
}
|
||||
|
||||
function unfixTopic(int $group_id, int $topic_id)
|
||||
public function unfixTopic(int $group_id, int $topic_id)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$topic = (new TopicsRepo)->getTopicById($group_id, $topic_id);
|
||||
$topic = (new TopicsRepo())->getTopicById($group_id, $topic_id);
|
||||
|
||||
if(!$topic || !$topic->getClub() || !$topic->getClub()->canBeModifiedBy($this->getUser())) {
|
||||
if (!$topic || !$topic->getClub() || !$topic->getClub()->canBeModifiedBy($this->getUser())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if($topic->isPinned()) {
|
||||
if ($topic->isPinned()) {
|
||||
$topic->setClosed(0);
|
||||
$topic->save();
|
||||
}
|
||||
|
@ -411,17 +430,18 @@ final class Board extends VKAPIRequestHandler
|
|||
$res->text = $comment->getText(false);
|
||||
$res->attachments = [];
|
||||
$res->likes = [];
|
||||
if($need_likes) {
|
||||
if ($need_likes) {
|
||||
$res->likes = [
|
||||
"count" => $comment->getLikesCount(),
|
||||
"user_likes" => (int) $comment->hasLikeFrom($this->getUser()),
|
||||
"can_like" => 1 # а чё типо не может ахахаххахах
|
||||
"can_like" => 1, # а чё типо не может ахахаххахах
|
||||
];
|
||||
}
|
||||
|
||||
foreach($comment->getChildren() as $attachment) {
|
||||
if($attachment->isDeleted())
|
||||
foreach ($comment->getChildren() as $attachment) {
|
||||
if ($attachment->isDeleted()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$res->attachments[] = $attachment->toVkApiStruct();
|
||||
}
|
||||
|
|
242
VKAPI/Handlers/Docs.php
Normal file
242
VKAPI/Handlers/Docs.php
Normal file
|
@ -0,0 +1,242 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
use openvk\Web\Models\Entities\Document;
|
||||
use openvk\Web\Models\Repositories\Documents;
|
||||
|
||||
final class Docs extends VKAPIRequestHandler
|
||||
{
|
||||
public function add(int $owner_id, int $doc_id, ?string $access_key): string
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$doc = (new Documents())->getDocumentById($owner_id, $doc_id, $access_key);
|
||||
if (!$doc || $doc->isDeleted()) {
|
||||
$this->fail(1150, "Invalid document id");
|
||||
}
|
||||
|
||||
if (!$doc->checkAccessKey($access_key)) {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
if ($doc->isCopiedBy($this->getUser())) {
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: this document already added");
|
||||
}
|
||||
|
||||
$new_doc = $doc->copy($this->getUser());
|
||||
|
||||
return $new_doc->getPrettyId();
|
||||
}
|
||||
|
||||
public function delete(int $owner_id, int $doc_id): int
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
$doc = (new Documents())->getDocumentByIdUnsafe($owner_id, $doc_id);
|
||||
if (!$doc || $doc->isDeleted()) {
|
||||
$this->fail(1150, "Invalid document id");
|
||||
}
|
||||
|
||||
if (!$doc->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(1153, "Access to document is denied");
|
||||
}
|
||||
|
||||
$doc->delete();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function restore(int $owner_id, int $doc_id): int
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
return $this->add($owner_id, $doc_id, "");
|
||||
}
|
||||
|
||||
public function edit(int $owner_id, int $doc_id, ?string $title = "", ?string $tags = "", ?int $folder_id = 0, int $owner_hidden = -1): int
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$doc = (new Documents())->getDocumentByIdUnsafe($owner_id, $doc_id);
|
||||
if (!$doc || $doc->isDeleted()) {
|
||||
$this->fail(1150, "Invalid document id");
|
||||
}
|
||||
if (!$doc->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(1153, "Access to document is denied");
|
||||
}
|
||||
if (iconv_strlen($title ?? "") > 128 || iconv_strlen($title ?? "") < 0) {
|
||||
$this->fail(1152, "Invalid document title");
|
||||
}
|
||||
if (iconv_strlen($tags ?? "") > 256) {
|
||||
$this->fail(1154, "Invalid tags");
|
||||
}
|
||||
|
||||
if ($title) {
|
||||
$doc->setName($title);
|
||||
}
|
||||
|
||||
$doc->setTags($tags);
|
||||
if (in_array($folder_id, [0, 3])) {
|
||||
$doc->setFolder_id($folder_id);
|
||||
}
|
||||
if (in_array($owner_hidden, [0, 1])) {
|
||||
$doc->setOwner_hidden($owner_hidden);
|
||||
}
|
||||
|
||||
try {
|
||||
$doc->setEdited(time());
|
||||
$doc->save();
|
||||
} catch (\Throwable $e) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function get(int $count = 30, int $offset = 0, int $type = -1, int $owner_id = null, int $return_tags = 0, int $order = 0): object
|
||||
{
|
||||
$this->requireUser();
|
||||
if (!$owner_id) {
|
||||
$owner_id = $this->getUser()->getId();
|
||||
}
|
||||
|
||||
if ($owner_id > 0 && $owner_id != $this->getUser()->getId()) {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
$documents = (new Documents())->getDocumentsByOwner($owner_id, $order, $type);
|
||||
$res = (object) [
|
||||
"count" => $documents->size(),
|
||||
"items" => [],
|
||||
];
|
||||
|
||||
foreach ($documents->offsetLimit($offset, $count) as $doc) {
|
||||
$res->items[] = $doc->toVkApiStruct($this->getUser(), $return_tags == 1);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function getById(string $docs, int $return_tags = 0): array
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$item_ids = explode(",", $docs);
|
||||
$response = [];
|
||||
if (sizeof($item_ids) < 1) {
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: docs is undefined");
|
||||
}
|
||||
|
||||
foreach ($item_ids as $id) {
|
||||
$splitted_id = explode("_", $id);
|
||||
$doc = (new Documents())->getDocumentById((int) $splitted_id[0], (int) $splitted_id[1], $splitted_id[2]);
|
||||
if (!$doc || $doc->isDeleted()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$response[] = $doc->toVkApiStruct($this->getUser(), $return_tags === 1);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function getTypes(?int $owner_id)
|
||||
{
|
||||
$this->requireUser();
|
||||
if (!$owner_id) {
|
||||
$owner_id = $this->getUser()->getId();
|
||||
}
|
||||
|
||||
if ($owner_id > 0 && $owner_id != $this->getUser()->getId()) {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
$types = (new Documents())->getTypes($owner_id);
|
||||
return [
|
||||
"count" => sizeof($types),
|
||||
"items" => $types,
|
||||
];
|
||||
}
|
||||
|
||||
public function getTags(?int $owner_id, ?int $type = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
if (!$owner_id) {
|
||||
$owner_id = $this->getUser()->getId();
|
||||
}
|
||||
|
||||
if ($owner_id > 0 && $owner_id != $this->getUser()->getId()) {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
$tags = (new Documents())->getTags($owner_id, $type);
|
||||
return $tags;
|
||||
}
|
||||
|
||||
public function search(string $q = "", int $search_own = -1, int $order = -1, int $count = 30, int $offset = 0, int $return_tags = 0, int $type = 0, ?string $tags = null): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$params = [];
|
||||
$o_order = ["type" => "id", "invert" => false];
|
||||
|
||||
if (iconv_strlen($q) > 512) {
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: q should be not more 512 letters length");
|
||||
}
|
||||
|
||||
if (in_array($type, [1,2,3,4,5,6,7,8])) {
|
||||
$params["type"] = $type;
|
||||
}
|
||||
|
||||
if (iconv_strlen($tags ?? "") < 512) {
|
||||
$params["tags"] = $tags;
|
||||
}
|
||||
|
||||
if ($search_own === 1) {
|
||||
$params["from_me"] = $this->getUser()->getId();
|
||||
}
|
||||
|
||||
$documents = (new Documents())->find($q, $params, $o_order);
|
||||
$res = (object) [
|
||||
"count" => $documents->size(),
|
||||
"items" => [],
|
||||
];
|
||||
|
||||
foreach ($documents->offsetLimit($offset, $count) as $doc) {
|
||||
$res->items[] = $doc->toVkApiStruct($this->getUser(), $return_tags == 1);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function getUploadServer(?int $group_id = null)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getWallUploadServer(?int $group_id = null)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function save(string $file, string $title, string $tags, ?int $return_tags = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -1,20 +1,38 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
|
||||
use openvk\Web\Models\Repositories\Users as UsersRepo;
|
||||
|
||||
final class Friends extends VKAPIRequestHandler
|
||||
{
|
||||
function get(int $user_id, string $fields = "", int $offset = 0, int $count = 100): object
|
||||
public function get(int $user_id = 0, string $fields = "", int $offset = 0, int $count = 100): object
|
||||
{
|
||||
$i = 0;
|
||||
$offset++;
|
||||
$friends = [];
|
||||
|
||||
$users = new UsersRepo;
|
||||
$users = new UsersRepo();
|
||||
|
||||
$this->requireUser();
|
||||
|
||||
foreach($users->get($user_id)->getFriends($offset, $count) as $friend) {
|
||||
if ($user_id == 0) {
|
||||
$user_id = $this->getUser()->getId();
|
||||
}
|
||||
|
||||
$user = $users->get($user_id);
|
||||
|
||||
if (!$user || $user->isDeleted()) {
|
||||
$this->fail(100, "Invalid user");
|
||||
}
|
||||
|
||||
if (!$user->getPrivacyPermission("friends.read", $this->getUser())) {
|
||||
$this->fail(15, "Access denied: this user chose to hide his friends.");
|
||||
}
|
||||
|
||||
foreach ($user->getFriends($offset, $count) as $friend) {
|
||||
$friends[$i] = $friend->getId();
|
||||
$i++;
|
||||
}
|
||||
|
@ -23,61 +41,62 @@ final class Friends extends VKAPIRequestHandler
|
|||
|
||||
$usersApi = new Users($this->getUser());
|
||||
|
||||
if(!is_null($fields))
|
||||
$response = $usersApi->get(implode(',', $friends), $fields, 0, $count); # FIXME
|
||||
if (!is_null($fields)) {
|
||||
$response = $usersApi->get(implode(',', $friends), $fields, 0, $count);
|
||||
} # FIXME
|
||||
|
||||
return (object) [
|
||||
"count" => $users->get($user_id)->getFriendsCount(),
|
||||
"items" => $response
|
||||
"items" => $response,
|
||||
];
|
||||
}
|
||||
|
||||
function getLists(): object
|
||||
public function getLists(): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
return (object) [
|
||||
"count" => 0,
|
||||
"items" => (array)[]
|
||||
"items" => (array) [],
|
||||
];
|
||||
}
|
||||
|
||||
function deleteList(): int
|
||||
public function deleteList(): int
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function edit(): int
|
||||
public function edit(): int
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function editList(): int
|
||||
public function editList(): int
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function add(string $user_id): int
|
||||
public function add(string $user_id): int
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$users = new UsersRepo;
|
||||
$users = new UsersRepo();
|
||||
$user = $users->get(intval($user_id));
|
||||
|
||||
if(is_null($user)) {
|
||||
if (is_null($user)) {
|
||||
$this->fail(177, "Cannot add this user to friends as user not found");
|
||||
} else if($user->getId() == $this->getUser()->getId()) {
|
||||
} elseif ($user->getId() == $this->getUser()->getId()) {
|
||||
$this->fail(174, "Cannot add user himself as friend");
|
||||
}
|
||||
|
||||
switch($user->getSubscriptionStatus($this->getUser())) {
|
||||
switch ($user->getSubscriptionStatus($this->getUser())) {
|
||||
case 0:
|
||||
$user->toggleSubscription($this->getUser());
|
||||
return 1;
|
||||
|
@ -94,16 +113,16 @@ final class Friends extends VKAPIRequestHandler
|
|||
}
|
||||
}
|
||||
|
||||
function delete(string $user_id): int
|
||||
public function delete(string $user_id): int
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$users = new UsersRepo;
|
||||
$users = new UsersRepo();
|
||||
|
||||
$user = $users->get(intval($user_id));
|
||||
|
||||
switch($user->getSubscriptionStatus($this->getUser())) {
|
||||
switch ($user->getSubscriptionStatus($this->getUser())) {
|
||||
case 3:
|
||||
$user->toggleSubscription($this->getUser());
|
||||
return 1;
|
||||
|
@ -113,32 +132,33 @@ final class Friends extends VKAPIRequestHandler
|
|||
}
|
||||
}
|
||||
|
||||
function areFriends(string $user_ids): array
|
||||
public function areFriends(string $user_ids): array
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$users = new UsersRepo;
|
||||
$users = new UsersRepo();
|
||||
|
||||
$friends = explode(',', $user_ids);
|
||||
|
||||
$response = [];
|
||||
|
||||
for($i=0; $i < sizeof($friends); $i++) {
|
||||
for ($i = 0; $i < sizeof($friends); $i++) {
|
||||
$friend = $users->get(intval($friends[$i]));
|
||||
|
||||
$response[] = (object)[
|
||||
$response[] = (object) [
|
||||
"friend_status" => $friend->getSubscriptionStatus($this->getUser()),
|
||||
"user_id" => $friend->getId()
|
||||
"user_id" => $friend->getId(),
|
||||
];
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
function getRequests(string $fields = "", int $offset = 0, int $count = 100, int $extended = 0): object
|
||||
public function getRequests(string $fields = "", int $out = 0, int $offset = 0, int $count = 100, int $extended = 0): object
|
||||
{
|
||||
if ($count >= 1000)
|
||||
if ($count >= 1000) {
|
||||
$this->fail(100, "One of the required parameters was not passed or is invalid.");
|
||||
}
|
||||
|
||||
$this->requireUser();
|
||||
|
||||
|
@ -146,22 +166,30 @@ final class Friends extends VKAPIRequestHandler
|
|||
$offset++;
|
||||
$followers = [];
|
||||
|
||||
foreach($this->getUser()->getFollowers($offset, $count) as $follower) {
|
||||
if ($out != 0) {
|
||||
foreach ($this->getUser()->getFollowers($offset, $count) as $follower) {
|
||||
$followers[$i] = $follower->getId();
|
||||
$i++;
|
||||
}
|
||||
} else {
|
||||
foreach ($this->getUser()->getRequests($offset, $count) as $follower) {
|
||||
$followers[$i] = $follower->getId();
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
$response = $followers;
|
||||
$usersApi = new Users($this->getUser());
|
||||
|
||||
$response = $usersApi->get(implode(',', $followers), $fields, 0, $count);
|
||||
|
||||
foreach($response as $user)
|
||||
foreach ($response as $user) {
|
||||
$user->user_id = $user->id;
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"count" => $this->getUser()->getFollowersCount(),
|
||||
"items" => $response
|
||||
"items" => $response,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,90 +1,121 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
|
||||
use openvk\Web\Models\Repositories\Users as UsersRepo;
|
||||
use openvk\Web\Models\Repositories\Gifts as GiftsRepo;
|
||||
use openvk\Web\Models\Entities\Notifications\GiftNotification;
|
||||
|
||||
final class Gifts extends VKAPIRequestHandler
|
||||
{
|
||||
function get(int $user_id, int $count = 10, int $offset = 0)
|
||||
public function get(int $user_id = null, int $count = 10, int $offset = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$i = 0;
|
||||
|
||||
$i += $offset;
|
||||
$server_url = ovk_scheme(true) . $_SERVER["HTTP_HOST"];
|
||||
|
||||
$user = (new UsersRepo)->get($user_id);
|
||||
if ($user_id) {
|
||||
$user = (new UsersRepo())->get($user_id);
|
||||
} else {
|
||||
$user = $this->getUser();
|
||||
}
|
||||
|
||||
if(!$user || $user->isDeleted())
|
||||
if (!$user || $user->isDeleted()) {
|
||||
$this->fail(177, "Invalid user");
|
||||
}
|
||||
|
||||
if (!$user->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
/*
|
||||
if(!$user->getPrivacyPermission('gifts.read', $this->getUser()))
|
||||
$this->fail(15, "Access denied: this user chose to hide his gifts");*/
|
||||
|
||||
|
||||
if (!$user->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
$gift_item = [];
|
||||
|
||||
$userGifts = array_slice(iterator_to_array($user->getGifts(1, $count, false)), $offset);
|
||||
|
||||
if(sizeof($userGifts) < 0) {
|
||||
return NULL;
|
||||
if (sizeof($userGifts) < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach($userGifts as $gift) {
|
||||
if($i < $count) {
|
||||
foreach ($userGifts as $gift) {
|
||||
if ($i < $count) {
|
||||
$gift_item[] = [
|
||||
"id" => $i,
|
||||
"from_id" => $gift->anon == true ? 0 : $gift->sender->getId(),
|
||||
"message" => $gift->caption == NULL ? "" : $gift->caption,
|
||||
"message" => $gift->caption == null ? "" : $gift->caption,
|
||||
"date" => $gift->sent->timestamp(),
|
||||
"gift" => [
|
||||
"id" => $gift->gift->getId(),
|
||||
"thumb_256" => $gift->gift->getImage(2),
|
||||
"thumb_96" => $gift->gift->getImage(2),
|
||||
"thumb_48" => $gift->gift->getImage(2)
|
||||
"thumb_256" => $server_url . $gift->gift->getImage(2),
|
||||
"thumb_96" => $server_url . $gift->gift->getImage(2),
|
||||
"thumb_48" => $server_url . $gift->gift->getImage(2),
|
||||
],
|
||||
"privacy" => 0
|
||||
"privacy" => 0,
|
||||
];
|
||||
}
|
||||
$i+=1;
|
||||
$i += 1;
|
||||
}
|
||||
|
||||
return $gift_item;
|
||||
}
|
||||
|
||||
function send(int $user_ids, int $gift_id, string $message = "", int $privacy = 0)
|
||||
public function send(int $user_ids, int $gift_id, string $message = "", int $privacy = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$user = (new UsersRepo)->get((int) $user_ids);
|
||||
$user = (new UsersRepo())->get((int) $user_ids);
|
||||
|
||||
if(!OPENVK_ROOT_CONF['openvk']['preferences']['commerce'])
|
||||
if (!OPENVK_ROOT_CONF['openvk']['preferences']['commerce']) {
|
||||
$this->fail(105, "Commerce is disabled on this instance");
|
||||
}
|
||||
|
||||
if(!$user || $user->isDeleted())
|
||||
if (!$user || $user->isDeleted()) {
|
||||
$this->fail(177, "Invalid user");
|
||||
}
|
||||
|
||||
$gift = (new GiftsRepo)->get($gift_id);
|
||||
if (!$user->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
if(!$gift)
|
||||
$gift = (new GiftsRepo())->get($gift_id);
|
||||
|
||||
if (!$gift) {
|
||||
$this->fail(165, "Invalid gift");
|
||||
}
|
||||
|
||||
$price = $gift->getPrice();
|
||||
$coinsLeft = $this->getUser()->getCoins() - $price;
|
||||
|
||||
if(!$gift->canUse($this->getUser()))
|
||||
if (!$gift->canUse($this->getUser())) {
|
||||
return (object)
|
||||
[
|
||||
"success" => 0,
|
||||
"user_ids" => $user_ids,
|
||||
"error" => "You don't have any more of these gifts."
|
||||
"error" => "You don't have any more of these gifts.",
|
||||
];
|
||||
}
|
||||
|
||||
if($coinsLeft < 0)
|
||||
if ($coinsLeft < 0) {
|
||||
return (object)
|
||||
[
|
||||
"success" => 0,
|
||||
"user_ids" => $user_ids,
|
||||
"error" => "You don't have enough voices."
|
||||
"error" => "You don't have enough voices.",
|
||||
];
|
||||
}
|
||||
|
||||
$user->gift($this->getUser(), $gift, $message);
|
||||
$gift->used();
|
||||
|
@ -99,11 +130,11 @@ final class Gifts extends VKAPIRequestHandler
|
|||
[
|
||||
"success" => 1,
|
||||
"user_ids" => $user_ids,
|
||||
"withdraw_votes" => $price
|
||||
"withdraw_votes" => $price,
|
||||
];
|
||||
}
|
||||
|
||||
function delete()
|
||||
public function delete()
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
@ -111,27 +142,29 @@ final class Gifts extends VKAPIRequestHandler
|
|||
$this->fail(501, "Not implemented");
|
||||
}
|
||||
|
||||
# этих методов не было в ВК, но я их добавил чтобы можно было отобразить список подарков
|
||||
function getCategories(bool $extended = false, int $page = 1)
|
||||
# в vk кстати называется gifts.getCatalog
|
||||
public function getCategories(bool $extended = false, int $page = 1)
|
||||
{
|
||||
$cats = (new GiftsRepo)->getCategories($page);
|
||||
$cats = (new GiftsRepo())->getCategories($page);
|
||||
$categ = [];
|
||||
$i = 0;
|
||||
$server_url = ovk_scheme(true) . $_SERVER["HTTP_HOST"];
|
||||
|
||||
if(!OPENVK_ROOT_CONF['openvk']['preferences']['commerce'])
|
||||
if (!OPENVK_ROOT_CONF['openvk']['preferences']['commerce']) {
|
||||
$this->fail(105, "Commerce is disabled on this instance");
|
||||
}
|
||||
|
||||
foreach($cats as $cat) {
|
||||
foreach ($cats as $cat) {
|
||||
$categ[$i] = [
|
||||
"name" => $cat->getName(),
|
||||
"description" => $cat->getDescription(),
|
||||
"id" => $cat->getId(),
|
||||
"thumbnail" => $cat->getThumbnailURL(),
|
||||
"thumbnail" => $server_url . $cat->getThumbnailURL(),
|
||||
];
|
||||
|
||||
if($extended == true) {
|
||||
if ($extended == true) {
|
||||
$categ[$i]["localizations"] = [];
|
||||
foreach(getLanguages() as $lang) {
|
||||
foreach (getLanguages() as $lang) {
|
||||
$code = $lang["code"];
|
||||
$categ[$i]["localizations"][$code] =
|
||||
[
|
||||
|
@ -146,26 +179,28 @@ final class Gifts extends VKAPIRequestHandler
|
|||
return $categ;
|
||||
}
|
||||
|
||||
function getGiftsInCategory(int $id, int $page = 1)
|
||||
public function getGiftsInCategory(int $id, int $page = 1)
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
if(!OPENVK_ROOT_CONF['openvk']['preferences']['commerce'])
|
||||
if (!OPENVK_ROOT_CONF['openvk']['preferences']['commerce']) {
|
||||
$this->fail(105, "Commerce is disabled on this instance");
|
||||
}
|
||||
|
||||
if(!(new GiftsRepo)->getCat($id))
|
||||
if (!(new GiftsRepo())->getCat($id)) {
|
||||
$this->fail(177, "Category not found");
|
||||
}
|
||||
|
||||
$giftz = ((new GiftsRepo)->getCat($id))->getGifts($page);
|
||||
$giftz = ((new GiftsRepo())->getCat($id))->getGifts($page);
|
||||
$gifts = [];
|
||||
|
||||
foreach($giftz as $gift) {
|
||||
foreach ($giftz as $gift) {
|
||||
$gifts[] = [
|
||||
"name" => $gift->getName(),
|
||||
"image" => $gift->getImage(2),
|
||||
"usages_left" => (int)$gift->getUsagesLeft($this->getUser()),
|
||||
"price" => $gift->getPrice(), # голосов
|
||||
"is_free" => $gift->isFree()
|
||||
"usages_left" => (int) $gift->getUsagesLeft($this->getUser()),
|
||||
"price" => $gift->getPrice(),
|
||||
"is_free" => $gift->isFree(),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -1,28 +1,46 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
|
||||
use openvk\Web\Models\Repositories\Clubs as ClubsRepo;
|
||||
use openvk\Web\Models\Repositories\Users as UsersRepo;
|
||||
use openvk\Web\Models\Repositories\Posts as PostsRepo;
|
||||
use openvk\Web\Models\Entities\Club;
|
||||
|
||||
final class Groups extends VKAPIRequestHandler
|
||||
{
|
||||
function get(int $user_id = 0, string $fields = "", int $offset = 0, int $count = 6, bool $online = false): object
|
||||
public function get(int $user_id = 0, string $fields = "", int $offset = 0, int $count = 6, bool $online = false, string $filter = "groups"): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
if($user_id == 0) {
|
||||
foreach($this->getUser()->getClubs($offset, false, $count, true) as $club)
|
||||
# InfoApp fix
|
||||
if ($filter == "admin" && ($user_id != 0 && $user_id != $this->getUser()->getId())) {
|
||||
$this->fail(15, 'Access denied: filter admin is available only for current user');
|
||||
}
|
||||
|
||||
$clbs = [];
|
||||
if ($user_id == 0) {
|
||||
foreach ($this->getUser()->getClubs($offset, $filter == "admin", $count, true) as $club) {
|
||||
$clbs[] = $club;
|
||||
}
|
||||
$clbsCount = $this->getUser()->getClubCount();
|
||||
} else {
|
||||
$users = new UsersRepo;
|
||||
$users = new UsersRepo();
|
||||
$user = $users->get($user_id);
|
||||
|
||||
if(is_null($user))
|
||||
if (is_null($user) || $user->isDeleted()) {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
foreach($user->getClubs($offset, false, $count, true) as $club)
|
||||
if (!$user->getPrivacyPermission('groups.read', $this->getUser())) {
|
||||
$this->fail(15, "Access denied: this user chose to hide his groups.");
|
||||
}
|
||||
|
||||
foreach ($user->getClubs($offset, $filter == "admin", $count, true) as $club) {
|
||||
$clbs[] = $club;
|
||||
}
|
||||
|
||||
$clbsCount = $user->getClubCount();
|
||||
}
|
||||
|
@ -30,13 +48,14 @@ final class Groups extends VKAPIRequestHandler
|
|||
$rClubs;
|
||||
|
||||
$ic = sizeof($clbs);
|
||||
if(sizeof($clbs) > $count)
|
||||
if (sizeof($clbs) > $count) {
|
||||
$ic = $count;
|
||||
}
|
||||
|
||||
if(!empty($clbs)) {
|
||||
for($i=0; $i < $ic; $i++) {
|
||||
if (!empty($clbs)) {
|
||||
for ($i = 0; $i < $ic; $i++) {
|
||||
$usr = $clbs[$i];
|
||||
if(is_null($usr)) {
|
||||
if (is_null($usr)) {
|
||||
|
||||
} else {
|
||||
$rClubs[$i] = (object) [
|
||||
|
@ -49,8 +68,8 @@ final class Groups extends VKAPIRequestHandler
|
|||
|
||||
$flds = explode(',', $fields);
|
||||
|
||||
foreach($flds as $field) {
|
||||
switch($field) {
|
||||
foreach ($flds as $field) {
|
||||
switch ($field) {
|
||||
case "verified":
|
||||
$rClubs[$i]->verified = intval($usr->isVerified());
|
||||
break;
|
||||
|
@ -80,6 +99,23 @@ final class Groups extends VKAPIRequestHandler
|
|||
break;
|
||||
case "members_count":
|
||||
$rClubs[$i]->members_count = $usr->getFollowersCount();
|
||||
break;
|
||||
case "can_suggest":
|
||||
$rClubs[$i]->can_suggest = !$usr->canBeModifiedBy($this->getUser()) && $usr->getWallType() == 2;
|
||||
break;
|
||||
case "background":
|
||||
$backgrounds = $usr->getBackDropPictureURLs();
|
||||
$rClubs[$i]->background = $backgrounds;
|
||||
break;
|
||||
# unstandard feild
|
||||
case "suggested_count":
|
||||
if ($usr->getWallType() != 2) {
|
||||
$rClubs[$i]->suggested_count = null;
|
||||
break;
|
||||
}
|
||||
|
||||
$rClubs[$i]->suggested_count = $usr->getSuggestedPostsCount($this->getUser());
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -91,57 +127,62 @@ final class Groups extends VKAPIRequestHandler
|
|||
|
||||
return (object) [
|
||||
"count" => $clbsCount,
|
||||
"items" => $rClubs
|
||||
"items" => $rClubs,
|
||||
];
|
||||
}
|
||||
|
||||
function getById(string $group_ids = "", string $group_id = "", string $fields = "", int $offset = 0, int $count = 500): ?array
|
||||
public 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(empty($group_ids) && !empty($group_id))
|
||||
if (empty($group_ids) && !empty($group_id)) {
|
||||
$group_ids = $group_id;
|
||||
}
|
||||
|
||||
if(empty($group_ids) && empty($group_id))
|
||||
if (empty($group_ids) && empty($group_id)) {
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: group_ids is undefined");
|
||||
}
|
||||
|
||||
$clbs = explode(',', $group_ids);
|
||||
$response = array();
|
||||
$response = [];
|
||||
|
||||
$ic = sizeof($clbs);
|
||||
|
||||
if(sizeof($clbs) > $count)
|
||||
if (sizeof($clbs) > $count) {
|
||||
$ic = $count;
|
||||
}
|
||||
|
||||
$clbs = array_slice($clbs, $offset * $count);
|
||||
|
||||
|
||||
for($i=0; $i < $ic; $i++) {
|
||||
if($i > 500 || $clbs[$i] == 0)
|
||||
for ($i = 0; $i < $ic; $i++) {
|
||||
if ($i > 500 || $clbs[$i] == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if($clbs[$i] < 0)
|
||||
if ($clbs[$i] < 0) {
|
||||
$this->fail(100, "ты ошибся чутка, у айди группы убери минус");
|
||||
}
|
||||
|
||||
$clb = $clubs->get((int) $clbs[$i]);
|
||||
if(is_null($clb)) {
|
||||
$response[$i] = (object)[
|
||||
if (is_null($clb)) {
|
||||
$response[$i] = (object) [
|
||||
"id" => intval($clbs[$i]),
|
||||
"name" => "DELETED",
|
||||
"screen_name" => "club".intval($clbs[$i]),
|
||||
"screen_name" => "club" . intval($clbs[$i]),
|
||||
"type" => "group",
|
||||
"description" => "This group was deleted or it doesn't exist"
|
||||
"description" => "This group was deleted or it doesn't exist",
|
||||
];
|
||||
} else if($clbs[$i] == NULL) {
|
||||
} elseif ($clbs[$i] == null) {
|
||||
|
||||
} else {
|
||||
$response[$i] = (object)[
|
||||
$response[$i] = (object) [
|
||||
"id" => $clb->getId(),
|
||||
"name" => $clb->getName(),
|
||||
"screen_name" => $clb->getShortCode() ?? "club".$clb->getId(),
|
||||
"screen_name" => $clb->getShortCode() ?? "club" . $clb->getId(),
|
||||
"is_closed" => false,
|
||||
"type" => "group",
|
||||
"is_member" => !is_null($this->getUser()) ? (int) $clb->getSubscriptionStatus($this->getUser()) : 0,
|
||||
|
@ -150,8 +191,8 @@ final class Groups extends VKAPIRequestHandler
|
|||
|
||||
$flds = explode(',', $fields);
|
||||
|
||||
foreach($flds as $field) {
|
||||
switch($field) {
|
||||
foreach ($flds as $field) {
|
||||
switch ($field) {
|
||||
case "verified":
|
||||
$response[$i]->verified = intval($clb->isVerified());
|
||||
break;
|
||||
|
@ -188,24 +229,43 @@ final class Groups extends VKAPIRequestHandler
|
|||
case "description":
|
||||
$response[$i]->description = $clb->getDescription();
|
||||
break;
|
||||
case "can_suggest":
|
||||
$response[$i]->can_suggest = !$clb->canBeModifiedBy($this->getUser()) && $clb->getWallType() == 2;
|
||||
break;
|
||||
case "background":
|
||||
$backgrounds = $clb->getBackDropPictureURLs();
|
||||
$response[$i]->background = $backgrounds;
|
||||
break;
|
||||
# unstandard feild
|
||||
case "suggested_count":
|
||||
if ($clb->getWallType() != 2) {
|
||||
$response[$i]->suggested_count = null;
|
||||
break;
|
||||
}
|
||||
|
||||
$response[$i]->suggested_count = $clb->getSuggestedPostsCount($this->getUser());
|
||||
break;
|
||||
case "contacts":
|
||||
$contacts;
|
||||
$contactTmp = $clb->getManagers(1, true);
|
||||
|
||||
foreach($contactTmp as $contact)
|
||||
$contacts[] = array(
|
||||
foreach ($contactTmp as $contact) {
|
||||
$contacts[] = [
|
||||
"user_id" => $contact->getUser()->getId(),
|
||||
"desc" => $contact->getComment()
|
||||
);
|
||||
"desc" => $contact->getComment(),
|
||||
];
|
||||
}
|
||||
|
||||
$response[$i]->contacts = $contacts;
|
||||
break;
|
||||
case "can_post":
|
||||
if(!is_null($this->getUser()))
|
||||
if($clb->canBeModifiedBy($this->getUser()))
|
||||
if (!is_null($this->getUser())) {
|
||||
if ($clb->canBeModifiedBy($this->getUser())) {
|
||||
$response[$i]->can_post = true;
|
||||
else
|
||||
} else {
|
||||
$response[$i]->can_post = $clb->canPost();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -215,62 +275,72 @@ final class Groups extends VKAPIRequestHandler
|
|||
return $response;
|
||||
}
|
||||
|
||||
function search(string $q, int $offset = 0, int $count = 100)
|
||||
public function search(string $q, int $offset = 0, int $count = 100, string $fields = "screen_name,is_admin,is_member,is_advertiser,photo_50,photo_100,photo_200")
|
||||
{
|
||||
$clubs = new ClubsRepo;
|
||||
if ($count > 100) {
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: count should be less or equal to 100");
|
||||
}
|
||||
|
||||
$clubs = new ClubsRepo();
|
||||
|
||||
$array = [];
|
||||
$find = $clubs->find($q);
|
||||
|
||||
foreach ($find as $group)
|
||||
foreach ($find->offsetLimit($offset, $count) as $group) {
|
||||
$array[] = $group->getId();
|
||||
}
|
||||
|
||||
if (!$array || sizeof($array) < 1) {
|
||||
return (object) [
|
||||
"count" => $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
|
||||
*/
|
||||
"count" => 0,
|
||||
"items" => [],
|
||||
];
|
||||
}
|
||||
|
||||
function join(int $group_id)
|
||||
return (object) [
|
||||
"count" => $find->size(),
|
||||
"items" => $this->getById(implode(',', $array), "", $fields),
|
||||
];
|
||||
}
|
||||
|
||||
public function join(int $group_id)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$club = (new ClubsRepo)->get($group_id);
|
||||
$club = (new ClubsRepo())->get($group_id);
|
||||
|
||||
$isMember = !is_null($this->getUser()) ? (int) $club->getSubscriptionStatus($this->getUser()) : 0;
|
||||
|
||||
if($isMember == 0)
|
||||
if ($isMember == 0) {
|
||||
$club->toggleSubscription($this->getUser());
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function leave(int $group_id)
|
||||
public function leave(int $group_id)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$club = (new ClubsRepo)->get($group_id);
|
||||
$club = (new ClubsRepo())->get($group_id);
|
||||
|
||||
$isMember = !is_null($this->getUser()) ? (int) $club->getSubscriptionStatus($this->getUser()) : 0;
|
||||
|
||||
if($isMember == 1)
|
||||
if ($isMember == 1) {
|
||||
$club->toggleSubscription($this->getUser());
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function create(string $title, string $description = "", string $type = "group", int $public_category = 1, int $public_subcategory = 1, int $subtype = 1)
|
||||
public function create(string $title, string $description = "", string $type = "group", int $public_category = 1, int $public_subcategory = 1, int $subtype = 1)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$club = new Club;
|
||||
$club = new Club();
|
||||
|
||||
$club->setName($title);
|
||||
$club->setAbout($description);
|
||||
|
@ -279,55 +349,80 @@ final class Groups extends VKAPIRequestHandler
|
|||
|
||||
$club->toggleSubscription($this->getUser());
|
||||
|
||||
return $this->getById((string)$club->getId());
|
||||
return $this->getById((string) $club->getId());
|
||||
}
|
||||
|
||||
function edit(
|
||||
public function edit(
|
||||
int $group_id,
|
||||
string $title = NULL,
|
||||
string $description = NULL,
|
||||
string $screen_name = NULL,
|
||||
string $website = NULL,
|
||||
int $wall = NULL,
|
||||
int $topics = NULL,
|
||||
int $adminlist = NULL,
|
||||
int $topicsAboveWall = NULL,
|
||||
int $hideFromGlobalFeed = NULL)
|
||||
{
|
||||
string $title = null,
|
||||
string $description = null,
|
||||
string $screen_name = null,
|
||||
string $website = null,
|
||||
int $wall = -1,
|
||||
int $topics = null,
|
||||
int $adminlist = null,
|
||||
int $topicsAboveWall = null,
|
||||
int $hideFromGlobalFeed = null,
|
||||
int $audio = null
|
||||
) {
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$club = (new ClubsRepo)->get($group_id);
|
||||
$club = (new ClubsRepo())->get($group_id);
|
||||
|
||||
if(!$club) $this->fail(203, "Club not found");
|
||||
if(!$club || !$club->canBeModifiedBy($this->getUser())) $this->fail(15, "You can't modify this group.");
|
||||
if(!empty($screen_name) && !$club->setShortcode($screen_name)) $this->fail(103, "Invalid shortcode.");
|
||||
if (!$club) {
|
||||
$this->fail(203, "Club not found");
|
||||
}
|
||||
if (!$club || !$club->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(15, "You can't modify this group.");
|
||||
}
|
||||
if (!empty($screen_name) && !$club->setShortcode($screen_name)) {
|
||||
$this->fail(103, "Invalid shortcode.");
|
||||
}
|
||||
|
||||
!is_null($title) ? $club->setName($title) : NULL;
|
||||
!is_null($description) ? $club->setAbout($description) : NULL;
|
||||
!is_null($screen_name) ? $club->setShortcode($screen_name) : NULL;
|
||||
!is_null($website) ? $club->setWebsite((!parse_url($website, PHP_URL_SCHEME) ? "https://" : "") . $website) : NULL;
|
||||
!is_null($wall) ? $club->setWall($wall) : NULL;
|
||||
!is_null($topics) ? $club->setEveryone_Can_Create_Topics($topics) : NULL;
|
||||
!is_null($adminlist) ? $club->setAdministrators_List_Display($adminlist) : NULL;
|
||||
!is_null($topicsAboveWall) ? $club->setDisplay_Topics_Above_Wall($topicsAboveWall) : NULL;
|
||||
!is_null($hideFromGlobalFeed) ? $club->setHide_From_Global_Feed($hideFromGlobalFeed) : NULL;
|
||||
!empty($title) ? $club->setName($title) : null;
|
||||
!empty($description) ? $club->setAbout($description) : null;
|
||||
!empty($screen_name) ? $club->setShortcode($screen_name) : null;
|
||||
!empty($website) ? $club->setWebsite((!parse_url($website, PHP_URL_SCHEME) ? "https://" : "") . $website) : null;
|
||||
|
||||
try {
|
||||
$wall != -1 ? $club->setWall($wall) : null;
|
||||
} catch (\Exception $e) {
|
||||
$this->fail(50, "Invalid wall value");
|
||||
}
|
||||
|
||||
!empty($topics) ? $club->setEveryone_Can_Create_Topics($topics) : null;
|
||||
!empty($adminlist) ? $club->setAdministrators_List_Display($adminlist) : null;
|
||||
!empty($topicsAboveWall) ? $club->setDisplay_Topics_Above_Wall($topicsAboveWall) : null;
|
||||
|
||||
if (!$club->isHidingFromGlobalFeedEnforced()) {
|
||||
!empty($hideFromGlobalFeed) ? $club->setHide_From_Global_Feed($hideFromGlobalFeed) : null;
|
||||
}
|
||||
|
||||
in_array($audio, [0, 1]) ? $club->setEveryone_can_upload_audios($audio) : null;
|
||||
|
||||
try {
|
||||
$club->save();
|
||||
} catch (\TypeError $e) {
|
||||
$this->fail(15, "Nothing changed");
|
||||
} catch (\Exception $e) {
|
||||
$this->fail(18, "An unknown error occurred: maybe you set an incorrect value?");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function getMembers(string $group_id, string $sort = "id_asc", int $offset = 0, int $count = 100, string $fields = "", string $filter = "any")
|
||||
public function getMembers(string $group_id, string $sort = "id_asc", int $offset = 0, int $count = 100, string $fields = "", string $filter = "any")
|
||||
{
|
||||
# bdate,can_post,can_see_all_posts,can_see_audio,can_write_private_message,city,common_count,connections,contacts,country,domain,education,has_mobile,last_seen,lists,online,online_mobile,photo_100,photo_200,photo_200_orig,photo_400_orig,photo_50,photo_max,photo_max_orig,relation,relatives,schools,sex,site,status,universities
|
||||
$club = (new ClubsRepo)->get((int) $group_id);
|
||||
if(!$club)
|
||||
$club = (new ClubsRepo())->get((int) $group_id);
|
||||
if (!$club) {
|
||||
$this->fail(125, "Invalid group id");
|
||||
}
|
||||
|
||||
$sorter = "follower ASC";
|
||||
|
||||
switch($sort) {
|
||||
switch ($sort) {
|
||||
default:
|
||||
case "time_asc":
|
||||
case "id_asc":
|
||||
|
@ -342,13 +437,13 @@ final class Groups extends VKAPIRequestHandler
|
|||
$members = array_slice(iterator_to_array($club->getFollowers(1, $count, $sorter)), $offset);
|
||||
$arr = (object) [
|
||||
"count" => count($members),
|
||||
"items" => array()];
|
||||
"items" => []];
|
||||
|
||||
$filds = explode(",", $fields);
|
||||
|
||||
$i = 0;
|
||||
foreach($members as $member) {
|
||||
if($i > $count) {
|
||||
foreach ($members as $member) {
|
||||
if ($i > $count) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -358,10 +453,16 @@ final class Groups extends VKAPIRequestHandler
|
|||
"last_name" => $member->getLastName(),
|
||||
];
|
||||
|
||||
foreach($filds as $fild) {
|
||||
switch($fild) {
|
||||
foreach ($filds as $fild) {
|
||||
$canView = $member->canBeViewedBy($this->getUser());
|
||||
switch ($fild) {
|
||||
case "bdate":
|
||||
$arr->items[$i]->bdate = $member->getBirthday()->format('%e.%m.%Y');
|
||||
if (!$canView) {
|
||||
$arr->items[$i]->bdate = "01.01.1970";
|
||||
break;
|
||||
}
|
||||
|
||||
$arr->items[$i]->bdate = $member->getBirthday() ? $member->getBirthday()->format('%e.%m.%Y') : null;
|
||||
break;
|
||||
case "can_post":
|
||||
$arr->items[$i]->can_post = $club->canBeModifiedBy($member);
|
||||
|
@ -370,7 +471,7 @@ final class Groups extends VKAPIRequestHandler
|
|||
$arr->items[$i]->can_see_all_posts = 1;
|
||||
break;
|
||||
case "can_see_audio":
|
||||
$arr->items[$i]->can_see_audio = 0;
|
||||
$arr->items[$i]->can_see_audio = 1;
|
||||
break;
|
||||
case "can_write_private_message":
|
||||
$arr->items[$i]->can_write_private_message = 0;
|
||||
|
@ -382,6 +483,11 @@ final class Groups extends VKAPIRequestHandler
|
|||
$arr->items[$i]->connections = 1;
|
||||
break;
|
||||
case "contacts":
|
||||
if (!$canView) {
|
||||
$arr->items[$i]->contacts = "secret@gmail.com";
|
||||
break;
|
||||
}
|
||||
|
||||
$arr->items[$i]->contacts = $member->getContactEmail();
|
||||
break;
|
||||
case "country":
|
||||
|
@ -397,15 +503,30 @@ final class Groups extends VKAPIRequestHandler
|
|||
$arr->items[$i]->has_mobile = false;
|
||||
break;
|
||||
case "last_seen":
|
||||
if (!$canView) {
|
||||
$arr->items[$i]->last_seen = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
$arr->items[$i]->last_seen = $member->getOnline()->timestamp();
|
||||
break;
|
||||
case "lists":
|
||||
$arr->items[$i]->lists = "";
|
||||
break;
|
||||
case "online":
|
||||
if (!$canView) {
|
||||
$arr->items[$i]->online = false;
|
||||
break;
|
||||
}
|
||||
|
||||
$arr->items[$i]->online = $member->isOnline();
|
||||
break;
|
||||
case "online_mobile":
|
||||
if (!$canView) {
|
||||
$arr->items[$i]->online_mobile = false;
|
||||
break;
|
||||
}
|
||||
|
||||
$arr->items[$i]->online_mobile = $member->getOnlinePlatform() == "android" || $member->getOnlinePlatform() == "iphone" || $member->getOnlinePlatform() == "mobile";
|
||||
break;
|
||||
case "photo_100":
|
||||
|
@ -436,12 +557,27 @@ final class Groups extends VKAPIRequestHandler
|
|||
$arr->items[$i]->schools = 0;
|
||||
break;
|
||||
case "sex":
|
||||
if (!$canView) {
|
||||
$arr->items[$i]->sex = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
$arr->items[$i]->sex = $member->isFemale() ? 1 : 2;
|
||||
break;
|
||||
case "site":
|
||||
if (!$canView) {
|
||||
$arr->items[$i]->site = null;
|
||||
break;
|
||||
}
|
||||
|
||||
$arr->items[$i]->site = $member->getWebsite();
|
||||
break;
|
||||
case "status":
|
||||
if (!$canView) {
|
||||
$arr->items[$i]->status = "r";
|
||||
break;
|
||||
}
|
||||
|
||||
$arr->items[$i]->status = $member->getStatus();
|
||||
break;
|
||||
case "universities":
|
||||
|
@ -454,22 +590,23 @@ final class Groups extends VKAPIRequestHandler
|
|||
return $arr;
|
||||
}
|
||||
|
||||
function getSettings(string $group_id)
|
||||
public function getSettings(string $group_id)
|
||||
{
|
||||
$this->requireUser();
|
||||
$club = (new ClubsRepo)->get((int)$group_id);
|
||||
$club = (new ClubsRepo())->get((int) $group_id);
|
||||
|
||||
if(!$club || !$club->canBeModifiedBy($this->getUser()))
|
||||
if (!$club || !$club->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(15, "You can't get settings of this group.");
|
||||
}
|
||||
|
||||
$arr = (object) [
|
||||
"title" => $club->getName(),
|
||||
"description" => $club->getDescription() != NULL ? $club->getDescription() : "",
|
||||
"description" => $club->getDescription() != null ? $club->getDescription() : "",
|
||||
"address" => $club->getShortcode(),
|
||||
"wall" => $club->canPost() == true ? 1 : 0,
|
||||
"wall" => $club->getWallType(), # отличается от вкшных но да ладно
|
||||
"photos" => 1,
|
||||
"video" => 0,
|
||||
"audio" => 0,
|
||||
"audio" => $club->isEveryoneCanUploadAudios() ? 1 : 0,
|
||||
"docs" => 0,
|
||||
"topics" => $club->isEveryoneCanCreateTopics() == true ? 1 : 0,
|
||||
"wiki" => 0,
|
||||
|
@ -486,7 +623,7 @@ final class Groups extends VKAPIRequestHandler
|
|||
3 => "категорий",
|
||||
4 => "групп",
|
||||
],
|
||||
"rss" => "/club".$club->getId()."/rss",
|
||||
"rss" => "/club" . $club->getId() . "/rss",
|
||||
"website" => $club->getWebsite(),
|
||||
"age_limits" => 0,
|
||||
"market" => [],
|
||||
|
@ -495,24 +632,27 @@ final class Groups extends VKAPIRequestHandler
|
|||
return $arr;
|
||||
}
|
||||
|
||||
function isMember(string $group_id, int $user_id, string $user_ids = "", bool $extended = false)
|
||||
public function isMember(string $group_id, int $user_id, string $user_ids = "", bool $extended = false)
|
||||
{
|
||||
$this->requireUser();
|
||||
$id = $user_id != NULL ? $user_id : explode(",", $user_ids);
|
||||
$id = $user_id != null ? $user_id : explode(",", $user_ids);
|
||||
|
||||
if($group_id < 0)
|
||||
if ($group_id < 0) {
|
||||
$this->fail(228, "Remove the minus from group_id");
|
||||
}
|
||||
|
||||
$club = (new ClubsRepo)->get((int)$group_id);
|
||||
$usver = (new UsersRepo)->get((int)$id);
|
||||
$club = (new ClubsRepo())->get((int) $group_id);
|
||||
$usver = (new UsersRepo())->get((int) $id);
|
||||
|
||||
if(!$club || $group_id == 0)
|
||||
if (!$club || $group_id == 0) {
|
||||
$this->fail(203, "Invalid club");
|
||||
}
|
||||
|
||||
if(!$usver || $usver->isDeleted() || $user_id == 0)
|
||||
if (!$usver || $usver->isDeleted() || $user_id == 0) {
|
||||
$this->fail(30, "Invalid user");
|
||||
}
|
||||
|
||||
if($extended == false) {
|
||||
if ($extended == false) {
|
||||
return $club->getSubscriptionStatus($usver) ? 1 : 0;
|
||||
} else {
|
||||
return (object)
|
||||
|
@ -521,12 +661,12 @@ final class Groups extends VKAPIRequestHandler
|
|||
"request" => 0,
|
||||
"invitation" => 0,
|
||||
"can_invite" => 0,
|
||||
"can_recall" => 0
|
||||
"can_recall" => 0,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
function remove(int $group_id, int $user_id)
|
||||
public function remove(int $group_id, int $user_id)
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
|
|
|
@ -1,71 +1,217 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
|
||||
use openvk\Web\Models\Repositories\Users as UsersRepo;
|
||||
use openvk\Web\Models\Repositories\Posts as PostsRepo;
|
||||
use openvk\Web\Models\Repositories\Comments as CommentsRepo;
|
||||
use openvk\Web\Models\Repositories\Videos as VideosRepo;
|
||||
use openvk\Web\Models\Repositories\Photos as PhotosRepo;
|
||||
use openvk\Web\Models\Repositories\Notes as NotesRepo;
|
||||
|
||||
final class Likes extends VKAPIRequestHandler
|
||||
{
|
||||
function add(string $type, int $owner_id, int $item_id): object
|
||||
public function add(string $type, int $owner_id, int $item_id): object
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
switch($type) {
|
||||
$postable = null;
|
||||
switch ($type) {
|
||||
case "post":
|
||||
$post = (new PostsRepo)->getPostById($owner_id, $item_id);
|
||||
if(is_null($post))
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: object not found");
|
||||
|
||||
$post->setLike(true, $this->getUser());
|
||||
|
||||
return (object) [
|
||||
"likes" => $post->getLikesCount()
|
||||
];
|
||||
$post = (new PostsRepo())->getPostById($owner_id, $item_id);
|
||||
$postable = $post;
|
||||
break;
|
||||
case "comment":
|
||||
$comment = (new CommentsRepo())->get($item_id);
|
||||
$postable = $comment;
|
||||
break;
|
||||
case "video":
|
||||
$video = (new VideosRepo())->getByOwnerAndVID($owner_id, $item_id);
|
||||
$postable = $video;
|
||||
break;
|
||||
case "photo":
|
||||
$photo = (new PhotosRepo())->getByOwnerAndVID($owner_id, $item_id);
|
||||
$postable = $photo;
|
||||
break;
|
||||
case "note":
|
||||
$note = (new NotesRepo())->getNoteById($owner_id, $item_id);
|
||||
$postable = $note;
|
||||
break;
|
||||
default:
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: incorrect type");
|
||||
}
|
||||
|
||||
if (is_null($postable) || $postable->isDeleted()) {
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: object not found");
|
||||
}
|
||||
|
||||
function delete(string $type, int $owner_id, int $item_id): object
|
||||
if (!$postable->canBeViewedBy($this->getUser() ?? null)) {
|
||||
$this->fail(2, "Access to postable denied");
|
||||
}
|
||||
|
||||
$postable->setLike(true, $this->getUser());
|
||||
|
||||
return (object) [
|
||||
"likes" => $postable->getLikesCount(),
|
||||
];
|
||||
}
|
||||
|
||||
public function delete(string $type, int $owner_id, int $item_id): object
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
switch($type) {
|
||||
$postable = null;
|
||||
switch ($type) {
|
||||
case "post":
|
||||
$post = (new PostsRepo)->getPostById($owner_id, $item_id);
|
||||
if (is_null($post))
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: object not found");
|
||||
|
||||
$post->setLike(false, $this->getUser());
|
||||
return (object) [
|
||||
"likes" => $post->getLikesCount()
|
||||
];
|
||||
$post = (new PostsRepo())->getPostById($owner_id, $item_id);
|
||||
$postable = $post;
|
||||
break;
|
||||
case "comment":
|
||||
$comment = (new CommentsRepo())->get($item_id);
|
||||
$postable = $comment;
|
||||
break;
|
||||
case "video":
|
||||
$video = (new VideosRepo())->getByOwnerAndVID($owner_id, $item_id);
|
||||
$postable = $video;
|
||||
break;
|
||||
case "photo":
|
||||
$photo = (new PhotosRepo())->getByOwnerAndVID($owner_id, $item_id);
|
||||
$postable = $photo;
|
||||
break;
|
||||
case "note":
|
||||
$note = (new NotesRepo())->getNoteById($owner_id, $item_id);
|
||||
$postable = $note;
|
||||
break;
|
||||
default:
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: incorrect type");
|
||||
}
|
||||
|
||||
if (is_null($postable) || $postable->isDeleted()) {
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: object not found");
|
||||
}
|
||||
|
||||
function isLiked(int $user_id, string $type, int $owner_id, int $item_id): object
|
||||
if (!$postable->canBeViewedBy($this->getUser() ?? null)) {
|
||||
$this->fail(2, "Access to postable denied");
|
||||
}
|
||||
|
||||
if (!is_null($postable)) {
|
||||
$postable->setLike(false, $this->getUser());
|
||||
|
||||
return (object) [
|
||||
"likes" => $postable->getLikesCount(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
public function isLiked(int $user_id, string $type, int $owner_id, int $item_id): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
switch($type) {
|
||||
case "post":
|
||||
$user = (new UsersRepo)->get($user_id);
|
||||
if (is_null($user))
|
||||
$user = (new UsersRepo())->get($user_id);
|
||||
|
||||
if (is_null($user) || $user->isDeleted()) {
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: user not found");
|
||||
}
|
||||
|
||||
$post = (new PostsRepo)->getPostById($owner_id, $item_id);
|
||||
if (is_null($post))
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: object not found");
|
||||
if (!$user->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(1984, "Access denied: you can't see this user");
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"liked" => (int) $post->hasLikeFrom($user),
|
||||
"copied" => 0 # TODO: handle this
|
||||
];
|
||||
$postable = null;
|
||||
switch ($type) {
|
||||
case "post":
|
||||
$post = (new PostsRepo())->getPostById($owner_id, $item_id);
|
||||
$postable = $post;
|
||||
break;
|
||||
case "comment":
|
||||
$comment = (new CommentsRepo())->get($item_id);
|
||||
$postable = $comment;
|
||||
break;
|
||||
case "video":
|
||||
$video = (new VideosRepo())->getByOwnerAndVID($owner_id, $item_id);
|
||||
$postable = $video;
|
||||
break;
|
||||
case "photo":
|
||||
$photo = (new PhotosRepo())->getByOwnerAndVID($owner_id, $item_id);
|
||||
$postable = $photo;
|
||||
break;
|
||||
case "note":
|
||||
$note = (new NotesRepo())->getNoteById($owner_id, $item_id);
|
||||
$postable = $note;
|
||||
break;
|
||||
default:
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: incorrect type");
|
||||
}
|
||||
|
||||
if (is_null($postable) || $postable->isDeleted()) {
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: object not found");
|
||||
}
|
||||
|
||||
if (!$postable->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(665, "Access to postable denied");
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"liked" => (int) $postable->hasLikeFrom($user),
|
||||
"copied" => 0,
|
||||
];
|
||||
}
|
||||
|
||||
public function getList(string $type, int $owner_id, int $item_id, bool $extended = false, int $offset = 0, int $count = 10, bool $skip_own = false)
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$object = null;
|
||||
|
||||
switch ($type) {
|
||||
case "post":
|
||||
$object = (new PostsRepo())->getPostById($owner_id, $item_id);
|
||||
break;
|
||||
case "comment":
|
||||
$object = (new CommentsRepo())->get($item_id);
|
||||
break;
|
||||
case "photo":
|
||||
$object = (new PhotosRepo())->getByOwnerAndVID($owner_id, $item_id);
|
||||
break;
|
||||
case "video":
|
||||
$object = (new VideosRepo())->getByOwnerAndVID($owner_id, $item_id);
|
||||
break;
|
||||
default:
|
||||
$this->fail(58, "Invalid type");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$object || $object->isDeleted()) {
|
||||
$this->fail(56, "Invalid postable");
|
||||
}
|
||||
|
||||
if (!$object->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(665, "Access to postable denied");
|
||||
}
|
||||
|
||||
$res = (object) [
|
||||
"count" => $object->getLikesCount(),
|
||||
"items" => [],
|
||||
];
|
||||
|
||||
$likers = array_slice(iterator_to_array($object->getLikers(1, $offset + $count)), $offset);
|
||||
|
||||
foreach ($likers as $liker) {
|
||||
if ($skip_own && $liker->getId() == $this->getUser()->getId()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$extended) {
|
||||
$res->items[] = $liker->getId();
|
||||
} else {
|
||||
$res->items[] = $liker->toVkApiStruct(null, 'photo_50');
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
|
||||
use openvk\Web\Events\NewMessageEvent;
|
||||
use openvk\Web\Models\Entities\{Correspondence, Message};
|
||||
use openvk\Web\Models\Repositories\{Messages as MSGRepo, Users as USRRepo};
|
||||
|
@ -11,13 +15,14 @@ final class Messages extends VKAPIRequestHandler
|
|||
{
|
||||
private function resolvePeer(int $user_id = -1, int $peer_id = -1): ?int
|
||||
{
|
||||
if($user_id === -1) {
|
||||
if($peer_id === -1)
|
||||
return NULL;
|
||||
else if($peer_id < 0)
|
||||
return NULL;
|
||||
else if(($peer_id - 2000000000) > 0)
|
||||
return NULL;
|
||||
if ($user_id === -1) {
|
||||
if ($peer_id === -1) {
|
||||
return null;
|
||||
} elseif ($peer_id < 0) {
|
||||
return null;
|
||||
} elseif (($peer_id - 2000000000) > 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $peer_id;
|
||||
}
|
||||
|
@ -25,22 +30,23 @@ final class Messages extends VKAPIRequestHandler
|
|||
return $user_id;
|
||||
}
|
||||
|
||||
function getById(string $message_ids, int $preview_length = 0, int $extended = 0): object
|
||||
public function getById(string $message_ids, int $preview_length = 0, int $extended = 0): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$msgs = new MSGRepo;
|
||||
$msgs = new MSGRepo();
|
||||
$ids = preg_split("%, ?%", $message_ids);
|
||||
$items = [];
|
||||
foreach($ids as $id) {
|
||||
foreach ($ids as $id) {
|
||||
$message = $msgs->get((int) $id);
|
||||
if(!$message)
|
||||
if (!$message) {
|
||||
continue;
|
||||
else if($message->getSender()->getId() !== $this->getUser()->getId() && $message->getRecipient()->getId() !== $this->getUser()->getId())
|
||||
} elseif ($message->getSender()->getId() !== $this->getUser()->getId() && $message->getRecipient()->getId() !== $this->getUser()->getId()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$author = $message->getSender()->getId() === $this->getUser()->getId() ? $message->getRecipient()->getId() : $message->getSender()->getId();
|
||||
$rMsg = new APIMsg;
|
||||
$rMsg = new APIMsg();
|
||||
|
||||
$rMsg->id = $message->getId();
|
||||
$rMsg->user_id = $author;
|
||||
|
@ -52,8 +58,9 @@ final class Messages extends VKAPIRequestHandler
|
|||
$rMsg->text = $message->getText(false);
|
||||
$rMsg->emoji = true;
|
||||
|
||||
if($preview_length > 0)
|
||||
if ($preview_length > 0) {
|
||||
$rMsg->body = ovk_proc_strtr($rMsg->body, $preview_length);
|
||||
}
|
||||
$rMsg->text = ovk_proc_strtr($rMsg->text, $preview_length);
|
||||
|
||||
$items[] = $rMsg;
|
||||
|
@ -65,73 +72,105 @@ final class Messages extends VKAPIRequestHandler
|
|||
];
|
||||
}
|
||||
|
||||
function send(int $user_id = -1, int $peer_id = -1, string $domain = "", int $chat_id = -1, string $user_ids = "", string $message = "", int $sticker_id = -1, int $forGodSakePleaseDoNotReportAboutMyOnlineActivity = 0)
|
||||
{
|
||||
public function send(
|
||||
int $user_id = -1,
|
||||
int $peer_id = -1,
|
||||
string $domain = "",
|
||||
int $chat_id = -1,
|
||||
string $user_ids = "",
|
||||
string $message = "",
|
||||
int $sticker_id = -1,
|
||||
int $forGodSakePleaseDoNotReportAboutMyOnlineActivity = 0,
|
||||
string $attachment = ""
|
||||
) { # интересно почему не attachments
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if($forGodSakePleaseDoNotReportAboutMyOnlineActivity == 0)
|
||||
{
|
||||
if ($forGodSakePleaseDoNotReportAboutMyOnlineActivity == 0) {
|
||||
$this->getUser()->updOnline($this->getPlatform());
|
||||
}
|
||||
|
||||
if($chat_id !== -1)
|
||||
if ($chat_id !== -1) {
|
||||
$this->fail(946, "Chats are not implemented");
|
||||
else if($sticker_id !== -1)
|
||||
} elseif ($sticker_id !== -1) {
|
||||
$this->fail(-151, "Stickers are not implemented");
|
||||
else if(empty($message))
|
||||
}
|
||||
|
||||
if (empty($message) && empty($attachment)) {
|
||||
$this->fail(100, "Message text is empty or invalid");
|
||||
}
|
||||
|
||||
# lol recursion
|
||||
if(!empty($user_ids)) {
|
||||
if (!empty($user_ids)) {
|
||||
$rIds = [];
|
||||
$ids = preg_split("%, ?%", $user_ids);
|
||||
if(sizeof($ids) > 100)
|
||||
if (sizeof($ids) > 100) {
|
||||
$this->fail(913, "Too many recipients");
|
||||
}
|
||||
|
||||
foreach($ids as $id)
|
||||
foreach ($ids as $id) {
|
||||
$rIds[] = $this->send(-1, $id, "", -1, "", $message);
|
||||
}
|
||||
|
||||
return $rIds;
|
||||
}
|
||||
|
||||
if(!empty($domain)) {
|
||||
$peer = (new USRRepo)->getByShortCode($domain);
|
||||
if (!empty($domain)) {
|
||||
$peer = (new USRRepo())->getByShortCode($domain);
|
||||
} else {
|
||||
$peer = $this->resolvePeer($user_id, $peer_id);
|
||||
$peer = (new USRRepo)->get($peer);
|
||||
$peer = (new USRRepo())->get($peer);
|
||||
}
|
||||
|
||||
if(!$peer)
|
||||
if (!$peer) {
|
||||
$this->fail(936, "There is no peer with this id");
|
||||
}
|
||||
|
||||
if($this->getUser()->getId() !== $peer->getId() && !$peer->getPrivacyPermission('messages.write', $this->getUser()))
|
||||
if ($this->getUser()->getId() !== $peer->getId() && !$peer->getPrivacyPermission('messages.write', $this->getUser())) {
|
||||
$this->fail(945, "This chat is disabled because of privacy settings");
|
||||
}
|
||||
|
||||
# Finally we get to send a message!
|
||||
$chat = new Correspondence($this->getUser(), $peer);
|
||||
$msg = new Message;
|
||||
$msg = new Message();
|
||||
$msg->setContent($message);
|
||||
|
||||
$msg = $chat->sendMessage($msg, true);
|
||||
if(!$msg)
|
||||
if (!$msg) {
|
||||
$this->fail(950, "Internal error");
|
||||
else
|
||||
} elseif (!empty($attachment)) {
|
||||
$attachs = parseAttachments($attachment);
|
||||
|
||||
# Работают только фотки, остальное просто не будет отображаться.
|
||||
if (sizeof($attachs) >= 10) {
|
||||
$this->fail(15, "Too many attachments");
|
||||
}
|
||||
|
||||
foreach ($attachs as $attach) {
|
||||
if ($attach && !$attach->isDeleted() && $attach->getOwner()->getId() == $this->getUser()->getId()) {
|
||||
$msg->attach($attach);
|
||||
} else {
|
||||
$this->fail(52, "One of the attachments is invalid");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $msg->getId();
|
||||
}
|
||||
|
||||
function delete(string $message_ids, int $spam = 0, int $delete_for_all = 0): object
|
||||
public function delete(string $message_ids, int $spam = 0, int $delete_for_all = 0): object
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$msgs = new MSGRepo;
|
||||
$msgs = new MSGRepo();
|
||||
$ids = preg_split("%, ?%", $message_ids);
|
||||
$items = [];
|
||||
foreach($ids as $id) {
|
||||
foreach ($ids as $id) {
|
||||
$message = $msgs->get((int) $id);
|
||||
if(!$message || $message->getSender()->getId() !== $this->getUser()->getId() && $message->getRecipient()->getId() !== $this->getUser()->getId())
|
||||
if (!$message || $message->getSender()->getId() !== $this->getUser()->getId() && $message->getRecipient()->getId() !== $this->getUser()->getId()) {
|
||||
$items[$id] = 0;
|
||||
}
|
||||
|
||||
$message->delete();
|
||||
$items[$id] = 1;
|
||||
|
@ -140,40 +179,42 @@ final class Messages extends VKAPIRequestHandler
|
|||
return (object) $items;
|
||||
}
|
||||
|
||||
function restore(int $message_id): int
|
||||
public function restore(int $message_id): int
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$msg = (new MSGRepo)->get($message_id);
|
||||
if(!$msg)
|
||||
$msg = (new MSGRepo())->get($message_id);
|
||||
if (!$msg) {
|
||||
return 0;
|
||||
else if($msg->getSender()->getId() !== $this->getUser()->getId())
|
||||
} elseif ($msg->getSender()->getId() !== $this->getUser()->getId()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$msg->undelete();
|
||||
return 1;
|
||||
}
|
||||
|
||||
function getConversations(int $offset = 0, int $count = 20, string $filter = "all", int $extended = 0, string $fields = ""): object
|
||||
public function getConversations(int $offset = 0, int $count = 20, string $filter = "all", int $extended = 0, string $fields = ""): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$convos = (new MSGRepo)->getCorrespondencies($this->getUser(), -1, $count, $offset);
|
||||
$convosCount = (new MSGRepo)->getCorrespondenciesCount($this->getUser());
|
||||
$convos = (new MSGRepo())->getCorrespondencies($this->getUser(), -1, $count, $offset);
|
||||
$convosCount = (new MSGRepo())->getCorrespondenciesCount($this->getUser());
|
||||
$list = [];
|
||||
|
||||
$users = [];
|
||||
foreach($convos as $convo) {
|
||||
foreach ($convos as $convo) {
|
||||
$correspondents = $convo->getCorrespondents();
|
||||
if($correspondents[0]->getId() === $this->getUser()->getId())
|
||||
if ($correspondents[0]->getId() === $this->getUser()->getId()) {
|
||||
$peer = $correspondents[1];
|
||||
else
|
||||
} else {
|
||||
$peer = $correspondents[0];
|
||||
}
|
||||
|
||||
$lastMessage = $convo->getPreviewMessage();
|
||||
|
||||
$listConvo = new APIConvo;
|
||||
$listConvo = new APIConvo();
|
||||
$listConvo->peer = [
|
||||
"id" => $peer->getId(),
|
||||
"type" => "user",
|
||||
|
@ -185,16 +226,17 @@ final class Messages extends VKAPIRequestHandler
|
|||
"allowed" => $canWrite,
|
||||
];
|
||||
|
||||
$lastMessagePreview = NULL;
|
||||
if(!is_null($lastMessage)) {
|
||||
$lastMessagePreview = null;
|
||||
if (!is_null($lastMessage)) {
|
||||
$listConvo->last_message_id = $lastMessage->getId();
|
||||
|
||||
if($lastMessage->getSender()->getId() === $this->getUser()->getId())
|
||||
if ($lastMessage->getSender()->getId() === $this->getUser()->getId()) {
|
||||
$author = $lastMessage->getRecipient()->getId();
|
||||
else
|
||||
} else {
|
||||
$author = $lastMessage->getSender()->getId();
|
||||
}
|
||||
|
||||
$lastMessagePreview = new APIMsg;
|
||||
$lastMessagePreview = new APIMsg();
|
||||
$lastMessagePreview->id = $lastMessage->getId();
|
||||
$lastMessagePreview->user_id = $author;
|
||||
$lastMessagePreview->from_id = $lastMessage->getSender()->getId();
|
||||
|
@ -205,7 +247,7 @@ final class Messages extends VKAPIRequestHandler
|
|||
$lastMessagePreview->text = $lastMessage->getText(false);
|
||||
$lastMessagePreview->emoji = true;
|
||||
|
||||
if($extended == 1) {
|
||||
if ($extended == 1) {
|
||||
$users[] = $author;
|
||||
}
|
||||
}
|
||||
|
@ -216,7 +258,7 @@ final class Messages extends VKAPIRequestHandler
|
|||
];
|
||||
}
|
||||
|
||||
if($extended == 0){
|
||||
if ($extended == 0) {
|
||||
return (object) [
|
||||
"count" => $convosCount,
|
||||
"items" => $list,
|
||||
|
@ -228,12 +270,12 @@ final class Messages extends VKAPIRequestHandler
|
|||
return (object) [
|
||||
"count" => $convosCount,
|
||||
"items" => $list,
|
||||
"profiles" => (!empty($users) ? (new APIUsers)->get(implode(',', $users), $fields, 0, $count+1) : [])
|
||||
"profiles" => (!empty($users) ? (new APIUsers())->get(implode(',', $users), $fields, 0, $count + 1) : []),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
function getConversationsById(string $peer_ids, int $extended = 0, string $fields = "")
|
||||
public function getConversationsById(string $peer_ids, int $extended = 0, string $fields = "")
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
|
@ -241,21 +283,23 @@ final class Messages extends VKAPIRequestHandler
|
|||
|
||||
$output = [
|
||||
"count" => 0,
|
||||
"items" => []
|
||||
"items" => [],
|
||||
];
|
||||
|
||||
$userslist = [];
|
||||
|
||||
foreach($peers as $peer) {
|
||||
if(key($peers) > 100)
|
||||
foreach ($peers as $peer) {
|
||||
if (key($peers) > 100) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(is_null($user_id = $this->resolvePeer((int) $peer)))
|
||||
if (is_null($user_id = $this->resolvePeer((int) $peer))) {
|
||||
$this->fail(-151, "Chats are not implemented");
|
||||
}
|
||||
|
||||
$user = (new USRRepo)->get((int) $peer);
|
||||
$user = (new USRRepo())->get((int) $peer);
|
||||
|
||||
if($user) {
|
||||
if ($user) {
|
||||
$dialogue = new Correspondence($this->getUser(), $user);
|
||||
$iterator = $dialogue->getMessages(Correspondence::CAP_BEHAVIOUR_START_MESSAGE_ID, 0, 1, 0, false);
|
||||
$msg = $iterator[0]->unwrap(); // шоб удобнее было
|
||||
|
@ -263,7 +307,7 @@ final class Messages extends VKAPIRequestHandler
|
|||
"peer" => [
|
||||
"id" => $user->getId(),
|
||||
"type" => "user",
|
||||
"local_id" => $user->getId()
|
||||
"local_id" => $user->getId(),
|
||||
],
|
||||
"last_message_id" => $msg->id,
|
||||
"in_read" => $msg->id,
|
||||
|
@ -278,41 +322,43 @@ final class Messages extends VKAPIRequestHandler
|
|||
"is_marked_unread" => $iterator[0]->isUnread(),
|
||||
"important" => false, // целестора когда релиз
|
||||
"can_write" => [
|
||||
"allowed" => ($user->getId() === $this->getUser()->getId() || $user->getPrivacyPermission('messages.write', $this->getUser()) === true)
|
||||
]
|
||||
"allowed" => ($user->getId() === $this->getUser()->getId() || $user->getPrivacyPermission('messages.write', $this->getUser()) === true),
|
||||
],
|
||||
];
|
||||
$userslist[] = $user->getId();
|
||||
}
|
||||
}
|
||||
|
||||
if($extended == 1) {
|
||||
if ($extended == 1) {
|
||||
$userslist = array_unique($userslist);
|
||||
$output['profiles'] = (!empty($userslist) ? (new APIUsers)->get(implode(',', $userslist), $fields) : []);
|
||||
$output['profiles'] = (!empty($userslist) ? (new APIUsers())->get(implode(',', $userslist), $fields) : []);
|
||||
}
|
||||
|
||||
$output['count'] = sizeof($output['items']);
|
||||
return (object) $output;
|
||||
}
|
||||
|
||||
function getHistory(int $offset = 0, int $count = 20, int $user_id = -1, int $peer_id = -1, int $start_message_id = 0, int $rev = 0, int $extended = 0, string $fields = ""): object
|
||||
public function getHistory(int $offset = 0, int $count = 20, int $user_id = -1, int $peer_id = -1, int $start_message_id = 0, int $rev = 0, int $extended = 0, string $fields = ""): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
if(is_null($user_id = $this->resolvePeer($user_id, $peer_id)))
|
||||
if (is_null($user_id = $this->resolvePeer($user_id, $peer_id))) {
|
||||
$this->fail(-151, "Chats are not implemented");
|
||||
}
|
||||
|
||||
$peer = (new USRRepo)->get($user_id);
|
||||
if(!$peer)
|
||||
$peer = (new USRRepo())->get($user_id);
|
||||
if (!$peer) {
|
||||
$this->fail(1, "ошибка про то что пира нет");
|
||||
}
|
||||
|
||||
$results = [];
|
||||
$dialogue = new Correspondence($this->getUser(), $peer);
|
||||
$iterator = $dialogue->getMessages(Correspondence::CAP_BEHAVIOUR_START_MESSAGE_ID, $start_message_id, $count, abs($offset), $rev === 1);
|
||||
foreach($iterator as $message) {
|
||||
foreach ($iterator as $message) {
|
||||
$msgU = $message->unwrap(); # Why? As of OpenVK 2 Public Preview Two database layer doesn't work correctly and refuses to cache entities.
|
||||
# UPDATE: the issue seems to be caused by debug mode and json_encode (bruh_encode). ~~Dorothy
|
||||
|
||||
$rMsg = new APIMsg;
|
||||
$rMsg = new APIMsg();
|
||||
$rMsg->id = $msgU->id;
|
||||
$rMsg->user_id = $msgU->sender_id === $this->getUser()->getId() ? $msgU->recipient_id : $msgU->sender_id;
|
||||
$rMsg->from_id = $msgU->sender_id;
|
||||
|
@ -340,7 +386,7 @@ final class Messages extends VKAPIRequestHandler
|
|||
return (object) $output;
|
||||
}
|
||||
|
||||
function getLongPollHistory(int $ts = -1, int $preview_length = 0, int $events_limit = 1000, int $msgs_limit = 1000): object
|
||||
public function getLongPollHistory(int $ts = -1, int $preview_length = 0, int $events_limit = 1000, int $msgs_limit = 1000): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
|
@ -352,14 +398,16 @@ final class Messages extends VKAPIRequestHandler
|
|||
];
|
||||
|
||||
$manager = SignalManager::i();
|
||||
$events = $manager->getHistoryFor($this->getUser()->getId(), $ts === -1 ? NULL : $ts, min($events_limit, $msgs_limit));
|
||||
foreach($events as $event) {
|
||||
if(!($event instanceof NewMessageEvent))
|
||||
$events = $manager->getHistoryFor($this->getUser()->getId(), $ts === -1 ? null : $ts, min($events_limit, $msgs_limit));
|
||||
foreach ($events as $event) {
|
||||
if (!($event instanceof NewMessageEvent)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$message = $this->getById((string) $event->getLongPoolSummary()->message["uuid"], $preview_length, 1)->items[0];
|
||||
if(!$message)
|
||||
if (!$message) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$res["messages"][] = $message;
|
||||
$res["history"][] = $event->getVKAPISummary($this->getUser()->getId());
|
||||
|
@ -372,25 +420,79 @@ final class Messages extends VKAPIRequestHandler
|
|||
return (object) $res;
|
||||
}
|
||||
|
||||
function getLongPollServer(int $need_pts = 1, int $lp_version = 3, ?int $group_id = NULL): array
|
||||
public function getLongPollServer(int $need_pts = 1, int $lp_version = 3, ?int $group_id = null): array
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
if($group_id > 0)
|
||||
if ($group_id > 0) {
|
||||
$this->fail(-151, "Not implemented");
|
||||
}
|
||||
|
||||
$url = "http" . (ovk_is_ssl() ? "s" : "") . "://$_SERVER[HTTP_HOST]/nim" . $this->getUser()->getId();
|
||||
$key = openssl_random_pseudo_bytes(8);
|
||||
$key = bin2hex($key) . bin2hex($key ^ ( ~CHANDLER_ROOT_CONF["security"]["secret"] | ((string) $this->getUser()->getId()) ));
|
||||
$key = bin2hex($key) . bin2hex($key ^ (~CHANDLER_ROOT_CONF["security"]["secret"] | ((string) $this->getUser()->getId())));
|
||||
$res = [
|
||||
"key" => $key,
|
||||
"server" => $url,
|
||||
"ts" => time(),
|
||||
];
|
||||
|
||||
if($need_pts === 1)
|
||||
if ($need_pts === 1) {
|
||||
$res["pts"] = -1;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function edit(int $message_id, string $message = "", string $attachment = "", int $peer_id = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$msg = (new MSGRepo())->get($message_id);
|
||||
|
||||
if (empty($message) && empty($attachment)) {
|
||||
$this->fail(100, "Required parameter 'message' missing.");
|
||||
}
|
||||
|
||||
if (!$msg || $msg->isDeleted()) {
|
||||
$this->fail(102, "Invalid message");
|
||||
}
|
||||
|
||||
if ($msg->getSender()->getId() != $this->getUser()->getId()) {
|
||||
$this->fail(15, "Access to message denied");
|
||||
}
|
||||
|
||||
if (!empty($message)) {
|
||||
$msg->setContent($message);
|
||||
}
|
||||
|
||||
$msg->setEdited(time());
|
||||
$msg->save(true);
|
||||
|
||||
if (!empty($attachment)) {
|
||||
$attachs = parseAttachments($attachment);
|
||||
$newAttachmentsCount = sizeof($attachs);
|
||||
|
||||
$postsAttachments = iterator_to_array($msg->getChildren());
|
||||
|
||||
if (sizeof($postsAttachments) >= 10) {
|
||||
$this->fail(15, "Message have too many attachments");
|
||||
}
|
||||
|
||||
if (($newAttachmentsCount + sizeof($postsAttachments)) > 10) {
|
||||
$this->fail(158, "Message will have too many attachments");
|
||||
}
|
||||
|
||||
foreach ($attachs as $attach) {
|
||||
if ($attach && !$attach->isDeleted() && $attach->getOwner()->getId() == $this->getUser()->getId()) {
|
||||
$msg->attach($attach);
|
||||
} else {
|
||||
$this->fail(52, "One of the attachments is invalid");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
use openvk\Web\Models\Repositories\Posts as PostsRepo;
|
||||
use openvk\Web\Models\Entities\User;
|
||||
|
@ -7,12 +11,11 @@ use openvk\VKAPI\Handlers\Wall;
|
|||
|
||||
final class Newsfeed extends VKAPIRequestHandler
|
||||
{
|
||||
function get(string $fields = "", int $start_from = 0, int $start_time = 0, int $end_time = 0, int $offset = 0, int $count = 30, int $extended = 0, int $forGodSakePleaseDoNotReportAboutMyOnlineActivity = 0)
|
||||
public function get(string $fields = "", int $start_from = 0, int $start_time = 0, int $end_time = 0, int $offset = 0, int $count = 30, int $extended = 0, int $forGodSakePleaseDoNotReportAboutMyOnlineActivity = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
if($forGodSakePleaseDoNotReportAboutMyOnlineActivity == 0)
|
||||
{
|
||||
if ($forGodSakePleaseDoNotReportAboutMyOnlineActivity == 0) {
|
||||
$this->getUser()->updOnline($this->getPlatform());
|
||||
}
|
||||
|
||||
|
@ -21,7 +24,7 @@ final class Newsfeed extends VKAPIRequestHandler
|
|||
->getContext()
|
||||
->table("subscriptions")
|
||||
->where("follower", $id);
|
||||
$ids = array_map(function($rel) {
|
||||
$ids = array_map(function ($rel) {
|
||||
return $rel->target * ($rel->model === "openvk\Web\Models\Entities\User" ? 1 : -1);
|
||||
}, iterator_to_array($subs));
|
||||
$ids[] = $this->getUser()->getId();
|
||||
|
@ -32,29 +35,42 @@ final class Newsfeed extends VKAPIRequestHandler
|
|||
->select("id")
|
||||
->where("wall IN (?)", $ids)
|
||||
->where("deleted", 0)
|
||||
->where("suggested", 0)
|
||||
->where("id < (?)", empty($start_from) ? PHP_INT_MAX : $start_from)
|
||||
->where("? <= created", empty($start_time) ? 0 : $start_time)
|
||||
->where("? >= created", empty($end_time) ? PHP_INT_MAX : $end_time)
|
||||
->order("created DESC");
|
||||
|
||||
$rposts = [];
|
||||
foreach($posts->page((int) ($offset + 1), $count) as $post)
|
||||
$rposts[] = (new PostsRepo)->get($post->id)->getPrettyId();
|
||||
foreach ($posts->page((int) ($offset + 1), $count) as $post) {
|
||||
$rposts[] = (new PostsRepo())->get($post->id)->getPrettyId();
|
||||
}
|
||||
|
||||
$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))); // ну и костыли пиздец конечно)
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
function getGlobal(string $fields = "", int $start_from = 0, int $start_time = 0, int $end_time = 0, int $offset = 0, int $count = 30, int $extended = 0)
|
||||
public function getGlobal(string $fields = "", int $start_from = 0, int $start_time = 0, int $end_time = 0, int $offset = 0, int $count = 30, int $extended = 0, int $rss = 0)
|
||||
{
|
||||
$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";
|
||||
$queryBase = "FROM `posts` LEFT JOIN `groups` ON GREATEST(`posts`.`wall`, 0) = 0 AND `groups`.`id` = ABS(`posts`.`wall`) LEFT JOIN `profiles` ON LEAST(`posts`.`wall`, 0) = 0 AND `profiles`.`id` = ABS(`posts`.`wall`)";
|
||||
$queryBase .= "WHERE (`groups`.`hide_from_global_feed` = 0 OR `groups`.`name` IS NULL) AND (`profiles`.`profile_type` = 0 OR `profiles`.`first_name` IS NULL) AND `posts`.`deleted` = 0 AND `posts`.`suggested` = 0";
|
||||
|
||||
if($this->getUser()->getNsfwTolerance() === User::NSFW_INTOLERANT)
|
||||
if ($this->getUser()->getNsfwTolerance() === User::NSFW_INTOLERANT) {
|
||||
$queryBase .= " AND `nsfw` = 0";
|
||||
}
|
||||
|
||||
if ($return_banned == 0) {
|
||||
$ignored_sources_ids = $this->getUser()->getIgnoredSources(0, OPENVK_ROOT_CONF['openvk']['preferences']['newsfeed']['ignoredSourcesLimit'] ?? 50, true);
|
||||
|
||||
if (sizeof($ignored_sources_ids) > 0) {
|
||||
$imploded_ids = implode("', '", $ignored_sources_ids);
|
||||
$queryBase .= " AND `posts`.`wall` NOT IN ('$imploded_ids')";
|
||||
}
|
||||
}
|
||||
|
||||
$start_from = empty($start_from) ? PHP_INT_MAX : $start_from;
|
||||
$start_time = empty($start_time) ? 0 : $start_time;
|
||||
|
@ -63,14 +79,195 @@ final class Newsfeed extends VKAPIRequestHandler
|
|||
|
||||
$rposts = [];
|
||||
$ids = [];
|
||||
foreach($posts as $post) {
|
||||
$rposts[] = (new PostsRepo)->get($post->id)->getPrettyId();
|
||||
if ($rss == 1) {
|
||||
$channel = new \Bhaktaraz\RSSGenerator\Channel();
|
||||
$channel->title("Global Feed — " . OPENVK_ROOT_CONF['openvk']['appearance']['name'])
|
||||
->description('OVK Global feed')
|
||||
->url(ovk_scheme(true) . $_SERVER["HTTP_HOST"] . "/feed/all");
|
||||
|
||||
foreach ($posts as $item) {
|
||||
$post = (new PostsRepo())->get($item->id);
|
||||
if (!$post || $post->isDeleted()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$output = $post->toRss();
|
||||
$output->appendTo($channel);
|
||||
}
|
||||
|
||||
return $channel;
|
||||
}
|
||||
|
||||
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 = (new Wall())->getById(implode(',', $rposts), $extended, $fields, $this->getUser());
|
||||
$response->next_from = end($ids);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function getByType(string $feed_type = 'top', string $fields = "", int $start_from = 0, int $start_time = 0, int $end_time = 0, int $offset = 0, int $count = 30, int $extended = 0, int $return_banned = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
switch ($feed_type) {
|
||||
case 'top':
|
||||
return $this->getGlobal($fields, $start_from, $start_time, $end_time, $offset, $count, $extended, $return_banned);
|
||||
break;
|
||||
default:
|
||||
return $this->get($fields, $start_from, $start_time, $end_time, $offset, $count, $extended);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function getBanned(int $extended = 0, string $fields = "", string $name_case = "nom", int $merge = 0): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$offset = 0;
|
||||
$count = OPENVK_ROOT_CONF['openvk']['preferences']['newsfeed']['ignoredSourcesLimit'] ?? 50;
|
||||
$banned = $this->getUser()->getIgnoredSources($offset, $count, ($extended != 1));
|
||||
$return_object = (object) [
|
||||
'groups' => [],
|
||||
'members' => [],
|
||||
];
|
||||
|
||||
if ($extended == 0) {
|
||||
foreach ($banned as $ban) {
|
||||
if ($ban > 0) {
|
||||
$return_object->members[] = $ban;
|
||||
} else {
|
||||
$return_object->groups[] = $ban;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($merge == 1) {
|
||||
$return_object = (object) [
|
||||
'count' => sizeof($banned),
|
||||
'items' => [],
|
||||
];
|
||||
|
||||
foreach ($banned as $ban) {
|
||||
$return_object->items[] = $ban->toVkApiStruct($this->getUser(), $fields);
|
||||
}
|
||||
} else {
|
||||
$return_object = (object) [
|
||||
'groups' => [],
|
||||
'profiles' => [],
|
||||
];
|
||||
|
||||
foreach ($banned as $ban) {
|
||||
if ($ban->getRealId() > 0) {
|
||||
$return_object->profiles[] = $ban->toVkApiStruct($this->getUser(), $fields);
|
||||
} else {
|
||||
$return_object->groups[] = $ban->toVkApiStruct($this->getUser(), $fields);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $return_object;
|
||||
}
|
||||
|
||||
public function addBan(string $user_ids = "", string $group_ids = "")
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
# Formatting input ids
|
||||
if (!empty($user_ids)) {
|
||||
$user_ids = array_map(function ($el) {
|
||||
return (int) $el;
|
||||
}, explode(',', $user_ids));
|
||||
$user_ids = array_unique($user_ids);
|
||||
} else {
|
||||
$user_ids = [];
|
||||
}
|
||||
|
||||
if (!empty($group_ids)) {
|
||||
$group_ids = array_map(function ($el) {
|
||||
return abs((int) $el) * -1;
|
||||
}, explode(',', $group_ids));
|
||||
$group_ids = array_unique($group_ids);
|
||||
} else {
|
||||
$group_ids = [];
|
||||
}
|
||||
|
||||
$ids = array_merge($user_ids, $group_ids);
|
||||
if (sizeof($ids) < 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sizeof($ids) > 10) {
|
||||
$this->fail(-10, "Limit of 'ids' is 10");
|
||||
}
|
||||
|
||||
$config_limit = OPENVK_ROOT_CONF['openvk']['preferences']['newsfeed']['ignoredSourcesLimit'] ?? 50;
|
||||
$user_ignores = $this->getUser()->getIgnoredSourcesCount();
|
||||
if (($user_ignores + sizeof($ids)) > $config_limit) {
|
||||
$this->fail(-50, "Ignoring limit exceeded");
|
||||
}
|
||||
|
||||
$entities = get_entities($ids);
|
||||
$successes = 0;
|
||||
foreach ($entities as $entity) {
|
||||
if (!$entity || $entity->getRealId() === $this->getUser()->getRealId() || $entity->isHideFromGlobalFeedEnabled() || $entity->isIgnoredBy($this->getUser())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$entity->addIgnore($this->getUser());
|
||||
$successes += 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function deleteBan(string $user_ids = "", string $group_ids = "")
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if (!empty($user_ids)) {
|
||||
$user_ids = array_map(function ($el) {
|
||||
return (int) $el;
|
||||
}, explode(',', $user_ids));
|
||||
$user_ids = array_unique($user_ids);
|
||||
} else {
|
||||
$user_ids = [];
|
||||
}
|
||||
|
||||
if (!empty($group_ids)) {
|
||||
$group_ids = array_map(function ($el) {
|
||||
return abs((int) $el) * -1;
|
||||
}, explode(',', $group_ids));
|
||||
$group_ids = array_unique($group_ids);
|
||||
} else {
|
||||
$group_ids = [];
|
||||
}
|
||||
|
||||
$ids = array_merge($user_ids, $group_ids);
|
||||
if (sizeof($ids) < 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sizeof($ids) > 10) {
|
||||
$this->fail(-10, "Limit of ids is 10");
|
||||
}
|
||||
|
||||
$entities = get_entities($ids);
|
||||
$successes = 0;
|
||||
foreach ($entities as $entity) {
|
||||
if (!$entity || $entity->getRealId() === $this->getUser()->getRealId() || !$entity->isIgnoredBy($this->getUser())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$entity->removeIgnore($this->getUser());
|
||||
$successes += 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
|
||||
use openvk\Web\Models\Repositories\Notes as NotesRepo;
|
||||
use openvk\Web\Models\Repositories\Users as UsersRepo;
|
||||
use openvk\Web\Models\Repositories\Comments as CommentsRepo;
|
||||
|
@ -9,12 +13,12 @@ use openvk\Web\Models\Entities\{Note, Comment};
|
|||
|
||||
final class Notes extends VKAPIRequestHandler
|
||||
{
|
||||
function add(string $title, string $text, int $privacy = 0, int $comment_privacy = 0, string $privacy_view = "", string $privacy_comment = "")
|
||||
public function add(string $title, string $text, int $privacy = 0, int $comment_privacy = 0, string $privacy_view = "", string $privacy_comment = "")
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$note = new Note;
|
||||
$note = new Note();
|
||||
$note->setOwner($this->getUser()->getId());
|
||||
$note->setCreated(time());
|
||||
$note->setName($title);
|
||||
|
@ -25,28 +29,37 @@ final class Notes extends VKAPIRequestHandler
|
|||
return $note->getVirtualId();
|
||||
}
|
||||
|
||||
function createComment(string $note_id, int $owner_id, string $message, int $reply_to = 0, string $attachments = "")
|
||||
public function createComment(string $note_id, int $owner_id, string $message, int $reply_to = 0, string $attachments = "")
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
$note = (new NotesRepo)->getNoteById((int)$owner_id, (int)$note_id);
|
||||
$note = (new NotesRepo())->getNoteById((int) $owner_id, (int) $note_id);
|
||||
|
||||
if(!$note)
|
||||
if (!$note) {
|
||||
$this->fail(180, "Note not found");
|
||||
}
|
||||
|
||||
if($note->isDeleted())
|
||||
if ($note->isDeleted()) {
|
||||
$this->fail(189, "Note is deleted");
|
||||
}
|
||||
|
||||
if($note->getOwner()->isDeleted())
|
||||
if ($note->getOwner()->isDeleted()) {
|
||||
$this->fail(403, "Owner is deleted");
|
||||
}
|
||||
|
||||
if(!$note->getOwner()->getPrivacyPermission('notes.read', $this->getUser()))
|
||||
if (!$note->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
if (!$note->getOwner()->getPrivacyPermission('notes.read', $this->getUser())) {
|
||||
$this->fail(43, "No access");
|
||||
}
|
||||
|
||||
if(empty($message) && empty($attachments))
|
||||
if (empty($message) && empty($attachments)) {
|
||||
$this->fail(100, "Required parameter 'message' missing.");
|
||||
}
|
||||
|
||||
$comment = new Comment;
|
||||
$comment = new Comment();
|
||||
$comment->setOwner($this->getUser()->getId());
|
||||
$comment->setModel(get_class($note));
|
||||
$comment->setTarget($note->getId());
|
||||
|
@ -54,43 +67,49 @@ final class Notes extends VKAPIRequestHandler
|
|||
$comment->setCreated(time());
|
||||
$comment->save();
|
||||
|
||||
if(!empty($attachments)) {
|
||||
if (!empty($attachments)) {
|
||||
$attachmentsArr = explode(",", $attachments);
|
||||
|
||||
if(sizeof($attachmentsArr) > 10)
|
||||
if (sizeof($attachmentsArr) > 10) {
|
||||
$this->fail(50, "Error: too many attachments");
|
||||
}
|
||||
|
||||
foreach($attachmentsArr as $attac) {
|
||||
$attachmentType = NULL;
|
||||
foreach ($attachmentsArr as $attac) {
|
||||
$attachmentType = null;
|
||||
|
||||
if(str_contains($attac, "photo"))
|
||||
if (str_contains($attac, "photo")) {
|
||||
$attachmentType = "photo";
|
||||
elseif(str_contains($attac, "video"))
|
||||
} elseif (str_contains($attac, "video")) {
|
||||
$attachmentType = "video";
|
||||
else
|
||||
} else {
|
||||
$this->fail(205, "Unknown attachment type");
|
||||
}
|
||||
|
||||
$attachment = str_replace($attachmentType, "", $attac);
|
||||
|
||||
$attachmentOwner = (int)explode("_", $attachment)[0];
|
||||
$attachmentId = (int)end(explode("_", $attachment));
|
||||
$attachmentOwner = (int) explode("_", $attachment)[0];
|
||||
$attachmentId = (int) end(explode("_", $attachment));
|
||||
|
||||
$attacc = NULL;
|
||||
$attacc = null;
|
||||
|
||||
if($attachmentType == "photo") {
|
||||
$attacc = (new PhotosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if(!$attacc || $attacc->isDeleted())
|
||||
if ($attachmentType == "photo") {
|
||||
$attacc = (new PhotosRepo())->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if (!$attacc || $attacc->isDeleted()) {
|
||||
$this->fail(100, "Photo does not exists");
|
||||
if($attacc->getOwner()->getId() != $this->getUser()->getId())
|
||||
}
|
||||
if ($attacc->getOwner()->getId() != $this->getUser()->getId()) {
|
||||
$this->fail(43, "You do not have access to this photo");
|
||||
}
|
||||
|
||||
$comment->attach($attacc);
|
||||
} elseif($attachmentType == "video") {
|
||||
$attacc = (new VideosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if(!$attacc || $attacc->isDeleted())
|
||||
} elseif ($attachmentType == "video") {
|
||||
$attacc = (new VideosRepo())->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if (!$attacc || $attacc->isDeleted()) {
|
||||
$this->fail(100, "Video does not exists");
|
||||
if($attacc->getOwner()->getId() != $this->getUser()->getId())
|
||||
}
|
||||
if ($attacc->getOwner()->getId() != $this->getUser()->getId()) {
|
||||
$this->fail(43, "You do not have access to this video");
|
||||
}
|
||||
|
||||
$comment->attach($attacc);
|
||||
}
|
||||
|
@ -100,118 +119,96 @@ final class Notes extends VKAPIRequestHandler
|
|||
return $comment->getId();
|
||||
}
|
||||
|
||||
function delete(string $note_id)
|
||||
public function delete(string $note_id)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$note = (new NotesRepo)->get((int)$note_id);
|
||||
$note = (new NotesRepo())->get((int) $note_id);
|
||||
|
||||
if(!$note)
|
||||
if (!$note) {
|
||||
$this->fail(180, "Note not found");
|
||||
}
|
||||
|
||||
if(!$note->canBeModifiedBy($this->getUser()))
|
||||
if (!$note->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(15, "Access to note denied");
|
||||
}
|
||||
|
||||
$note->delete();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function deleteComment(int $comment_id, int $owner_id = 0)
|
||||
public function edit(string $note_id, string $title = "", string $text = "", int $privacy = 0, int $comment_privacy = 0, string $privacy_view = "", string $privacy_comment = "")
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$comment = (new CommentsRepo)->get($comment_id);
|
||||
$note = (new NotesRepo())->getNoteById($this->getUser()->getId(), (int) $note_id);
|
||||
|
||||
if(!$comment || !$comment->canBeDeletedBy($this->getUser()))
|
||||
$this->fail(403, "Access to comment denied");
|
||||
|
||||
$comment->delete();
|
||||
|
||||
return 1;
|
||||
if (!$note) {
|
||||
$this->fail(180, "Note not found");
|
||||
}
|
||||
|
||||
function edit(string $note_id, string $title = "", string $text = "", int $privacy = 0, int $comment_privacy = 0, string $privacy_view = "", string $privacy_comment = "")
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$note = (new NotesRepo)->getNoteById($this->getUser()->getId(), (int)$note_id);
|
||||
|
||||
if(!$note)
|
||||
$this->fail(180, "Note not found");
|
||||
|
||||
if($note->isDeleted())
|
||||
if ($note->isDeleted()) {
|
||||
$this->fail(189, "Note is deleted");
|
||||
}
|
||||
|
||||
if(!$note->canBeModifiedBy($this->getUser()))
|
||||
if (!$note->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(403, "No access");
|
||||
}
|
||||
|
||||
!empty($title) ? $note->setName($title) : NULL;
|
||||
!empty($text) ? $note->setSource($text) : NULL;
|
||||
!empty($title) ? $note->setName($title) : null;
|
||||
!empty($text) ? $note->setSource($text) : null;
|
||||
|
||||
$note->setCached_Content(NULL);
|
||||
$note->setCached_Content(null);
|
||||
$note->setEdited(time());
|
||||
$note->save();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function editComment(int $comment_id, string $message, int $owner_id = NULL)
|
||||
public function get(int $user_id, string $note_ids = "", int $offset = 0, int $count = 10, int $sort = 0)
|
||||
{
|
||||
/*
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
$user = (new UsersRepo())->get($user_id);
|
||||
|
||||
$comment = (new CommentsRepo)->get($comment_id);
|
||||
|
||||
if($comment->getOwner() != $this->getUser()->getId())
|
||||
$this->fail(15, "Access to comment denied");
|
||||
|
||||
$comment->setContent($message);
|
||||
$comment->setEdited(time());
|
||||
$comment->save();
|
||||
*/
|
||||
|
||||
return 1;
|
||||
if (!$user || $user->isDeleted()) {
|
||||
$this->fail(15, "Invalid user");
|
||||
}
|
||||
|
||||
function get(int $user_id, string $note_ids = "", int $offset = 0, int $count = 10, int $sort = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$user = (new UsersRepo)->get($user_id);
|
||||
if (!$user->getPrivacyPermission('notes.read', $this->getUser())) {
|
||||
$this->fail(15, "Access denied: this user chose to hide his notes");
|
||||
}
|
||||
|
||||
if(!$user || $user->isDeleted())
|
||||
$this->fail(15, "Invalid user");
|
||||
if (!$user->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
if(!$user->getPrivacyPermission('notes.read', $this->getUser()))
|
||||
$this->fail(43, "Access denied: this user chose to hide his notes");
|
||||
|
||||
if(empty($note_ids)) {
|
||||
$notes = array_slice(iterator_to_array((new NotesRepo)->getUserNotes($user, 1, $count + $offset, $sort == 0 ? "ASC" : "DESC")), $offset);
|
||||
if (empty($note_ids)) {
|
||||
$notes = array_slice(iterator_to_array((new NotesRepo())->getUserNotes($user, 1, $count + $offset, $sort == 0 ? "ASC" : "DESC")), $offset);
|
||||
$nodez = (object) [
|
||||
"count" => (new NotesRepo)->getUserNotesCount((new UsersRepo)->get($user_id)),
|
||||
"notes" => []
|
||||
"count" => (new NotesRepo())->getUserNotesCount((new UsersRepo())->get($user_id)),
|
||||
"notes" => [],
|
||||
];
|
||||
|
||||
foreach($notes as $note) {
|
||||
if($note->isDeleted()) continue;
|
||||
foreach ($notes as $note) {
|
||||
if ($note->isDeleted()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$nodez->notes[] = $note->toVkApiStruct();
|
||||
}
|
||||
} else {
|
||||
$notes = explode(',', $note_ids);
|
||||
|
||||
foreach($notes as $note)
|
||||
{
|
||||
foreach ($notes as $note) {
|
||||
$id = explode("_", $note);
|
||||
|
||||
$items = [];
|
||||
|
||||
$note = (new NotesRepo)->getNoteById((int)$id[0], (int)$id[1]);
|
||||
if($note) {
|
||||
$note = (new NotesRepo())->getNoteById((int) $id[0], (int) $id[1]);
|
||||
if ($note && !$note->isDeleted()) {
|
||||
$nodez->notes[] = $note->toVkApiStruct();
|
||||
}
|
||||
}
|
||||
|
@ -220,63 +217,79 @@ final class Notes extends VKAPIRequestHandler
|
|||
return $nodez;
|
||||
}
|
||||
|
||||
function getById(int $note_id, int $owner_id, bool $need_wiki = false)
|
||||
public function getById(int $note_id, int $owner_id, bool $need_wiki = false)
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$note = (new NotesRepo)->getNoteById($owner_id, $note_id);
|
||||
$note = (new NotesRepo())->getNoteById($owner_id, $note_id);
|
||||
|
||||
if(!$note)
|
||||
if (!$note) {
|
||||
$this->fail(180, "Note not found");
|
||||
}
|
||||
|
||||
if($note->isDeleted())
|
||||
if ($note->isDeleted()) {
|
||||
$this->fail(189, "Note is deleted");
|
||||
}
|
||||
|
||||
if(!$note->getOwner() || $note->getOwner()->isDeleted())
|
||||
if (!$note->getOwner() || $note->getOwner()->isDeleted()) {
|
||||
$this->fail(177, "Owner does not exists");
|
||||
}
|
||||
|
||||
if(!$note->getOwner()->getPrivacyPermission('notes.read', $this->getUser()))
|
||||
if (!$note->getOwner()->getPrivacyPermission('notes.read', $this->getUser())) {
|
||||
$this->fail(40, "Access denied: this user chose to hide his notes");
|
||||
}
|
||||
|
||||
if (!$note->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(15, "Access to note denied");
|
||||
}
|
||||
|
||||
return $note->toVkApiStruct();
|
||||
}
|
||||
|
||||
function getComments(int $note_id, int $owner_id, int $sort = 1, int $offset = 0, int $count = 100)
|
||||
public function getComments(int $note_id, int $owner_id, int $sort = 1, int $offset = 0, int $count = 100)
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$note = (new NotesRepo)->getNoteById($owner_id, $note_id);
|
||||
$note = (new NotesRepo())->getNoteById($owner_id, $note_id);
|
||||
|
||||
if(!$note)
|
||||
if (!$note) {
|
||||
$this->fail(180, "Note not found");
|
||||
}
|
||||
|
||||
if($note->isDeleted())
|
||||
if ($note->isDeleted()) {
|
||||
$this->fail(189, "Note is deleted");
|
||||
}
|
||||
|
||||
if(!$note->getOwner())
|
||||
if (!$note->getOwner()) {
|
||||
$this->fail(177, "Owner does not exists");
|
||||
}
|
||||
|
||||
if(!$note->getOwner()->getPrivacyPermission('notes.read', $this->getUser()))
|
||||
if (!$note->getOwner()->getPrivacyPermission('notes.read', $this->getUser())) {
|
||||
$this->fail(14, "No access");
|
||||
}
|
||||
|
||||
if (!$note->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(15, "Access to note denied");
|
||||
}
|
||||
|
||||
$arr = (object) [
|
||||
"count" => $note->getCommentsCount(),
|
||||
"comments" => []];
|
||||
$comments = array_slice(iterator_to_array($note->getComments(1, $count + $offset)), $offset);
|
||||
|
||||
foreach($comments as $comment) {
|
||||
foreach ($comments as $comment) {
|
||||
$arr->comments[] = $comment->toVkApiStruct($this->getUser(), false, false, $note);
|
||||
}
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
function getFriendsNotes(int $offset = 0, int $count = 0)
|
||||
public function getFriendsNotes(int $offset = 0, int $count = 0)
|
||||
{
|
||||
$this->fail(501, "Not implemented");
|
||||
}
|
||||
|
||||
function restoreComment(int $comment_id = 0, int $owner_id = 0)
|
||||
public function restoreComment(int $comment_id = 0, int $owner_id = 0)
|
||||
{
|
||||
$this->fail(501, "Not implemented");
|
||||
}
|
||||
|
|
91
VKAPI/Handlers/Notifications.php
Normal file
91
VKAPI/Handlers/Notifications.php
Normal file
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
|
||||
use openvk\Web\Models\Entities\Club;
|
||||
use openvk\Web\Models\Repositories\{Notifications as Notifs, Clubs, Users};
|
||||
|
||||
final class Notifications extends VKAPIRequestHandler
|
||||
{
|
||||
public function get(
|
||||
int $count = 10,
|
||||
string $from = "",
|
||||
int $offset = 0,
|
||||
string $start_from = "",
|
||||
string $filters = "",
|
||||
int $start_time = 0,
|
||||
int $end_time = 0,
|
||||
int $archived = 0
|
||||
) {
|
||||
$this->requireUser();
|
||||
|
||||
$res = (object) [
|
||||
"items" => [],
|
||||
"profiles" => [],
|
||||
"groups" => [],
|
||||
"last_viewed" => $this->getUser()->getNotificationOffset(),
|
||||
];
|
||||
|
||||
if ($count > 100) {
|
||||
$this->fail(125, "Count is too big");
|
||||
}
|
||||
|
||||
if (!eventdb()) {
|
||||
$this->fail(1289, "EventDB is disabled on this instance");
|
||||
}
|
||||
|
||||
$notifs = array_slice(iterator_to_array((new Notifs())->getNotificationsByUser($this->getUser(), $this->getUser()->getNotificationOffset(), (bool) $archived, 1, $offset + $count)), $offset);
|
||||
$tmpProfiles = [];
|
||||
foreach ($notifs as $notif) {
|
||||
$sxModel = $notif->getModel(1);
|
||||
|
||||
if (!method_exists($sxModel, "getAvatarUrl")) {
|
||||
$sxModel = $notif->getModel(0);
|
||||
}
|
||||
|
||||
|
||||
$tmpProfiles[] = $sxModel instanceof Club ? $sxModel->getId() * -1 : $sxModel->getId();
|
||||
$res->items[] = $notif->toVkApiStruct();
|
||||
}
|
||||
|
||||
foreach (array_unique($tmpProfiles) as $id) {
|
||||
if ($id > 0) {
|
||||
$sxModel = (new Users())->get($id);
|
||||
$result = (object) [
|
||||
"uid" => $sxModel->getId(),
|
||||
"first_name" => $sxModel->getFirstName(),
|
||||
"last_name" => $sxModel->getLastName(),
|
||||
"photo" => $sxModel->getAvatarUrl(),
|
||||
"photo_medium_rec" => $sxModel->getAvatarUrl("tiny"),
|
||||
"screen_name" => $sxModel->getShortCode(),
|
||||
];
|
||||
|
||||
$res->profiles[] = $result;
|
||||
} else {
|
||||
$sxModel = (new Clubs())->get(abs($id));
|
||||
$result = $sxModel->toVkApiStruct($this->getUser());
|
||||
|
||||
$res->groups[] = $result;
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function markAsViewed()
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
try {
|
||||
$this->getUser()->updateNotificationOffset();
|
||||
$this->getUser()->save();
|
||||
} catch (\Throwable $e) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -1,15 +1,19 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
|
||||
use openvk\Web\Models\Repositories\{Users as UsersRepo, Clubs as ClubsRepo, Posts as PostsRepo};
|
||||
|
||||
final class Ovk extends VKAPIRequestHandler
|
||||
{
|
||||
function version(): string
|
||||
public function version(): string
|
||||
{
|
||||
return OPENVK_VERSION;
|
||||
}
|
||||
|
||||
function test(): object
|
||||
public function test(): object
|
||||
{
|
||||
return (object) [
|
||||
"authorized" => $this->userAuthorized(),
|
||||
|
@ -18,57 +22,58 @@ final class Ovk extends VKAPIRequestHandler
|
|||
];
|
||||
}
|
||||
|
||||
function chickenWings(): string
|
||||
public function chickenWings(): string
|
||||
{
|
||||
return "крылышки";
|
||||
}
|
||||
|
||||
function aboutInstance(string $fields = "statistics,administrators,popular_groups,links", string $admin_fields = "", string $group_fields = ""): object
|
||||
public function aboutInstance(string $fields = "statistics,administrators,popular_groups,links", string $admin_fields = "", string $group_fields = ""): object
|
||||
{
|
||||
$fields = explode(',', $fields);
|
||||
$response = (object) [];
|
||||
|
||||
if(in_array("statistics", $fields)) {
|
||||
$usersStats = (new UsersRepo)->getStatistics();
|
||||
$clubsCount = (new ClubsRepo)->getCount();
|
||||
$postsCount = (new PostsRepo)->getCount();
|
||||
if (in_array("statistics", $fields)) {
|
||||
$usersStats = (new UsersRepo())->getStatistics();
|
||||
$clubsCount = (new ClubsRepo())->getCount();
|
||||
$postsCount = (new PostsRepo())->getCount();
|
||||
$response->statistics = (object) [
|
||||
"users_count" => $usersStats->all,
|
||||
"online_users_count" => $usersStats->online,
|
||||
"active_users_count" => $usersStats->active,
|
||||
"groups_count" => $clubsCount,
|
||||
"wall_posts_count" => $postsCount
|
||||
"wall_posts_count" => $postsCount,
|
||||
];
|
||||
}
|
||||
|
||||
if(in_array("administrators", $fields)) {
|
||||
$admins = iterator_to_array((new UsersRepo)->getInstanceAdmins());
|
||||
$adminsResponse = (new Users($this->getUser()))->get(implode(',', array_map(function($admin) {
|
||||
if (in_array("administrators", $fields)) {
|
||||
$admins = iterator_to_array((new UsersRepo())->getInstanceAdmins());
|
||||
$adminsResponse = (new Users($this->getUser()))->get(implode(',', array_map(function ($admin) {
|
||||
return $admin->getId();
|
||||
}, $admins)), $admin_fields, 0, sizeof($admins));
|
||||
$response->administrators = (object) [
|
||||
"count" => sizeof($admins),
|
||||
"items" => $adminsResponse
|
||||
"items" => $adminsResponse,
|
||||
];
|
||||
}
|
||||
|
||||
if(in_array("popular_groups", $fields)) {
|
||||
$popularClubs = iterator_to_array((new ClubsRepo)->getPopularClubs());
|
||||
$clubsResponse = (new Groups($this->getUser()))->getById(implode(',', array_map(function($entry) {
|
||||
if (in_array("popular_groups", $fields)) {
|
||||
$popularClubs = iterator_to_array((new ClubsRepo())->getPopularClubs());
|
||||
$clubsResponse = (new Groups($this->getUser()))->getById(implode(',', array_map(function ($entry) {
|
||||
return $entry->club->getId();
|
||||
}, $popularClubs)), "", "members_count, " . $group_fields);
|
||||
|
||||
$response->popular_groups = (object) [
|
||||
"count" => sizeof($popularClubs),
|
||||
"items" => $clubsResponse
|
||||
"items" => $clubsResponse,
|
||||
];
|
||||
}
|
||||
|
||||
if(in_array("links", $fields))
|
||||
if (in_array("links", $fields)) {
|
||||
$response->links = (object) [
|
||||
"count" => sizeof(OPENVK_ROOT_CONF['openvk']['preferences']['about']['links']),
|
||||
"items" => is_null(OPENVK_ROOT_CONF['openvk']['preferences']['about']['links']) ? [] : OPENVK_ROOT_CONF['openvk']['preferences']['about']['links']
|
||||
"items" => is_null(OPENVK_ROOT_CONF['openvk']['preferences']['about']['links']) ? [] : OPENVK_ROOT_CONF['openvk']['preferences']['about']['links'],
|
||||
];
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
|
|
@ -1,16 +1,21 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
|
||||
use openvk\Web\Models\Repositories\Applications;
|
||||
|
||||
final class Pay extends VKAPIRequestHandler
|
||||
{
|
||||
function getIdByMarketingId(string $marketing_id): int
|
||||
public function getIdByMarketingId(string $marketing_id): int
|
||||
{
|
||||
[$hexId, $signature] = explode("_", $marketing_id);
|
||||
try {
|
||||
$key = CHANDLER_ROOT_CONF["security"]["secret"];
|
||||
if(sodium_memcmp(base64_decode($signature), hash_hmac("sha512/224", $hexId, $key, true)) == -1)
|
||||
if (sodium_memcmp(base64_decode($signature), hash_hmac("sha512/224", $hexId, $key, true)) == -1) {
|
||||
$this->fail(4, "Invalid marketing id");
|
||||
}
|
||||
} catch (\SodiumException $e) {
|
||||
$this->fail(4, "Invalid marketing id");
|
||||
}
|
||||
|
@ -18,21 +23,23 @@ final class Pay extends VKAPIRequestHandler
|
|||
return hexdec($hexId);
|
||||
}
|
||||
|
||||
function verifyOrder(int $app_id, float $amount, string $signature): bool
|
||||
public function verifyOrder(int $app_id, float $amount, string $signature): bool
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$app = (new Applications())->get($app_id);
|
||||
if(!$app)
|
||||
if (!$app) {
|
||||
$this->fail(26, "No app found with this id");
|
||||
else if($app->getOwner()->getId() != $this->getUser()->getId())
|
||||
} elseif ($app->getOwner()->getId() != $this->getUser()->getId()) {
|
||||
$this->fail(15, "Access error");
|
||||
}
|
||||
|
||||
[$time, $signature] = explode(",", $signature);
|
||||
try {
|
||||
$key = CHANDLER_ROOT_CONF["security"]["secret"];
|
||||
if(sodium_memcmp($signature, hash_hmac("whirlpool", "$app_id:$amount:$time", $key)) == -1)
|
||||
if (sodium_memcmp($signature, hash_hmac("whirlpool", "$app_id:$amount:$time", $key)) == -1) {
|
||||
$this->fail(4, "Invalid order");
|
||||
}
|
||||
} catch (\SodiumException $e) {
|
||||
$this->fail(4, "Invalid order");
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
|
||||
use Nette\InvalidStateException;
|
||||
|
@ -33,51 +36,54 @@ final class Photos extends VKAPIRequestHandler
|
|||
return ovk_scheme(true) . $_SERVER["HTTP_HOST"] . "/upload/photo/$uploadHash?$uploadInfo";
|
||||
}
|
||||
|
||||
private function getImagePath(string $photo, string $hash, ?string& $up = NULL, ?string& $group = NULL): string
|
||||
private function getImagePath(string $photo, string $hash, ?string& $up = null, ?string& $group = null): string
|
||||
{
|
||||
$secret = CHANDLER_ROOT_CONF["security"]["secret"];
|
||||
if(!hash_equals(hash_hmac("sha3-224", $photo, $secret), $hash))
|
||||
if (!hash_equals(hash_hmac("sha3-224", $photo, $secret), $hash)) {
|
||||
$this->fail(121, "Incorrect hash");
|
||||
}
|
||||
|
||||
[$up, $image, $group] = explode("|", $photo);
|
||||
|
||||
$imagePath = __DIR__ . "/../../tmp/api-storage/photos/$up" . "_$image.oct";
|
||||
if(!file_exists($imagePath))
|
||||
if (!file_exists($imagePath)) {
|
||||
$this->fail(10, "Invalid image");
|
||||
}
|
||||
|
||||
return $imagePath;
|
||||
}
|
||||
|
||||
function getOwnerPhotoUploadServer(int $owner_id = 0): object
|
||||
public function getOwnerPhotoUploadServer(int $owner_id = 0): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
if($owner_id < 0) {
|
||||
$club = (new Clubs)->get(abs($owner_id));
|
||||
if(!$club)
|
||||
$this->fail(0404, "Club not found");
|
||||
else if(!$club->canBeModifiedBy($this->getUser()))
|
||||
if ($owner_id < 0) {
|
||||
$club = (new Clubs())->get(abs($owner_id));
|
||||
if (!$club) {
|
||||
$this->fail(0o404, "Club not found");
|
||||
} elseif (!$club->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(200, "Access: Club can't be 'written' by user");
|
||||
}
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"upload_url" => $this->getPhotoUploadUrl("photo", !isset($club) ? 0 : $club->getId()),
|
||||
];
|
||||
}
|
||||
|
||||
function saveOwnerPhoto(string $photo, string $hash): object
|
||||
public function saveOwnerPhoto(string $photo, string $hash): object
|
||||
{
|
||||
$imagePath = $this->getImagePath($photo, $hash, $uploader, $group);
|
||||
if($group == 0) {
|
||||
$user = (new \openvk\Web\Models\Repositories\Users)->get((int) $uploader);
|
||||
$album = (new Albums)->getUserAvatarAlbum($user);
|
||||
if ($group == 0) {
|
||||
$user = (new \openvk\Web\Models\Repositories\Users())->get((int) $uploader);
|
||||
$album = (new Albums())->getUserAvatarAlbum($user);
|
||||
} else {
|
||||
$club = (new Clubs)->get((int) $group);
|
||||
$album = (new Albums)->getClubAvatarAlbum($club);
|
||||
$club = (new Clubs())->get((int) $group);
|
||||
$album = (new Albums())->getClubAvatarAlbum($club);
|
||||
}
|
||||
|
||||
try {
|
||||
$avatar = new Photo;
|
||||
$avatar = new Photo();
|
||||
$avatar->setOwner((int) $uploader);
|
||||
$avatar->setDescription("Profile photo");
|
||||
$avatar->setCreated(time());
|
||||
|
@ -88,30 +94,31 @@ final class Photos extends VKAPIRequestHandler
|
|||
$avatar->save();
|
||||
$album->addPhoto($avatar);
|
||||
unlink($imagePath);
|
||||
} catch(ImageException | InvalidStateException $e) {
|
||||
} catch (ImageException | InvalidStateException $e) {
|
||||
unlink($imagePath);
|
||||
$this->fail(129, "Invalid image file");
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"photo_hash" => NULL,
|
||||
"photo_hash" => null,
|
||||
"photo_src" => $avatar->getURL(),
|
||||
];
|
||||
}
|
||||
|
||||
function getWallUploadServer(?int $group_id = NULL): object
|
||||
public function getWallUploadServer(?int $group_id = null): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$album = NULL;
|
||||
if(!is_null($group_id)) {
|
||||
$club = (new Clubs)->get(abs($group_id));
|
||||
if(!$club)
|
||||
$this->fail(0404, "Club not found");
|
||||
else if(!$club->canBeModifiedBy($this->getUser()))
|
||||
$album = null;
|
||||
if (!is_null($group_id)) {
|
||||
$club = (new Clubs())->get(abs($group_id));
|
||||
if (!$club) {
|
||||
$this->fail(0o404, "Club not found");
|
||||
} elseif (!$club->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(200, "Access: Club can't be 'written' by user");
|
||||
}
|
||||
} else {
|
||||
$album = (new Albums)->getUserWallAlbum($this->getUser());
|
||||
$album = (new Albums())->getUserWallAlbum($this->getUser());
|
||||
}
|
||||
|
||||
return (object) [
|
||||
|
@ -121,20 +128,21 @@ final class Photos extends VKAPIRequestHandler
|
|||
];
|
||||
}
|
||||
|
||||
function saveWallPhoto(string $photo, string $hash, int $group_id = 0, ?string $caption = NULL): array
|
||||
public function saveWallPhoto(string $photo, string $hash, int $group_id = 0, ?string $caption = null): array
|
||||
{
|
||||
$imagePath = $this->getImagePath($photo, $hash, $uploader, $group);
|
||||
if($group_id != $group)
|
||||
if ($group_id != $group) {
|
||||
$this->fail(8, "group_id doesn't match");
|
||||
}
|
||||
|
||||
$album = NULL;
|
||||
if($group_id != 0) {
|
||||
$uploader = (new \openvk\Web\Models\Repositories\Users)->get((int) $uploader);
|
||||
$album = (new Albums)->getUserWallAlbum($uploader);
|
||||
$album = null;
|
||||
if ($group_id != 0) {
|
||||
$uploader = (new \openvk\Web\Models\Repositories\Users())->get((int) $uploader);
|
||||
$album = (new Albums())->getUserWallAlbum($uploader);
|
||||
}
|
||||
|
||||
try {
|
||||
$photo = new Photo;
|
||||
$photo = new Photo();
|
||||
$photo->setOwner((int) $uploader);
|
||||
$photo->setCreated(time());
|
||||
$photo->setFile([
|
||||
|
@ -142,25 +150,27 @@ final class Photos extends VKAPIRequestHandler
|
|||
"error" => 0,
|
||||
]);
|
||||
|
||||
if (!is_null($caption))
|
||||
if (!is_null($caption)) {
|
||||
$photo->setDescription($caption);
|
||||
}
|
||||
|
||||
$photo->save();
|
||||
unlink($imagePath);
|
||||
} catch(ImageException | InvalidStateException $e) {
|
||||
} catch (ImageException | InvalidStateException $e) {
|
||||
unlink($imagePath);
|
||||
$this->fail(129, "Invalid image file");
|
||||
}
|
||||
|
||||
if(!is_null($album))
|
||||
if (!is_null($album)) {
|
||||
$album->addPhoto($photo);
|
||||
}
|
||||
|
||||
return [
|
||||
$photo->toVkApiStruct(),
|
||||
];
|
||||
}
|
||||
|
||||
function getUploadServer(?int $album_id = NULL): object
|
||||
public function getUploadServer(?int $album_id = null): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
|
@ -172,34 +182,37 @@ final class Photos extends VKAPIRequestHandler
|
|||
];
|
||||
}
|
||||
|
||||
function save(string $photos_list, string $hash, int $album_id = 0, ?string $caption = NULL): object
|
||||
public function save(string $photos_list, string $hash, int $album_id = 0, ?string $caption = null): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$secret = CHANDLER_ROOT_CONF["security"]["secret"];
|
||||
if(!hash_equals(hash_hmac("sha3-224", $photos_list, $secret), $hash))
|
||||
if (!hash_equals(hash_hmac("sha3-224", $photos_list, $secret), $hash)) {
|
||||
$this->fail(121, "Incorrect hash");
|
||||
}
|
||||
|
||||
$album = NULL;
|
||||
if($album_id != 0) {
|
||||
$album_ = (new Albums)->get($album_id);
|
||||
if(!$album_)
|
||||
$this->fail(0404, "Invalid album");
|
||||
else if(!$album_->canBeModifiedBy($this->getUser()))
|
||||
$album = null;
|
||||
if ($album_id != 0) {
|
||||
$album_ = (new Albums())->get($album_id);
|
||||
if (!$album_) {
|
||||
$this->fail(0o404, "Invalid album");
|
||||
} elseif (!$album_->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(15, "Access: Album can't be 'written' by user");
|
||||
}
|
||||
|
||||
$album = $album_;
|
||||
}
|
||||
|
||||
$pList = json_decode($photos_list);
|
||||
$imagePaths = [];
|
||||
foreach($pList as $pDesc)
|
||||
foreach ($pList as $pDesc) {
|
||||
$imagePaths[] = __DIR__ . "/../../tmp/api-storage/photos/$pDesc->keyholder" . "_$pDesc->resource.oct";
|
||||
}
|
||||
|
||||
$images = [];
|
||||
try {
|
||||
foreach($imagePaths as $imagePath) {
|
||||
$photo = new Photo;
|
||||
foreach ($imagePaths as $imagePath) {
|
||||
$photo = new Photo();
|
||||
$photo->setOwner($this->getUser()->getId());
|
||||
$photo->setCreated(time());
|
||||
$photo->setFile([
|
||||
|
@ -207,20 +220,23 @@ final class Photos extends VKAPIRequestHandler
|
|||
"error" => 0,
|
||||
]);
|
||||
|
||||
if (!is_null($caption))
|
||||
if (!is_null($caption)) {
|
||||
$photo->setDescription($caption);
|
||||
}
|
||||
|
||||
$photo->save();
|
||||
unlink($imagePath);
|
||||
|
||||
if(!is_null($album))
|
||||
if (!is_null($album)) {
|
||||
$album->addPhoto($photo);
|
||||
}
|
||||
|
||||
$images[] = $photo->toVkApiStruct();
|
||||
}
|
||||
} catch(ImageException | InvalidStateException $e) {
|
||||
foreach($imagePaths as $imagePath)
|
||||
} catch (ImageException | InvalidStateException $e) {
|
||||
foreach ($imagePaths as $imagePath) {
|
||||
unlink($imagePath);
|
||||
}
|
||||
|
||||
$this->fail(129, "Invalid image file");
|
||||
}
|
||||
|
@ -231,20 +247,20 @@ final class Photos extends VKAPIRequestHandler
|
|||
];
|
||||
}
|
||||
|
||||
function createAlbum(string $title, int $group_id = 0, string $description = "", int $privacy = 0)
|
||||
public function createAlbum(string $title, int $group_id = 0, string $description = "", int $privacy = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if($group_id != 0) {
|
||||
$club = (new Clubs)->get((int) $group_id);
|
||||
if ($group_id != 0) {
|
||||
$club = (new Clubs())->get((int) $group_id);
|
||||
|
||||
if(!$club || !$club->canBeModifiedBy($this->getUser())) {
|
||||
if (!$club || !$club->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(20, "Invalid club");
|
||||
}
|
||||
}
|
||||
|
||||
$album = new Album;
|
||||
$album = new Album();
|
||||
$album->setOwner(isset($club) ? $club->getId() * -1 : $this->getUser()->getId());
|
||||
$album->setName($title);
|
||||
$album->setDescription($description);
|
||||
|
@ -254,26 +270,26 @@ final class Photos extends VKAPIRequestHandler
|
|||
return $album->toVkApiStruct($this->getUser());
|
||||
}
|
||||
|
||||
function editAlbum(int $album_id, int $owner_id, string $title, string $description = "", int $privacy = 0)
|
||||
public function editAlbum(int $album_id, int $owner_id, string $title, string $description = "", int $privacy = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$album = (new Albums)->getAlbumByOwnerAndId($owner_id, $album_id);
|
||||
$album = (new Albums())->getAlbumByOwnerAndId($owner_id, $album_id);
|
||||
|
||||
if(!$album || $album->isDeleted()) {
|
||||
if (!$album || $album->isDeleted()) {
|
||||
$this->fail(2, "Invalid album");
|
||||
}
|
||||
|
||||
if(empty($title)) {
|
||||
if (empty($title)) {
|
||||
$this->fail(25, "Title is empty");
|
||||
}
|
||||
|
||||
if($album->isCreatedBySystem()) {
|
||||
if ($album->isCreatedBySystem()) {
|
||||
$this->fail(40, "You can't change system album");
|
||||
}
|
||||
|
||||
if(!$album->canBeModifiedBy($this->getUser())) {
|
||||
if (!$album->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(2, "Access to album denied");
|
||||
}
|
||||
|
||||
|
@ -285,52 +301,55 @@ final class Photos extends VKAPIRequestHandler
|
|||
return $album->toVkApiStruct($this->getUser());
|
||||
}
|
||||
|
||||
function getAlbums(int $owner_id, string $album_ids = "", int $offset = 0, int $count = 100, bool $need_system = true, bool $need_covers = true, bool $photo_sizes = false)
|
||||
public function getAlbums(int $owner_id, string $album_ids = "", int $offset = 0, int $count = 100, bool $need_system = true, bool $need_covers = true, bool $photo_sizes = false)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$res = [];
|
||||
|
||||
if(empty($album_ids)) {
|
||||
if($owner_id > 0) {
|
||||
$user = (new UsersRepo)->get($owner_id);
|
||||
if (empty($album_ids)) {
|
||||
if ($owner_id > 0) {
|
||||
$user = (new UsersRepo())->get($owner_id);
|
||||
|
||||
$res = [
|
||||
"count" => (new Albums)->getUserAlbumsCount($user),
|
||||
"items" => []
|
||||
"count" => (new Albums())->getUserAlbumsCount($user),
|
||||
"items" => [],
|
||||
];
|
||||
|
||||
if(!$user || $user->isDeleted())
|
||||
if (!$user || $user->isDeleted()) {
|
||||
$this->fail(2, "Invalid user");
|
||||
}
|
||||
|
||||
|
||||
if(!$user->getPrivacyPermission('photos.read', $this->getUser()))
|
||||
if (!$user->getPrivacyPermission('photos.read', $this->getUser())) {
|
||||
$this->fail(21, "This user chose to hide his albums.");
|
||||
}
|
||||
|
||||
$albums = array_slice(iterator_to_array((new Albums)->getUserAlbums($user, 1, $count + $offset)), $offset);
|
||||
$albums = array_slice(iterator_to_array((new Albums())->getUserAlbums($user, 1, $count + $offset)), $offset);
|
||||
|
||||
foreach($albums as $album) {
|
||||
if(!$need_system && $album->isCreatedBySystem()) continue;
|
||||
foreach ($albums as $album) {
|
||||
if (!$need_system && $album->isCreatedBySystem()) {
|
||||
continue;
|
||||
}
|
||||
$res["items"][] = $album->toVkApiStruct($this->getUser(), $need_covers, $photo_sizes);
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
$club = (new Clubs)->get($owner_id * -1);
|
||||
} else {
|
||||
$club = (new Clubs())->get($owner_id * -1);
|
||||
|
||||
$res = [
|
||||
"count" => (new Albums)->getClubAlbumsCount($club),
|
||||
"items" => []
|
||||
"count" => (new Albums())->getClubAlbumsCount($club),
|
||||
"items" => [],
|
||||
];
|
||||
|
||||
if(!$club)
|
||||
if (!$club) {
|
||||
$this->fail(2, "Invalid club");
|
||||
}
|
||||
|
||||
$albums = array_slice(iterator_to_array((new Albums)->getClubAlbums($club, 1, $count + $offset)), $offset);
|
||||
$albums = array_slice(iterator_to_array((new Albums())->getClubAlbums($club, 1, $count + $offset)), $offset);
|
||||
|
||||
foreach($albums as $album) {
|
||||
if(!$need_system && $album->isCreatedBySystem()) continue;
|
||||
foreach ($albums as $album) {
|
||||
if (!$need_system && $album->isCreatedBySystem()) {
|
||||
continue;
|
||||
}
|
||||
$res["items"][] = $album->toVkApiStruct($this->getUser(), $need_covers, $photo_sizes);
|
||||
}
|
||||
}
|
||||
|
@ -340,16 +359,17 @@ final class Photos extends VKAPIRequestHandler
|
|||
|
||||
$res = [
|
||||
"count" => sizeof($albums),
|
||||
"items" => []
|
||||
"items" => [],
|
||||
];
|
||||
|
||||
foreach($albums as $album)
|
||||
{
|
||||
foreach ($albums as $album) {
|
||||
$id = explode("_", $album);
|
||||
|
||||
$album = (new Albums)->getAlbumByOwnerAndId((int)$id[0], (int)$id[1]);
|
||||
if($album && !$album->isDeleted()) {
|
||||
if(!$need_system && $album->isCreatedBySystem()) continue;
|
||||
$album = (new Albums())->getAlbumByOwnerAndId((int) $id[0], (int) $id[1]);
|
||||
if ($album && !$album->isDeleted()) {
|
||||
if (!$need_system && $album->isCreatedBySystem()) {
|
||||
continue;
|
||||
}
|
||||
$res["items"][] = $album->toVkApiStruct($this->getUser(), $need_covers, $photo_sizes);
|
||||
}
|
||||
}
|
||||
|
@ -358,62 +378,54 @@ final class Photos extends VKAPIRequestHandler
|
|||
return $res;
|
||||
}
|
||||
|
||||
function getAlbumsCount(int $user_id = 0, int $group_id = 0)
|
||||
public function getAlbumsCount(int $user_id = 0, int $group_id = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if($user_id == 0 && $group_id == 0 || $user_id > 0 && $group_id > 0) {
|
||||
if ($user_id == 0 && $group_id == 0 || $user_id > 0 && $group_id > 0) {
|
||||
$this->fail(21, "Select user_id or group_id");
|
||||
}
|
||||
|
||||
if($user_id > 0) {
|
||||
|
||||
$us = (new UsersRepo)->get($user_id);
|
||||
if(!$us || $us->isDeleted()) {
|
||||
if ($user_id > 0) {
|
||||
$us = (new UsersRepo())->get($user_id);
|
||||
if (!$us || $us->isDeleted()) {
|
||||
$this->fail(21, "Invalid user");
|
||||
}
|
||||
|
||||
if(!$us->getPrivacyPermission('photos.read', $this->getUser())) {
|
||||
if (!$us->getPrivacyPermission('photos.read', $this->getUser())) {
|
||||
$this->fail(21, "This user chose to hide his albums.");
|
||||
}
|
||||
|
||||
return (new Albums)->getUserAlbumsCount($us);
|
||||
return (new Albums())->getUserAlbumsCount($us);
|
||||
}
|
||||
|
||||
if($group_id > 0)
|
||||
{
|
||||
$cl = (new Clubs)->get($group_id);
|
||||
if(!$cl) {
|
||||
if ($group_id > 0) {
|
||||
$cl = (new Clubs())->get($group_id);
|
||||
if (!$cl) {
|
||||
$this->fail(21, "Invalid club");
|
||||
}
|
||||
|
||||
return (new Albums)->getClubAlbumsCount($cl);
|
||||
return (new Albums())->getClubAlbumsCount($cl);
|
||||
}
|
||||
}
|
||||
|
||||
function getById(string $photos, bool $extended = false, bool $photo_sizes = false)
|
||||
public function getById(string $photos, bool $extended = false, bool $photo_sizes = false)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$phts = explode(",", $photos);
|
||||
$res = [];
|
||||
|
||||
foreach($phts as $phota) {
|
||||
foreach ($phts as $phota) {
|
||||
$ph = explode("_", $phota);
|
||||
$photo = (new PhotosRepo)->getByOwnerAndVID((int)$ph[0], (int)$ph[1]);
|
||||
$photo = (new PhotosRepo())->getByOwnerAndVID((int) $ph[0], (int) $ph[1]);
|
||||
|
||||
if(!$photo || $photo->isDeleted()) {
|
||||
if (!$photo || $photo->isDeleted()) {
|
||||
$this->fail(21, "Invalid photo");
|
||||
}
|
||||
|
||||
if($photo->getOwner()->isDeleted()) {
|
||||
$this->fail(21, "Owner of this photo is deleted");
|
||||
}
|
||||
|
||||
if(!$photo->getOwner()->getPrivacyPermission('photos.read', $this->getUser())) {
|
||||
$this->fail(21, "This user chose to hide his photos.");
|
||||
if (!$photo->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
$res[] = $photo->toVkApiStruct($photo_sizes, $extended);
|
||||
|
@ -422,29 +434,30 @@ final class Photos extends VKAPIRequestHandler
|
|||
return $res;
|
||||
}
|
||||
|
||||
function get(int $owner_id, int $album_id, string $photo_ids = "", bool $extended = false, bool $photo_sizes = false, int $offset = 0, int $count = 10)
|
||||
public function get(int $owner_id, int $album_id, string $photo_ids = "", bool $extended = false, bool $photo_sizes = false, int $offset = 0, int $count = 10)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$res = [];
|
||||
|
||||
if(empty($photo_ids)) {
|
||||
$album = (new Albums)->getAlbumByOwnerAndId($owner_id, $album_id);
|
||||
if (empty($photo_ids)) {
|
||||
$album = (new Albums())->getAlbumByOwnerAndId($owner_id, $album_id);
|
||||
|
||||
if(!$album->getOwner()->getPrivacyPermission('photos.read', $this->getUser())) {
|
||||
$this->fail(21, "This user chose to hide his albums.");
|
||||
}
|
||||
|
||||
if(!$album || $album->isDeleted()) {
|
||||
if (!$album || $album->isDeleted()) {
|
||||
$this->fail(21, "Invalid album");
|
||||
}
|
||||
|
||||
$photos = array_slice(iterator_to_array($album->getPhotos(1, $count + $offset)), $offset);
|
||||
$res["count"] = sizeof($photos);
|
||||
if (!$album->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
foreach($photos as $photo) {
|
||||
if(!$photo || $photo->isDeleted()) continue;
|
||||
$photos = array_slice(iterator_to_array($album->getPhotos(1, $count + $offset)), $offset);
|
||||
$res["count"] = $album->size();
|
||||
|
||||
foreach ($photos as $photo) {
|
||||
if (!$photo || $photo->isDeleted()) {
|
||||
continue;
|
||||
}
|
||||
$res["items"][] = $photo->toVkApiStruct($photo_sizes, $extended);
|
||||
}
|
||||
|
||||
|
@ -453,15 +466,14 @@ final class Photos extends VKAPIRequestHandler
|
|||
|
||||
$res = [
|
||||
"count" => sizeof($photos),
|
||||
"items" => []
|
||||
"items" => [],
|
||||
];
|
||||
|
||||
foreach($photos as $photo)
|
||||
{
|
||||
foreach ($photos as $photo) {
|
||||
$id = explode("_", $photo);
|
||||
|
||||
$phot = (new PhotosRepo)->getByOwnerAndVID((int)$id[0], (int)$id[1]);
|
||||
if($phot && !$phot->isDeleted()) {
|
||||
$phot = (new PhotosRepo())->getByOwnerAndVID((int) $id[0], (int) $id[1]);
|
||||
if ($phot && !$phot->isDeleted() && $phot->canBeViewedBy($this->getUser())) {
|
||||
$res["items"][] = $phot->toVkApiStruct($photo_sizes, $extended);
|
||||
}
|
||||
}
|
||||
|
@ -470,18 +482,18 @@ final class Photos extends VKAPIRequestHandler
|
|||
return $res;
|
||||
}
|
||||
|
||||
function deleteAlbum(int $album_id, int $group_id = 0)
|
||||
public function deleteAlbum(int $album_id, int $group_id = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$album = (new Albums)->get($album_id);
|
||||
$album = (new Albums())->get($album_id);
|
||||
|
||||
if(!$album || $album->canBeModifiedBy($this->getUser())) {
|
||||
if (!$album || $album->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(21, "Invalid album");
|
||||
}
|
||||
|
||||
if($album->isDeleted()) {
|
||||
if ($album->isDeleted()) {
|
||||
$this->fail(22, "Album already deleted");
|
||||
}
|
||||
|
||||
|
@ -490,22 +502,22 @@ final class Photos extends VKAPIRequestHandler
|
|||
return 1;
|
||||
}
|
||||
|
||||
function edit(int $owner_id, int $photo_id, string $caption = "")
|
||||
public function edit(int $owner_id, int $photo_id, string $caption = "")
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$photo = (new PhotosRepo)->getByOwnerAndVID($owner_id, $photo_id);
|
||||
$photo = (new PhotosRepo())->getByOwnerAndVID($owner_id, $photo_id);
|
||||
|
||||
if(!$photo) {
|
||||
if (!$photo) {
|
||||
$this->fail(21, "Invalid photo");
|
||||
}
|
||||
|
||||
if($photo->isDeleted()) {
|
||||
if ($photo->isDeleted()) {
|
||||
$this->fail(21, "Photo is deleted");
|
||||
}
|
||||
|
||||
if(!empty($caption)) {
|
||||
if (!empty($caption)) {
|
||||
$photo->setDescription($caption);
|
||||
$photo->save();
|
||||
}
|
||||
|
@ -513,45 +525,44 @@ final class Photos extends VKAPIRequestHandler
|
|||
return 1;
|
||||
}
|
||||
|
||||
function delete(int $owner_id, int $photo_id, string $photos = "")
|
||||
public function delete(int $owner_id, int $photo_id, string $photos = "")
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if(empty($photos)) {
|
||||
$photo = (new PhotosRepo)->getByOwnerAndVID($owner_id, $photo_id);
|
||||
if (empty($photos)) {
|
||||
$photo = (new PhotosRepo())->getByOwnerAndVID($owner_id, $photo_id);
|
||||
|
||||
if($this->getUser()->getId() !== $photo->getOwner()->getId()) {
|
||||
if ($this->getUser()->getId() !== $photo->getOwner()->getId()) {
|
||||
$this->fail(21, "You can't delete another's photo");
|
||||
}
|
||||
|
||||
if(!$photo) {
|
||||
if (!$photo) {
|
||||
$this->fail(21, "Invalid photo");
|
||||
}
|
||||
|
||||
if($photo->isDeleted()) {
|
||||
$this->fail(21, "Photo already deleted");
|
||||
if ($photo->isDeleted()) {
|
||||
$this->fail(21, "Photo is already deleted");
|
||||
}
|
||||
|
||||
$photo->delete();
|
||||
} else {
|
||||
$photozs = explode(',', $photos);
|
||||
|
||||
foreach($photozs as $photo)
|
||||
{
|
||||
foreach ($photozs as $photo) {
|
||||
$id = explode("_", $photo);
|
||||
|
||||
$phot = (new PhotosRepo)->getByOwnerAndVID((int)$id[0], (int)$id[1]);
|
||||
$phot = (new PhotosRepo())->getByOwnerAndVID((int) $id[0], (int) $id[1]);
|
||||
|
||||
if($this->getUser()->getId() !== $phot->getOwner()->getId()) {
|
||||
if ($this->getUser()->getId() !== $phot->getOwner()->getId()) {
|
||||
$this->fail(21, "You can't delete another's photo");
|
||||
}
|
||||
|
||||
if(!$phot) {
|
||||
if (!$phot) {
|
||||
$this->fail(21, "Invalid photo");
|
||||
}
|
||||
|
||||
if($phot->isDeleted()) {
|
||||
if ($phot->isDeleted()) {
|
||||
$this->fail(21, "Photo already deleted");
|
||||
}
|
||||
|
||||
|
@ -562,27 +573,23 @@ final class Photos extends VKAPIRequestHandler
|
|||
return 1;
|
||||
}
|
||||
|
||||
function getAllComments(int $owner_id, int $album_id, bool $need_likes = false, int $offset = 0, int $count = 100)
|
||||
public function getAllComments(int $owner_id, int $album_id, bool $need_likes = false, int $offset = 0, int $count = 100)
|
||||
{
|
||||
$this->fail(501, "Not implemented");
|
||||
}
|
||||
|
||||
function deleteComment(int $comment_id, int $owner_id = 0)
|
||||
public function deleteComment(int $comment_id, int $owner_id = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$comment = (new CommentsRepo)->get($comment_id);
|
||||
if(!$comment) {
|
||||
$comment = (new CommentsRepo())->get($comment_id);
|
||||
if (!$comment) {
|
||||
$this->fail(21, "Invalid comment");
|
||||
}
|
||||
|
||||
if(!$comment->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(21, "Forbidden");
|
||||
}
|
||||
|
||||
if($comment->isDeleted()) {
|
||||
$this->fail(4, "Comment already deleted");
|
||||
if (!$comment->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(21, "Access denied");
|
||||
}
|
||||
|
||||
$comment->delete();
|
||||
|
@ -590,27 +597,26 @@ final class Photos extends VKAPIRequestHandler
|
|||
return 1;
|
||||
}
|
||||
|
||||
function createComment(int $owner_id, int $photo_id, string $message = "", string $attachments = "", bool $from_group = false)
|
||||
public function createComment(int $owner_id, int $photo_id, string $message = "", string $attachments = "", bool $from_group = false)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if(empty($message) && empty($attachments)) {
|
||||
if (empty($message) && empty($attachments)) {
|
||||
$this->fail(100, "Required parameter 'message' missing.");
|
||||
}
|
||||
|
||||
$photo = (new PhotosRepo)->getByOwnerAndVID($owner_id, $photo_id);
|
||||
$photo = (new PhotosRepo())->getByOwnerAndVID($owner_id, $photo_id);
|
||||
|
||||
if(!$photo->getAlbum()->getOwner()->getPrivacyPermission('photos.read', $this->getUser())) {
|
||||
$this->fail(21, "This user chose to hide his albums.");
|
||||
if (!$photo || $photo->isDeleted()) {
|
||||
$this->fail(180, "Invalid photo");
|
||||
}
|
||||
|
||||
if(!$photo)
|
||||
$this->fail(180, "Photo not found");
|
||||
if($photo->isDeleted())
|
||||
$this->fail(189, "Photo is deleted");
|
||||
if (!$photo->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(15, "Access to photo denied");
|
||||
}
|
||||
|
||||
$comment = new Comment;
|
||||
$comment = new Comment();
|
||||
$comment->setOwner($this->getUser()->getId());
|
||||
$comment->setModel(get_class($photo));
|
||||
$comment->setTarget($photo->getId());
|
||||
|
@ -618,43 +624,49 @@ final class Photos extends VKAPIRequestHandler
|
|||
$comment->setCreated(time());
|
||||
$comment->save();
|
||||
|
||||
if(!empty($attachments)) {
|
||||
if (!empty($attachments)) {
|
||||
$attachmentsArr = explode(",", $attachments);
|
||||
|
||||
if(sizeof($attachmentsArr) > 10)
|
||||
if (sizeof($attachmentsArr) > 10) {
|
||||
$this->fail(50, "Error: too many attachments");
|
||||
}
|
||||
|
||||
foreach($attachmentsArr as $attac) {
|
||||
$attachmentType = NULL;
|
||||
foreach ($attachmentsArr as $attac) {
|
||||
$attachmentType = null;
|
||||
|
||||
if(str_contains($attac, "photo"))
|
||||
if (str_contains($attac, "photo")) {
|
||||
$attachmentType = "photo";
|
||||
elseif(str_contains($attac, "video"))
|
||||
} elseif (str_contains($attac, "video")) {
|
||||
$attachmentType = "video";
|
||||
else
|
||||
} else {
|
||||
$this->fail(205, "Unknown attachment type");
|
||||
}
|
||||
|
||||
$attachment = str_replace($attachmentType, "", $attac);
|
||||
|
||||
$attachmentOwner = (int)explode("_", $attachment)[0];
|
||||
$attachmentId = (int)end(explode("_", $attachment));
|
||||
$attachmentOwner = (int) explode("_", $attachment)[0];
|
||||
$attachmentId = (int) end(explode("_", $attachment));
|
||||
|
||||
$attacc = NULL;
|
||||
$attacc = null;
|
||||
|
||||
if($attachmentType == "photo") {
|
||||
$attacc = (new PhotosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if(!$attacc || $attacc->isDeleted())
|
||||
if ($attachmentType == "photo") {
|
||||
$attacc = (new PhotosRepo())->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if (!$attacc || $attacc->isDeleted()) {
|
||||
$this->fail(100, "Photo does not exists");
|
||||
if($attacc->getOwner()->getId() != $this->getUser()->getId())
|
||||
}
|
||||
if ($attacc->getOwner()->getId() != $this->getUser()->getId()) {
|
||||
$this->fail(43, "You do not have access to this photo");
|
||||
}
|
||||
|
||||
$comment->attach($attacc);
|
||||
} elseif($attachmentType == "video") {
|
||||
$attacc = (new VideosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if(!$attacc || $attacc->isDeleted())
|
||||
} elseif ($attachmentType == "video") {
|
||||
$attacc = (new VideosRepo())->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if (!$attacc || $attacc->isDeleted()) {
|
||||
$this->fail(100, "Video does not exists");
|
||||
if($attacc->getOwner()->getId() != $this->getUser()->getId())
|
||||
}
|
||||
if ($attacc->getOwner()->getId() != $this->getUser()->getId()) {
|
||||
$this->fail(43, "You do not have access to this video");
|
||||
}
|
||||
|
||||
$comment->attach($attacc);
|
||||
}
|
||||
|
@ -664,65 +676,63 @@ final class Photos extends VKAPIRequestHandler
|
|||
return $comment->getId();
|
||||
}
|
||||
|
||||
function getAll(int $owner_id, bool $extended = false, int $offset = 0, int $count = 100, bool $photo_sizes = false)
|
||||
public function getAll(int $owner_id, bool $extended = false, int $offset = 0, int $count = 100, bool $photo_sizes = false)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if($owner_id < 0) {
|
||||
if ($owner_id < 0) {
|
||||
$this->fail(4, "This method doesn't works with clubs");
|
||||
}
|
||||
|
||||
$user = (new UsersRepo)->get($owner_id);
|
||||
|
||||
if(!$user) {
|
||||
$user = (new UsersRepo())->get($owner_id);
|
||||
if (!$user) {
|
||||
$this->fail(4, "Invalid user");
|
||||
}
|
||||
|
||||
if(!$user->getPrivacyPermission('photos.read', $this->getUser())) {
|
||||
if (!$user->getPrivacyPermission('photos.read', $this->getUser())) {
|
||||
$this->fail(21, "This user chose to hide his albums.");
|
||||
}
|
||||
|
||||
$photos = array_slice(iterator_to_array((new PhotosRepo)->getEveryUserPhoto($user, 1, $count + $offset)), $offset);
|
||||
$res = [];
|
||||
$photos = (new PhotosRepo())->getEveryUserPhoto($user, $offset, $count);
|
||||
$res = [
|
||||
"count" => (new PhotosRepo())->getUserPhotosCount($user),
|
||||
"items" => [],
|
||||
];
|
||||
|
||||
foreach($photos as $photo) {
|
||||
if(!$photo || $photo->isDeleted()) continue;
|
||||
foreach ($photos as $photo) {
|
||||
if (!$photo || $photo->isDeleted()) {
|
||||
continue;
|
||||
}
|
||||
$res["items"][] = $photo->toVkApiStruct($photo_sizes, $extended);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
function getComments(int $owner_id, int $photo_id, bool $need_likes = false, int $offset = 0, int $count = 100, bool $extended = false, string $fields = "")
|
||||
public function getComments(int $owner_id, int $photo_id, bool $need_likes = false, int $offset = 0, int $count = 100, bool $extended = false, string $fields = "")
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$photo = (new PhotosRepo)->getByOwnerAndVID($owner_id, $photo_id);
|
||||
$photo = (new PhotosRepo())->getByOwnerAndVID($owner_id, $photo_id);
|
||||
$comms = array_slice(iterator_to_array($photo->getComments(1, $offset + $count)), $offset);
|
||||
|
||||
if(!$photo) {
|
||||
if (!$photo || $photo->isDeleted()) {
|
||||
$this->fail(4, "Invalid photo");
|
||||
}
|
||||
|
||||
if(!$photo->getAlbum()->getOwner()->getPrivacyPermission('photos.read', $this->getUser())) {
|
||||
$this->fail(21, "This user chose to hide his photos.");
|
||||
}
|
||||
|
||||
if($photo->isDeleted()) {
|
||||
$this->fail(4, "Photo is deleted");
|
||||
if (!$photo->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(21, "Access denied");
|
||||
}
|
||||
|
||||
$res = [
|
||||
"count" => sizeof($comms),
|
||||
"items" => []
|
||||
"items" => [],
|
||||
];
|
||||
|
||||
foreach($comms as $comment) {
|
||||
foreach ($comms as $comment) {
|
||||
$res["items"][] = $comment->toVkApiStruct($this->getUser(), $need_likes, $extended);
|
||||
if($extended) {
|
||||
if($comment->getOwner() instanceof \openvk\Web\Models\Entities\User) {
|
||||
if ($extended) {
|
||||
if ($comment->getOwner() instanceof \openvk\Web\Models\Entities\User) {
|
||||
$res["profiles"][] = $comment->getOwner()->toVkApiStruct();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?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;
|
||||
|
@ -10,31 +14,33 @@ 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")
|
||||
public 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);
|
||||
$poll = (new PollsRepo())->get($poll_id);
|
||||
|
||||
if (!$poll)
|
||||
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)[
|
||||
$users = [];
|
||||
$answers = [];
|
||||
foreach ($poll->getResults()->options as $answer) {
|
||||
$answers[] = (object) [
|
||||
"id" => $answer->id,
|
||||
"rate" => $answer->pct,
|
||||
"text" => $answer->name,
|
||||
"votes" => $answer->votes
|
||||
"votes" => $answer->votes,
|
||||
];
|
||||
}
|
||||
|
||||
$userVote = array();
|
||||
foreach($poll->getUserVote($this->getUser()) as $vote)
|
||||
$userVote = [];
|
||||
foreach ($poll->getUserVote($this->getUser()) as $vote) {
|
||||
$userVote[] = $vote[0];
|
||||
}
|
||||
|
||||
$response = [
|
||||
"multiple" => $poll->isMultipleChoice(),
|
||||
"end_date" => $poll->endsAt() == NULL ? 0 : $poll->endsAt()->timestamp(),
|
||||
"end_date" => $poll->endsAt() == null ? 0 : $poll->endsAt()->timestamp(),
|
||||
"closed" => $poll->hasEnded(),
|
||||
"is_board" => false,
|
||||
"can_edit" => false,
|
||||
|
@ -54,7 +60,7 @@ final class Polls extends VKAPIRequestHandler
|
|||
];
|
||||
|
||||
if ($extended) {
|
||||
$response["profiles"] = (new Users)->get(strval($poll->getOwner()->getId()), $fields, 0, 1);
|
||||
$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
|
||||
*/
|
||||
|
@ -63,45 +69,116 @@ final class Polls extends VKAPIRequestHandler
|
|||
return (object) $response;
|
||||
}
|
||||
|
||||
function addVote(int $poll_id, string $answers_ids)
|
||||
public function addVote(int $poll_id, string $answers_ids)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$poll = (new PollsRepo)->get($poll_id);
|
||||
$poll = (new PollsRepo())->get($poll_id);
|
||||
|
||||
if(!$poll)
|
||||
if (!$poll) {
|
||||
$this->fail(251, "Invalid poll id");
|
||||
}
|
||||
|
||||
try {
|
||||
$poll->vote($this->getUser(), explode(",", $answers_ids));
|
||||
return 1;
|
||||
} catch(AlreadyVotedException $ex) {
|
||||
} catch (AlreadyVotedException $ex) {
|
||||
return 0;
|
||||
} catch(PollLockedException $ex) {
|
||||
} catch (PollLockedException $ex) {
|
||||
return 0;
|
||||
} catch(InvalidOptionException $ex) {
|
||||
} catch (InvalidOptionException $ex) {
|
||||
$this->fail(8, "бдсм вибратор купить в киеве");
|
||||
}
|
||||
}
|
||||
|
||||
function deleteVote(int $poll_id)
|
||||
public function deleteVote(int $poll_id)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$poll = (new PollsRepo)->get($poll_id);
|
||||
$poll = (new PollsRepo())->get($poll_id);
|
||||
|
||||
if(!$poll)
|
||||
if (!$poll) {
|
||||
$this->fail(251, "Invalid poll id");
|
||||
}
|
||||
|
||||
try {
|
||||
$poll->revokeVote($this->getUser());
|
||||
return 1;
|
||||
} catch(PollLockedException $ex) {
|
||||
} catch (PollLockedException $ex) {
|
||||
$this->fail(15, "Access denied: Poll is locked or isn't revotable");
|
||||
} catch(InvalidOptionException $ex) {
|
||||
} catch (InvalidOptionException $ex) {
|
||||
$this->fail(8, "how.to. ook.bacon.in.microwova.");
|
||||
}
|
||||
}
|
||||
|
||||
public function getVoters(int $poll_id, int $answer_ids, int $offset = 0, int $count = 6)
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$poll = (new PollsRepo())->get($poll_id);
|
||||
|
||||
if (!$poll) {
|
||||
$this->fail(251, "Invalid poll");
|
||||
}
|
||||
|
||||
if ($poll->isAnonymous()) {
|
||||
$this->fail(251, "Access denied: poll is anonymous.");
|
||||
}
|
||||
|
||||
$voters = array_slice($poll->getVoters($answer_ids, 1, $offset + $count), $offset);
|
||||
$res = (object) [
|
||||
"answer_id" => $answer_ids,
|
||||
"users" => [],
|
||||
];
|
||||
|
||||
foreach ($voters as $voter) {
|
||||
$res->users[] = $voter->toVkApiStruct();
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function create(string $question, string $add_answers, bool $disable_unvote = false, bool $is_anonymous = false, bool $is_multiple = false, int $end_date = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$options = json_decode($add_answers);
|
||||
|
||||
if (!$options || empty($options)) {
|
||||
$this->fail(62, "Invalid options");
|
||||
}
|
||||
|
||||
if (sizeof($options) > ovkGetQuirk("polls.max-opts")) {
|
||||
$this->fail(51, "Too many options");
|
||||
}
|
||||
|
||||
$poll = new Poll();
|
||||
$poll->setOwner($this->getUser());
|
||||
$poll->setTitle($question);
|
||||
$poll->setMultipleChoice($is_multiple);
|
||||
$poll->setAnonymity($is_anonymous);
|
||||
$poll->setRevotability(!$disable_unvote);
|
||||
$poll->setOptions($options);
|
||||
|
||||
if ($end_date > time()) {
|
||||
if ($end_date > time() + (DAY * 365)) {
|
||||
$this->fail(89, "End date is too big");
|
||||
}
|
||||
|
||||
$poll->setEndDate($end_date);
|
||||
}
|
||||
|
||||
$poll->save();
|
||||
|
||||
return $this->getById($poll->getId());
|
||||
}
|
||||
|
||||
public function edit()
|
||||
{
|
||||
#todo
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
57
VKAPI/Handlers/Reports.php
Normal file
57
VKAPI/Handlers/Reports.php
Normal file
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
|
||||
use openvk\Web\Models\Entities\Report;
|
||||
use openvk\Web\Models\Repositories\Reports as ReportsRepo;
|
||||
|
||||
final class Reports extends VKAPIRequestHandler
|
||||
{
|
||||
public function add(int $owner_id = 0, string $comment = "", int $reason = 0, string $type = "", string $report_source = ""): int
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$allowed_types = ["post", "photo", "video", "group", "comment", "note", "app", "user", "audio"];
|
||||
if ($type == "" || !in_array($type, $allowed_types)) {
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: type should be " . implode(", ", $allowed_types));
|
||||
}
|
||||
|
||||
if ($owner_id <= 0) {
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: Bad input");
|
||||
}
|
||||
|
||||
if (mb_strlen($comment) === 0) {
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: Comment can't be empty");
|
||||
}
|
||||
|
||||
if ($type == "user" && $owner_id == $this->getUser()->getId()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($this->getUser()->isBannedInSupport()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sizeof(iterator_to_array((new ReportsRepo())->getDuplicates($type, $owner_id, null, $this->getUser()->getId()))) > 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
try {
|
||||
$report = new Report();
|
||||
$report->setUser_id($this->getUser()->getId());
|
||||
$report->setTarget_id($owner_id);
|
||||
$report->setType($type);
|
||||
$report->setReason($comment);
|
||||
$report->setCreated(time());
|
||||
|
||||
$report->save();
|
||||
} catch (\Throwable $e) {
|
||||
$this->fail(-1, "Unknown error failed");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -1,29 +1,49 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
|
||||
use openvk\Web\Models\Entities\User;
|
||||
use openvk\Web\Models\Repositories\Users as UsersRepo;
|
||||
|
||||
final class Status extends VKAPIRequestHandler
|
||||
{
|
||||
function get(int $user_id = 0, int $group_id = 0)
|
||||
public function get(int $user_id = 0, int $group_id = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
if($user_id == 0 && $group_id == 0) {
|
||||
return $this->getUser()->getStatus();
|
||||
} else {
|
||||
if($group_id > 0)
|
||||
|
||||
if ($user_id == 0 && $group_id == 0) {
|
||||
$user_id = $this->getUser()->getId();
|
||||
}
|
||||
|
||||
if ($group_id > 0) {
|
||||
$this->fail(501, "Group statuses are not implemented");
|
||||
else
|
||||
return (new UsersRepo)->get($user_id)->getStatus();
|
||||
} else {
|
||||
$user = (new UsersRepo())->get($user_id);
|
||||
|
||||
if (!$user || $user->isDeleted() || !$user->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(15, "Invalid user");
|
||||
}
|
||||
|
||||
$audioStatus = $user->getCurrentAudioStatus();
|
||||
if ($audioStatus) {
|
||||
return [
|
||||
"status" => $user->getStatus(),
|
||||
"audio" => $audioStatus->toVkApiStruct(),
|
||||
];
|
||||
}
|
||||
|
||||
return $user->getStatus();
|
||||
}
|
||||
}
|
||||
|
||||
function set(string $text, int $group_id = 0)
|
||||
public function set(string $text, int $group_id = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if($group_id > 0) {
|
||||
if ($group_id > 0) {
|
||||
$this->fail(501, "Group statuses are not implemented");
|
||||
} else {
|
||||
$this->getUser()->setStatus($text);
|
||||
|
|
|
@ -1,66 +1,81 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
use openvk\Web\Models\Entities\User;
|
||||
|
||||
use openvk\Web\Models\Entities\{User, Report};
|
||||
use openvk\Web\Models\Repositories\Users as UsersRepo;
|
||||
use openvk\Web\Models\Repositories\{Photos, Clubs, Albums, Videos, Notes, Audios};
|
||||
use openvk\Web\Models\Repositories\Reports;
|
||||
|
||||
final class Users extends VKAPIRequestHandler
|
||||
{
|
||||
function get(string $user_ids = "0", string $fields = "", int $offset = 0, int $count = 100, User $authuser = null /* костыль(( */): array
|
||||
public function get(string $user_ids = "0", string $fields = "", int $offset = 0, int $count = 100, User $authuser = null /* костыль(( */): array
|
||||
{
|
||||
if($authuser == NULL) $authuser = $this->getUser();
|
||||
if ($authuser == null) {
|
||||
$authuser = $this->getUser();
|
||||
}
|
||||
|
||||
$users = new UsersRepo();
|
||||
if ($user_ids == "0") {
|
||||
if (!$authuser) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$users = new UsersRepo;
|
||||
if($user_ids == "0")
|
||||
$user_ids = (string) $authuser->getId();
|
||||
}
|
||||
|
||||
|
||||
$usrs = explode(',', $user_ids);
|
||||
$response = array();
|
||||
$response = [];
|
||||
|
||||
$ic = sizeof($usrs);
|
||||
|
||||
if(sizeof($usrs) > $count)
|
||||
if (sizeof($usrs) > $count) {
|
||||
$ic = $count;
|
||||
}
|
||||
|
||||
$usrs = array_slice($usrs, $offset * $count);
|
||||
|
||||
for($i=0; $i < $ic; $i++) {
|
||||
if($usrs[$i] != 0) {
|
||||
for ($i = 0; $i < $ic; $i++) {
|
||||
if ($usrs[$i] != 0) {
|
||||
$usr = $users->get((int) $usrs[$i]);
|
||||
if(is_null($usr) || $usr->isDeleted()) {
|
||||
$response[$i] = (object)[
|
||||
if (is_null($usr) || $usr->isDeleted()) {
|
||||
$response[$i] = (object) [
|
||||
"id" => (int) $usrs[$i],
|
||||
"first_name" => "DELETED",
|
||||
"last_name" => "",
|
||||
"deactivated" => "deleted"
|
||||
"deactivated" => "deleted",
|
||||
];
|
||||
} else if($usr->isBanned()) {
|
||||
$response[$i] = (object)[
|
||||
} elseif ($usr->isBanned()) {
|
||||
$response[$i] = (object) [
|
||||
"id" => $usr->getId(),
|
||||
"first_name" => $usr->getFirstName(),
|
||||
"last_name" => $usr->getLastName(),
|
||||
"first_name" => $usr->getFirstName(true),
|
||||
"last_name" => $usr->getLastName(true),
|
||||
"deactivated" => "banned",
|
||||
"ban_reason" => $usr->getBanReason()
|
||||
"ban_reason" => $usr->getBanReason(),
|
||||
];
|
||||
} else if($usrs[$i] == NULL) {
|
||||
} elseif ($usrs[$i] == null) {
|
||||
|
||||
} else {
|
||||
$response[$i] = (object)[
|
||||
$response[$i] = (object) [
|
||||
"id" => $usr->getId(),
|
||||
"first_name" => $usr->getFirstName(),
|
||||
"last_name" => $usr->getLastName(),
|
||||
"is_closed" => false,
|
||||
"can_access_closed" => true,
|
||||
"first_name" => $usr->getFirstName(true),
|
||||
"last_name" => $usr->getLastName(true),
|
||||
"is_closed" => $usr->isClosed(),
|
||||
"can_access_closed" => (bool) $usr->canBeViewedBy($this->getUser()),
|
||||
];
|
||||
|
||||
$flds = explode(',', $fields);
|
||||
|
||||
foreach($flds as $field) {
|
||||
switch($field) {
|
||||
$canView = $usr->canBeViewedBy($this->getUser());
|
||||
foreach ($flds as $field) {
|
||||
switch ($field) {
|
||||
case "verified":
|
||||
$response[$i]->verified = intval($usr->isVerified());
|
||||
break;
|
||||
case "sex":
|
||||
$response[$i]->sex = $usr->isFemale() ? 1 : 2;
|
||||
$response[$i]->sex = $usr->isFemale() ? 1 : ($usr->isNeutral() ? 0 : 2);
|
||||
break;
|
||||
case "has_photo":
|
||||
$response[$i]->has_photo = is_null($usr->getAvatarPhoto()) ? 0 : 1;
|
||||
|
@ -93,15 +108,24 @@ final class Users extends VKAPIRequestHandler
|
|||
# ору а когда я это успел написать
|
||||
# вова кстати не матерись в коде мамка же спалит азщазаззазщазазаззазазазх
|
||||
case "status":
|
||||
if($usr->getStatus() != NULL)
|
||||
if ($usr->getStatus() != null) {
|
||||
$response[$i]->status = $usr->getStatus();
|
||||
}
|
||||
|
||||
$audioStatus = $usr->getCurrentAudioStatus();
|
||||
|
||||
if ($audioStatus) {
|
||||
$response[$i]->status_audio = $audioStatus->toVkApiStruct();
|
||||
}
|
||||
|
||||
break;
|
||||
case "screen_name":
|
||||
if($usr->getShortCode() != NULL)
|
||||
if ($usr->getShortCode() != null) {
|
||||
$response[$i]->screen_name = $usr->getShortCode();
|
||||
}
|
||||
break;
|
||||
case "friend_status":
|
||||
switch($usr->getSubscriptionStatus($authuser)) {
|
||||
switch ($usr->getSubscriptionStatus($authuser)) {
|
||||
case 3:
|
||||
# NOTICE falling through
|
||||
case 0:
|
||||
|
@ -127,7 +151,7 @@ final class Users extends VKAPIRequestHandler
|
|||
$platform = 4;
|
||||
break;
|
||||
|
||||
case NULL:
|
||||
case null:
|
||||
$platform = 7;
|
||||
break;
|
||||
|
||||
|
@ -138,155 +162,337 @@ final class Users extends VKAPIRequestHandler
|
|||
|
||||
$response[$i]->last_seen = (object) [
|
||||
"platform" => $platform,
|
||||
"time" => $usr->getOnline()->timestamp()
|
||||
"time" => $usr->getOnline()->timestamp(),
|
||||
];
|
||||
}
|
||||
// no break
|
||||
case "music":
|
||||
if (!$canView) {
|
||||
break;
|
||||
}
|
||||
|
||||
$response[$i]->music = $usr->getFavoriteMusic();
|
||||
break;
|
||||
case "movies":
|
||||
if (!$canView) {
|
||||
break;
|
||||
}
|
||||
|
||||
$response[$i]->movies = $usr->getFavoriteFilms();
|
||||
break;
|
||||
case "tv":
|
||||
if (!$canView) {
|
||||
break;
|
||||
}
|
||||
|
||||
$response[$i]->tv = $usr->getFavoriteShows();
|
||||
break;
|
||||
case "books":
|
||||
if (!$canView) {
|
||||
break;
|
||||
}
|
||||
|
||||
$response[$i]->books = $usr->getFavoriteBooks();
|
||||
break;
|
||||
case "city":
|
||||
if (!$canView) {
|
||||
break;
|
||||
}
|
||||
|
||||
$response[$i]->city = $usr->getCity();
|
||||
break;
|
||||
case "interests":
|
||||
if (!$canView) {
|
||||
break;
|
||||
}
|
||||
|
||||
$response[$i]->interests = $usr->getInterests();
|
||||
break;
|
||||
case "quotes":
|
||||
if (!$canView) {
|
||||
break;
|
||||
}
|
||||
|
||||
$response[$i]->quotes = $usr->getFavoriteQuote();
|
||||
break;
|
||||
case "games":
|
||||
if (!$canView) {
|
||||
break;
|
||||
}
|
||||
|
||||
$response[$i]->games = $usr->getFavoriteGames();
|
||||
break;
|
||||
case "email":
|
||||
if (!$canView) {
|
||||
break;
|
||||
}
|
||||
|
||||
$response[$i]->email = $usr->getContactEmail();
|
||||
break;
|
||||
case "telegram":
|
||||
if (!$canView) {
|
||||
break;
|
||||
}
|
||||
|
||||
$response[$i]->telegram = $usr->getTelegram();
|
||||
break;
|
||||
case "about":
|
||||
if (!$canView) {
|
||||
break;
|
||||
}
|
||||
|
||||
$response[$i]->about = $usr->getDescription();
|
||||
break;
|
||||
case "rating":
|
||||
if (!$canView) {
|
||||
break;
|
||||
}
|
||||
|
||||
$response[$i]->rating = $usr->getRating();
|
||||
break;
|
||||
case "counters":
|
||||
$response[$i]->counters = (object) [
|
||||
"friends_count" => $usr->getFriendsCount(),
|
||||
"photos_count" => (new Photos())->getUserPhotosCount($usr),
|
||||
"videos_count" => (new Videos())->getUserVideosCount($usr),
|
||||
"audios_count" => (new Audios())->getUserCollectionSize($usr),
|
||||
"notes_count" => (new Notes())->getUserNotesCount($usr),
|
||||
];
|
||||
break;
|
||||
case "correct_counters":
|
||||
$response[$i]->counters = (object) [
|
||||
"friends" => $usr->getFriendsCount(),
|
||||
"photos" => (new Photos())->getUserPhotosCount($usr),
|
||||
"videos" => (new Videos())->getUserVideosCount($usr),
|
||||
"audios" => (new Audios())->getUserCollectionSize($usr),
|
||||
"notes" => (new Notes())->getUserNotesCount($usr),
|
||||
"groups" => $usr->getClubCount(),
|
||||
"online_friends" => $usr->getFriendsOnlineCount(),
|
||||
];
|
||||
break;
|
||||
case "guid":
|
||||
$response[$i]->guid = $usr->getChandlerGUID();
|
||||
break;
|
||||
case 'background':
|
||||
$backgrounds = $usr->getBackDropPictureURLs();
|
||||
$response[$i]->background = $backgrounds;
|
||||
break;
|
||||
case 'reg_date':
|
||||
if (!$canView) {
|
||||
break;
|
||||
}
|
||||
|
||||
$response[$i]->reg_date = $usr->getRegistrationTime()->timestamp();
|
||||
break;
|
||||
case 'is_dead':
|
||||
$response[$i]->is_dead = $usr->isDead();
|
||||
break;
|
||||
case 'nickname':
|
||||
$response[$i]->nickname = $usr->getPseudo();
|
||||
break;
|
||||
case 'blacklisted_by_me':
|
||||
if (!$authuser) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$response[$i]->blacklisted_by_me = (int) $usr->isBlacklistedBy($this->getUser());
|
||||
break;
|
||||
case 'blacklisted':
|
||||
if (!$authuser) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$response[$i]->blacklisted = (int) $this->getUser()->isBlacklistedBy($usr);
|
||||
break;
|
||||
case "custom_fields":
|
||||
if (sizeof($usrs) > 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
$c_fields = \openvk\Web\Models\Entities\UserInfoEntities\AdditionalField::getByOwner($usr->getId());
|
||||
$append_array = [];
|
||||
foreach ($c_fields as $c_field) {
|
||||
$append_array[] = $c_field->toVkApiStruct();
|
||||
}
|
||||
|
||||
$response[$i]->custom_fields = $append_array;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if($usr->getOnline()->timestamp() + 300 > time())
|
||||
if ($usr->getOnline()->timestamp() + 300 > time()) {
|
||||
$response[$i]->online = 1;
|
||||
else
|
||||
} else {
|
||||
$response[$i]->online = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
function getFollowers(int $user_id, string $fields = "", int $offset = 0, int $count = 100): object
|
||||
public function getFollowers(int $user_id, string $fields = "", int $offset = 0, int $count = 100): object
|
||||
{
|
||||
$offset++;
|
||||
$followers = [];
|
||||
|
||||
$users = new UsersRepo;
|
||||
$users = new UsersRepo();
|
||||
|
||||
$this->requireUser();
|
||||
|
||||
foreach($users->get($user_id)->getFollowers($offset, $count) as $follower)
|
||||
$user = $users->get($user_id);
|
||||
|
||||
if (!$user || $user->isDeleted()) {
|
||||
$this->fail(14, "Invalid user");
|
||||
}
|
||||
|
||||
if (!$user->canBeViewedBy($this->getUser())) {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
|
||||
foreach ($users->get($user_id)->getFollowers($offset, $count) as $follower) {
|
||||
$followers[] = $follower->getId();
|
||||
}
|
||||
|
||||
$response = $followers;
|
||||
|
||||
if(!is_null($fields))
|
||||
if (!is_null($fields)) {
|
||||
$response = $this->get(implode(',', $followers), $fields, 0, $count);
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"count" => $users->get($user_id)->getFollowersCount(),
|
||||
"items" => $response
|
||||
"items" => $response,
|
||||
];
|
||||
}
|
||||
|
||||
function search(string $q,
|
||||
public function search(
|
||||
string $q,
|
||||
string $fields = "",
|
||||
int $offset = 0,
|
||||
int $count = 100,
|
||||
string $city = "",
|
||||
string $hometown = "",
|
||||
int $sex = 2,
|
||||
int $status = 0, # это про marital status
|
||||
int $sex = 3,
|
||||
int $status = 0, # marital_status
|
||||
bool $online = false,
|
||||
# дальше идут параметры которых нету в vkapi но есть на сайте
|
||||
string $profileStatus = "", # а это уже нормальный статус
|
||||
# non standart params:
|
||||
int $sort = 0,
|
||||
int $before = 0,
|
||||
int $politViews = 0,
|
||||
int $after = 0,
|
||||
string $interests = "",
|
||||
int $polit_views = 0,
|
||||
string $fav_music = "",
|
||||
string $fav_films = "",
|
||||
string $fav_shows = "",
|
||||
string $fav_books = "",
|
||||
string $fav_quotes = ""
|
||||
)
|
||||
{
|
||||
$users = new UsersRepo;
|
||||
string $fav_books = ""
|
||||
) {
|
||||
if ($count > 100) {
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: count should be less or equal to 100");
|
||||
}
|
||||
|
||||
$sortg = "id ASC";
|
||||
$users = new UsersRepo();
|
||||
$output_sort = ['type' => 'id', 'invert' => false];
|
||||
$output_params = [
|
||||
"ignore_private" => true,
|
||||
];
|
||||
|
||||
$nfilds = $fields;
|
||||
|
||||
switch($sort) {
|
||||
switch ($sort) {
|
||||
default:
|
||||
case 0:
|
||||
$sortg = "id DESC";
|
||||
$output_sort = ['type' => 'id', 'invert' => false];
|
||||
break;
|
||||
case 1:
|
||||
$sortg = "id ASC";
|
||||
break;
|
||||
case 2:
|
||||
$sortg = "first_name DESC";
|
||||
break;
|
||||
case 3:
|
||||
$sortg = "first_name ASC";
|
||||
$output_sort = ['type' => 'id', 'invert' => true];
|
||||
break;
|
||||
case 4:
|
||||
$sortg = "rating DESC";
|
||||
|
||||
if(!str_contains($nfilds, "rating")) {
|
||||
$nfilds .= "rating";
|
||||
$output_sort = ['type' => 'rating', 'invert' => false];
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case 5:
|
||||
$sortg = "rating DESC";
|
||||
|
||||
if(!str_contains($nfilds, "rating")) {
|
||||
$nfilds .= "rating";
|
||||
if (!empty($city)) {
|
||||
$output_params['city'] = $city;
|
||||
}
|
||||
|
||||
break;
|
||||
if (!empty($hometown)) {
|
||||
$output_params['hometown'] = $hometown;
|
||||
}
|
||||
|
||||
if ($sex != 3) {
|
||||
$output_params['gender'] = $sex;
|
||||
}
|
||||
|
||||
if ($status != 0) {
|
||||
$output_params['marital_status'] = $status;
|
||||
}
|
||||
|
||||
if ($polit_views != 0) {
|
||||
$output_params['polit_views'] = $polit_views;
|
||||
}
|
||||
|
||||
if (!empty($interests)) {
|
||||
$output_params['interests'] = $interests;
|
||||
}
|
||||
|
||||
if (!empty($fav_music)) {
|
||||
$output_params['fav_music'] = $fav_music;
|
||||
}
|
||||
|
||||
if (!empty($fav_films)) {
|
||||
$output_params['fav_films'] = $fav_films;
|
||||
}
|
||||
|
||||
if (!empty($fav_shows)) {
|
||||
$output_params['fav_shows'] = $fav_shows;
|
||||
}
|
||||
|
||||
if (!empty($fav_books)) {
|
||||
$output_params['fav_books'] = $fav_books;
|
||||
}
|
||||
|
||||
if ($online) {
|
||||
$output_params['is_online'] = 1;
|
||||
}
|
||||
|
||||
$array = [];
|
||||
$find = $users->find($q, $output_params, $output_sort);
|
||||
|
||||
$parameters = [
|
||||
"city" => !empty($city) ? $city : NULL,
|
||||
"hometown" => !empty($hometown) ? $hometown : NULL,
|
||||
"gender" => $sex < 2 ? $sex : NULL,
|
||||
"maritalstatus" => (bool)$status ? $status : NULL,
|
||||
"politViews" => (bool)$politViews ? $politViews : NULL,
|
||||
"is_online" => $online ? 1 : NULL,
|
||||
"status" => !empty($profileStatus) ? $profileStatus : NULL,
|
||||
"before" => $before != 0 ? $before : NULL,
|
||||
"after" => $after != 0 ? $after : NULL,
|
||||
"interests" => !empty($interests) ? $interests : NULL,
|
||||
"fav_music" => !empty($fav_music) ? $fav_music : NULL,
|
||||
"fav_films" => !empty($fav_films) ? $fav_films : NULL,
|
||||
"fav_shows" => !empty($fav_shows) ? $fav_shows : NULL,
|
||||
"fav_books" => !empty($fav_books) ? $fav_books : NULL,
|
||||
"fav_quotes" => !empty($fav_quotes) ? $fav_quotes : NULL,
|
||||
];
|
||||
|
||||
$find = $users->find($q, $parameters, $sortg);
|
||||
|
||||
foreach ($find as $user)
|
||||
foreach ($find->offsetLimit($offset, $count) as $user) {
|
||||
$array[] = $user->getId();
|
||||
}
|
||||
|
||||
if (!$array || sizeof($array) < 1) {
|
||||
return (object) [
|
||||
"count" => 0,
|
||||
"items" => [],
|
||||
];
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"count" => $find->size(),
|
||||
"items" => $this->get(implode(',', $array), $nfilds, $offset, $count)
|
||||
"items" => $this->get(implode(',', $array), $fields),
|
||||
];
|
||||
}
|
||||
|
||||
public function report(int $user_id, string $type = "spam", string $comment = "")
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if ($user_id == $this->getUser()->getId()) {
|
||||
$this->fail(12, "Can't report yourself.");
|
||||
}
|
||||
|
||||
if (sizeof(iterator_to_array((new Reports())->getDuplicates("user", $user_id, null, $this->getUser()->getId()))) > 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
$report = new Report();
|
||||
$report->setUser_id($this->getUser()->getId());
|
||||
$report->setTarget_id($user_id);
|
||||
$report->setType("user");
|
||||
$report->setReason($comment);
|
||||
$report->setCreated(time());
|
||||
$report->save();
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,46 +1,62 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
|
||||
use openvk\Web\Models\Repositories\{Users, Clubs};
|
||||
|
||||
final class Utils extends VKAPIRequestHandler
|
||||
{
|
||||
function getServerTime(): int
|
||||
public function getServerTime(): int
|
||||
{
|
||||
return time();
|
||||
}
|
||||
|
||||
function resolveScreenName(string $screen_name): object
|
||||
public function resolveScreenName(string $screen_name): object
|
||||
{
|
||||
if(\Chandler\MVC\Routing\Router::i()->getMatchingRoute("/$screen_name")[0]->presenter !== "UnknownTextRouteStrategy") {
|
||||
if(substr($screen_name, 0, strlen("id")) === "id") {
|
||||
if (\Chandler\MVC\Routing\Router::i()->getMatchingRoute("/$screen_name")[0]->presenter !== "UnknownTextRouteStrategy") {
|
||||
if (substr($screen_name, 0, strlen("id")) === "id") {
|
||||
return (object) [
|
||||
"object_id" => (int) substr($screen_name, strlen("id")),
|
||||
"type" => "user"
|
||||
"type" => "user",
|
||||
];
|
||||
} else if(substr($screen_name, 0, strlen("club")) === "club") {
|
||||
} elseif (substr($screen_name, 0, strlen("club")) === "club") {
|
||||
return (object) [
|
||||
"object_id" => (int) substr($screen_name, strlen("club")),
|
||||
"type" => "group"
|
||||
"type" => "group",
|
||||
];
|
||||
} else {
|
||||
$this->fail(104, "Not found");
|
||||
}
|
||||
} else {
|
||||
$user = (new Users)->getByShortURL($screen_name);
|
||||
if($user) {
|
||||
$user = (new Users())->getByShortURL($screen_name);
|
||||
if ($user) {
|
||||
return (object) [
|
||||
"object_id" => $user->getId(),
|
||||
"type" => "user"
|
||||
"type" => "user",
|
||||
];
|
||||
}
|
||||
|
||||
$club = (new Clubs)->getByShortURL($screen_name);
|
||||
if($club) {
|
||||
$club = (new Clubs())->getByShortURL($screen_name);
|
||||
if ($club) {
|
||||
return (object) [
|
||||
"object_id" => $club->getId(),
|
||||
"type" => "group"
|
||||
"type" => "group",
|
||||
];
|
||||
}
|
||||
|
||||
return (object) [];
|
||||
$this->fail(104, "Not found");
|
||||
}
|
||||
}
|
||||
|
||||
public function resolveGuid(string $guid): object
|
||||
{
|
||||
$user = (new Users())->getByChandlerUserId($guid);
|
||||
if (is_null($user)) {
|
||||
$this->fail(104, "Not found");
|
||||
}
|
||||
|
||||
return $user->toVkApiStruct($this->getUser());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
|
||||
use openvk\VKAPI\Exceptions\APIErrorException;
|
||||
use openvk\Web\Models\Entities\IP;
|
||||
use openvk\Web\Models\Entities\User;
|
||||
|
@ -10,7 +14,7 @@ abstract class VKAPIRequestHandler
|
|||
protected $user;
|
||||
protected $platform;
|
||||
|
||||
function __construct(?User $user = NULL, ?string $platform = NULL)
|
||||
public function __construct(?User $user = null, ?string $platform = null)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->platform = $platform;
|
||||
|
@ -28,7 +32,7 @@ abstract class VKAPIRequestHandler
|
|||
|
||||
protected function getPlatform(): ?string
|
||||
{
|
||||
return $this->platform;
|
||||
return $this->platform ?? "";
|
||||
}
|
||||
|
||||
protected function userAuthorized(): bool
|
||||
|
@ -38,17 +42,18 @@ abstract class VKAPIRequestHandler
|
|||
|
||||
protected function requireUser(): void
|
||||
{
|
||||
if(!$this->userAuthorized())
|
||||
if (!$this->userAuthorized()) {
|
||||
$this->fail(5, "User authorization failed: no access_token passed.");
|
||||
}
|
||||
}
|
||||
|
||||
protected function willExecuteWriteAction(): void
|
||||
{
|
||||
$ip = (new IPs)->get(CONNECTING_IP);
|
||||
$ip = (new IPs())->get(CONNECTING_IP);
|
||||
$res = $ip->rateLimit();
|
||||
|
||||
if(!($res === IP::RL_RESET || $res === IP::RL_CANEXEC)) {
|
||||
if($res === IP::RL_BANNED && OPENVK_ROOT_CONF["openvk"]["preferences"]["security"]["rateLimits"]["autoban"]) {
|
||||
if (!($res === IP::RL_RESET || $res === IP::RL_CANEXEC)) {
|
||||
if ($res === IP::RL_BANNED && OPENVK_ROOT_CONF["openvk"]["preferences"]["security"]["rateLimits"]["autoban"]) {
|
||||
$this->user->ban("User account has been suspended for breaking API terms of service", false);
|
||||
$this->fail(18, "User account has been suspended due to repeated violation of API rate limits.");
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?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\Club;
|
||||
|
@ -11,47 +15,181 @@ use openvk\Web\Models\Repositories\Comments as CommentsRepo;
|
|||
|
||||
final class Video extends VKAPIRequestHandler
|
||||
{
|
||||
function get(int $owner_id, string $videos, int $offset = 0, int $count = 30, int $extended = 0): object
|
||||
public function get(int $owner_id = 0, string $videos = "", string $fields = "", int $offset = 0, int $count = 30, int $extended = 0): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
if ($videos) {
|
||||
if (!empty($videos)) {
|
||||
$vids = explode(',', $videos);
|
||||
|
||||
foreach($vids as $vid)
|
||||
{
|
||||
$profiles = [];
|
||||
$groups = [];
|
||||
foreach ($vids as $vid) {
|
||||
$id = explode("_", $vid);
|
||||
|
||||
$items = [];
|
||||
|
||||
$video = (new VideosRepo)->getByOwnerAndVID(intval($id[0]), intval($id[1]));
|
||||
if($video) {
|
||||
$items[] = $video->getApiStructure();
|
||||
$video = (new VideosRepo())->getByOwnerAndVID(intval($id[0]), intval($id[1]));
|
||||
if ($video && !$video->isDeleted()) {
|
||||
$out_video = $video->getApiStructure($this->getUser())->video;
|
||||
$items[] = $out_video;
|
||||
if ($out_video['owner_id']) {
|
||||
if ($out_video['owner_id'] > 0) {
|
||||
$profiles[] = $out_video['owner_id'];
|
||||
} else {
|
||||
$groups[] = abs($out_video['owner_id']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($extended == 1) {
|
||||
$profiles = array_unique($profiles);
|
||||
$groups = array_unique($groups);
|
||||
|
||||
$profilesFormatted = [];
|
||||
$groupsFormatted = [];
|
||||
|
||||
foreach ($profiles as $prof) {
|
||||
$profile = (new UsersRepo())->get($prof);
|
||||
$profilesFormatted[] = $profile->toVkApiStruct($this->getUser(), $fields);
|
||||
}
|
||||
|
||||
foreach ($groups as $gr) {
|
||||
$group = (new ClubsRepo())->get($gr);
|
||||
$groupsFormatted[] = $group->toVkApiStruct($this->getUser(), $fields);
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"count" => sizeof($items),
|
||||
"items" => $items,
|
||||
"profiles" => $profilesFormatted,
|
||||
"groups" => $groupsFormatted,
|
||||
];
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"count" => count($items),
|
||||
"items" => $items
|
||||
"items" => $items,
|
||||
];
|
||||
} else {
|
||||
if ($owner_id > 0)
|
||||
$user = (new UsersRepo)->get($owner_id);
|
||||
else
|
||||
if ($owner_id > 0) {
|
||||
$user = (new UsersRepo())->get($owner_id);
|
||||
} else {
|
||||
$this->fail(1, "Not implemented");
|
||||
}
|
||||
|
||||
$videos = (new VideosRepo)->getByUser($user, $offset + 1, $count);
|
||||
$videosCount = (new VideosRepo)->getUserVideosCount($user);
|
||||
if (!$user || $user->isDeleted()) {
|
||||
$this->fail(14, "Invalid user");
|
||||
}
|
||||
|
||||
if (!$user->getPrivacyPermission('videos.read', $this->getUser())) {
|
||||
$this->fail(21, "This user chose to hide his videos.");
|
||||
}
|
||||
|
||||
$videos = (new VideosRepo())->getByUserLimit($user, $offset, $count);
|
||||
$videosCount = (new VideosRepo())->getUserVideosCount($user);
|
||||
|
||||
$items = [];
|
||||
$profiles = [];
|
||||
$groups = [];
|
||||
foreach ($videos as $video) {
|
||||
$items[] = $video->getApiStructure();
|
||||
$video = $video->getApiStructure($this->getUser())->video;
|
||||
$items[] = $video;
|
||||
if ($video['owner_id']) {
|
||||
if ($video['owner_id'] > 0) {
|
||||
$profiles[] = $video['owner_id'];
|
||||
} else {
|
||||
$groups[] = abs($video['owner_id']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($extended == 1) {
|
||||
$profiles = array_unique($profiles);
|
||||
$groups = array_unique($groups);
|
||||
|
||||
$profilesFormatted = [];
|
||||
$groupsFormatted = [];
|
||||
|
||||
foreach ($profiles as $prof) {
|
||||
$profile = (new UsersRepo())->get($prof);
|
||||
$profilesFormatted[] = $profile->toVkApiStruct($this->getUser(), $fields);
|
||||
}
|
||||
|
||||
foreach ($groups as $gr) {
|
||||
$group = (new ClubsRepo())->get($gr);
|
||||
$groupsFormatted[] = $group->toVkApiStruct($this->getUser(), $fields);
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"count" => $videosCount,
|
||||
"items" => $items
|
||||
"items" => $items,
|
||||
"profiles" => $profilesFormatted,
|
||||
"groups" => $groupsFormatted,
|
||||
];
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"count" => $videosCount,
|
||||
"items" => $items,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
public function search(string $q = '', int $sort = 0, int $offset = 0, int $count = 10, bool $extended = false, string $fields = ''): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$params = [];
|
||||
$db_sort = ['type' => 'id', 'invert' => false];
|
||||
$videos = (new VideosRepo())->find($q, $params, $db_sort);
|
||||
$items = iterator_to_array($videos->offsetLimit($offset, $count));
|
||||
$count = $videos->size();
|
||||
|
||||
$return_items = [];
|
||||
$profiles = [];
|
||||
$groups = [];
|
||||
foreach ($items as $item) {
|
||||
$return_item = $item->getApiStructure($this->getUser());
|
||||
$return_item = $return_item->video;
|
||||
$return_items[] = $return_item;
|
||||
|
||||
if ($return_item['owner_id']) {
|
||||
if ($return_item['owner_id'] > 0) {
|
||||
$profiles[] = $return_item['owner_id'];
|
||||
} else {
|
||||
$groups[] = abs($return_item['owner_id']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($extended) {
|
||||
$profiles = array_unique($profiles);
|
||||
$groups = array_unique($groups);
|
||||
|
||||
$profilesFormatted = [];
|
||||
$groupsFormatted = [];
|
||||
|
||||
foreach ($profiles as $prof) {
|
||||
$profile = (new UsersRepo())->get($prof);
|
||||
$profilesFormatted[] = $profile->toVkApiStruct($this->getUser(), $fields);
|
||||
}
|
||||
|
||||
foreach ($groups as $gr) {
|
||||
$group = (new ClubsRepo())->get($gr);
|
||||
$groupsFormatted[] = $group->toVkApiStruct($this->getUser(), $fields);
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"count" => $count,
|
||||
"items" => $return_items,
|
||||
"profiles" => $profilesFormatted,
|
||||
"groups" => $groupsFormatted,
|
||||
];
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"count" => $count,
|
||||
"items" => $return_items,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -5,7 +5,7 @@ exceptions. It is still a work-in-progress functionality.
|
|||
**Note**: requests to API are routed through
|
||||
openvk.Web.Presenters.VKAPIPresenter, this dir contains only handlers.
|
||||
|
||||
[Documentation for API clients](https://docs.openvk.uk/openvk_engine/api/description/)
|
||||
[Documentation for API clients](https://docs.ovk.to/openvk_engine/api/description/)
|
||||
|
||||
## Implementing API methods
|
||||
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\VKAPI\Structures;
|
||||
|
||||
final class Conversation
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\VKAPI\Structures;
|
||||
|
||||
final class Message
|
||||
|
@ -17,5 +20,5 @@ final class Message
|
|||
public $emoji;
|
||||
public $important = true;
|
||||
public $deleted = 0;
|
||||
public $random_id = NULL;
|
||||
public $random_id = null;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Events;
|
||||
|
||||
interface ILPEmitable
|
||||
{
|
||||
function getLongPoolSummary(): object;
|
||||
public function getLongPoolSummary(): object;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Events;
|
||||
|
||||
use openvk\Web\Models\Entities\Message;
|
||||
use openvk\Web\Models\Repositories\Messages;
|
||||
|
||||
|
@ -7,12 +11,12 @@ class NewMessageEvent implements ILPEmitable
|
|||
{
|
||||
protected $payload;
|
||||
|
||||
function __construct(Message $message)
|
||||
public function __construct(Message $message)
|
||||
{
|
||||
$this->payload = $message->simplify();
|
||||
}
|
||||
|
||||
function getLongPoolSummary(): object
|
||||
public function getLongPoolSummary(): object
|
||||
{
|
||||
return (object) [
|
||||
"type" => "newMessage",
|
||||
|
@ -20,12 +24,13 @@ class NewMessageEvent implements ILPEmitable
|
|||
];
|
||||
}
|
||||
|
||||
function getVKAPISummary(int $userId): array
|
||||
public function getVKAPISummary(int $userId): array
|
||||
{
|
||||
$msg = (new Messages)->get($this->payload["uuid"]);
|
||||
$msg = (new Messages())->get($this->payload["uuid"]);
|
||||
$peer = $msg->getSender()->getId();
|
||||
if($peer === $userId)
|
||||
if ($peer === $userId) {
|
||||
$peer = $msg->getRecipient()->getId();
|
||||
}
|
||||
|
||||
/*
|
||||
* Source:
|
||||
|
@ -43,7 +48,7 @@ class NewMessageEvent implements ILPEmitable
|
|||
[], # empty attachments
|
||||
$msg->getId() << 2, # id as random_id
|
||||
$peer, # conversation id
|
||||
0 # not edited yet
|
||||
0, # not edited yet
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use openvk\Web\Models\RowModel;
|
||||
use openvk\Web\Models\Repositories\Users;
|
||||
use Nette\InvalidStateException as ISE;
|
||||
|
@ -8,50 +12,51 @@ class APIToken extends RowModel
|
|||
{
|
||||
protected $tableName = "api_tokens";
|
||||
|
||||
function getUser(): User
|
||||
public function getUser(): User
|
||||
{
|
||||
return (new Users)->get($this->getRecord()->user);
|
||||
return (new Users())->get($this->getRecord()->user);
|
||||
}
|
||||
|
||||
function getSecret(): string
|
||||
public function getSecret(): string
|
||||
{
|
||||
return $this->getRecord()->secret;
|
||||
}
|
||||
|
||||
function getFormattedToken(): string
|
||||
public function getFormattedToken(): string
|
||||
{
|
||||
return $this->getId() . "-" . chunk_split($this->getSecret(), 8, "-") . "jill";
|
||||
}
|
||||
|
||||
function getPlatform(): ?string
|
||||
public function getPlatform(): ?string
|
||||
{
|
||||
return $this->getRecord()->platform;
|
||||
}
|
||||
|
||||
function isRevoked(): bool
|
||||
public function isRevoked(): bool
|
||||
{
|
||||
return $this->isDeleted();
|
||||
}
|
||||
|
||||
function setUser(User $user): void
|
||||
public function setUser(User $user): void
|
||||
{
|
||||
$this->stateChanges("user", $user->getId());
|
||||
}
|
||||
|
||||
function setSecret(string $secret): void
|
||||
public function setSecret(string $secret): void
|
||||
{
|
||||
throw new ISE("Setting secret manually is prohbited");
|
||||
}
|
||||
|
||||
function revoke(): void
|
||||
public function revoke(): void
|
||||
{
|
||||
$this->delete();
|
||||
}
|
||||
|
||||
function save(): void
|
||||
public function save(?bool $log = false): void
|
||||
{
|
||||
if(is_null($this->getRecord()))
|
||||
if (is_null($this->getRecord())) {
|
||||
$this->stateChanges("secret", bin2hex(openssl_random_pseudo_bytes(36)));
|
||||
}
|
||||
|
||||
parent::save();
|
||||
}
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use openvk\Web\Models\Repositories\Photos;
|
||||
|
||||
class Album extends MediaCollection
|
||||
{
|
||||
const SPECIAL_AVATARS = 16;
|
||||
const SPECIAL_WALL = 32;
|
||||
public const SPECIAL_AVATARS = 16;
|
||||
public const SPECIAL_WALL = 32;
|
||||
|
||||
protected $tableName = "albums";
|
||||
protected $relTableName = "album_relations";
|
||||
|
@ -18,76 +22,94 @@ class Album extends MediaCollection
|
|||
64 => "_saved_photos_album",
|
||||
];
|
||||
|
||||
function getCoverURL(): ?string
|
||||
public function getCoverURL(): ?string
|
||||
{
|
||||
$coverPhoto = $this->getCoverPhoto();
|
||||
if(!$coverPhoto)
|
||||
if (!$coverPhoto) {
|
||||
return "/assets/packages/static/openvk/img/camera_200.png";
|
||||
}
|
||||
|
||||
return $coverPhoto->getURL();
|
||||
}
|
||||
|
||||
function getCoverPhoto(): ?Photo
|
||||
public function getCoverPhoto(): ?Photo
|
||||
{
|
||||
$cover = $this->getRecord()->cover_photo;
|
||||
if(!$cover) {
|
||||
if (!$cover) {
|
||||
$photos = iterator_to_array($this->getPhotos(1, 1));
|
||||
$photo = $photos[0] ?? NULL;
|
||||
if(!$photo || $photo->isDeleted())
|
||||
return NULL;
|
||||
else
|
||||
$photo = $photos[0] ?? null;
|
||||
if (!$photo || $photo->isDeleted()) {
|
||||
return null;
|
||||
} else {
|
||||
return $photo;
|
||||
}
|
||||
|
||||
return (new Photos)->get($cover);
|
||||
}
|
||||
|
||||
function getPhotos(int $page = 1, ?int $perPage = NULL): \Traversable
|
||||
return (new Photos())->get($cover);
|
||||
}
|
||||
|
||||
public function getPhotos(int $page = 1, ?int $perPage = null): \Traversable
|
||||
{
|
||||
return $this->fetch($page, $perPage);
|
||||
}
|
||||
|
||||
function getPhotosCount(): int
|
||||
public function getPhotosCount(): int
|
||||
{
|
||||
return $this->size();
|
||||
}
|
||||
|
||||
function addPhoto(Photo $photo): void
|
||||
public function addPhoto(Photo $photo): void
|
||||
{
|
||||
$this->add($photo);
|
||||
}
|
||||
|
||||
function removePhoto(Photo $photo): void
|
||||
public function removePhoto(Photo $photo): void
|
||||
{
|
||||
$this->remove($photo);
|
||||
}
|
||||
|
||||
function hasPhoto(Photo $photo): bool
|
||||
public function hasPhoto(Photo $photo): bool
|
||||
{
|
||||
return $this->has($photo);
|
||||
}
|
||||
|
||||
function toVkApiStruct(?User $user = NULL, bool $need_covers = false, bool $photo_sizes = false): object
|
||||
public function canBeViewedBy(?User $user = null): bool
|
||||
{
|
||||
if ($this->isDeleted()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$owner = $this->getOwner();
|
||||
|
||||
if (get_class($owner) == "openvk\\Web\\Models\\Entities\\User") {
|
||||
return $owner->canBeViewedBy($user) && $owner->getPrivacyPermission('photos.read', $user);
|
||||
} else {
|
||||
return $owner->canBeViewedBy($user);
|
||||
}
|
||||
}
|
||||
|
||||
public function toVkApiStruct(?User $user = null, bool $need_covers = false, bool $photo_sizes = false): object
|
||||
{
|
||||
$res = (object) [];
|
||||
|
||||
$res->id = $this->getPrettyId();
|
||||
$res->vid = $this->getId();
|
||||
$res->thumb_id = !is_null($this->getCoverPhoto()) ? $this->getCoverPhoto()->getPrettyId() : 0;
|
||||
$res->owner_id = $this->getOwner()->getId();
|
||||
$res->title = $this->getName();
|
||||
$res->description = $this->getDescription();
|
||||
$res->created = $this->getCreationTime()->timestamp();
|
||||
$res->updated = $this->getEditTime() ? $this->getEditTime()->timestamp() : NULL;
|
||||
$res->updated = $this->getEditTime() ? $this->getEditTime()->timestamp() : null;
|
||||
$res->size = $this->size();
|
||||
$res->privacy_comment = 1;
|
||||
$res->upload_by_admins_only = 1;
|
||||
$res->comments_disabled = 0;
|
||||
$res->can_upload = $this->canBeModifiedBy($user); # thisUser недоступен в entities
|
||||
if($need_covers) {
|
||||
if ($need_covers) {
|
||||
$res->thumb_src = $this->getCoverURL();
|
||||
|
||||
if($photo_sizes) {
|
||||
$res->sizes = !is_null($this->getCoverPhoto()) ? $this->getCoverPhoto()->getVkApiSizes() : NULL;
|
||||
if ($photo_sizes) {
|
||||
$res->sizes = !is_null($this->getCoverPhoto()) ? $this->getCoverPhoto()->getVkApiSizes() : null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use openvk\Web\Models\RowModel;
|
||||
|
@ -9,26 +12,27 @@ class Alias extends RowModel
|
|||
{
|
||||
protected $tableName = "aliases";
|
||||
|
||||
function getOwnerId(): int
|
||||
public function getOwnerId(): int
|
||||
{
|
||||
return $this->getRecord()->owner_id;
|
||||
}
|
||||
|
||||
function getType(): string
|
||||
public function getType(): string
|
||||
{
|
||||
if ($this->getOwnerId() < 0)
|
||||
if ($this->getOwnerId() < 0) {
|
||||
return "club";
|
||||
}
|
||||
|
||||
return "user";
|
||||
}
|
||||
|
||||
function getUser(): ?User
|
||||
public function getUser(): ?User
|
||||
{
|
||||
return (new Users)->get($this->getOwnerId());
|
||||
return (new Users())->get($this->getOwnerId());
|
||||
}
|
||||
|
||||
function getClub(): ?Club
|
||||
public function getClub(): ?Club
|
||||
{
|
||||
return (new Clubs)->get($this->getOwnerId() * -1);
|
||||
return (new Clubs())->get($this->getOwnerId() * -1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
use Nette\Utils\Image;
|
||||
use Nette\Utils\UnknownImageFileException;
|
||||
|
@ -11,7 +15,7 @@ class Application extends RowModel
|
|||
{
|
||||
protected $tableName = "apps";
|
||||
|
||||
const PERMS = [
|
||||
public const PERMS = [
|
||||
"notify",
|
||||
"friends",
|
||||
"photos",
|
||||
|
@ -35,40 +39,42 @@ class Application extends RowModel
|
|||
private function getAvatarsDir(): string
|
||||
{
|
||||
$uploadSettings = OPENVK_ROOT_CONF["openvk"]["preferences"]["uploads"];
|
||||
if($uploadSettings["mode"] === "server" && $uploadSettings["server"]["kind"] === "cdn")
|
||||
if ($uploadSettings["mode"] === "server" && $uploadSettings["server"]["kind"] === "cdn") {
|
||||
return $uploadSettings["server"]["directory"];
|
||||
else
|
||||
} else {
|
||||
return OPENVK_ROOT . "/storage/";
|
||||
}
|
||||
}
|
||||
|
||||
function getId(): int
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->getRecord()->id;
|
||||
}
|
||||
|
||||
function getOwner(): User
|
||||
public function getOwner(): User
|
||||
{
|
||||
return (new Users)->get($this->getRecord()->owner);
|
||||
return (new Users())->get($this->getRecord()->owner);
|
||||
}
|
||||
|
||||
function getName(): string
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->getRecord()->name;
|
||||
}
|
||||
|
||||
function getDescription(): string
|
||||
public function getDescription(): string
|
||||
{
|
||||
return $this->getRecord()->description;
|
||||
}
|
||||
|
||||
function getAvatarUrl(): string
|
||||
public function getAvatarUrl(): string
|
||||
{
|
||||
$serverUrl = ovk_scheme(true) . $_SERVER["HTTP_HOST"];
|
||||
if(is_null($this->getRecord()->avatar_hash))
|
||||
if (is_null($this->getRecord()->avatar_hash)) {
|
||||
return "$serverUrl/assets/packages/static/openvk/img/camera_200.png";
|
||||
}
|
||||
|
||||
$hash = $this->getRecord()->avatar_hash;
|
||||
switch(OPENVK_ROOT_CONF["openvk"]["preferences"]["uploads"]["mode"]) {
|
||||
switch (OPENVK_ROOT_CONF["openvk"]["preferences"]["uploads"]["mode"]) {
|
||||
default:
|
||||
case "default":
|
||||
case "basic":
|
||||
|
@ -86,34 +92,36 @@ class Application extends RowModel
|
|||
}
|
||||
}
|
||||
|
||||
function getNote(): ?Note
|
||||
public function getNote(): ?Note
|
||||
{
|
||||
if(!$this->getRecord()->news)
|
||||
return NULL;
|
||||
|
||||
return (new Notes)->get($this->getRecord()->news);
|
||||
if (!$this->getRecord()->news) {
|
||||
return null;
|
||||
}
|
||||
|
||||
function getNoteLink(): string
|
||||
return (new Notes())->get($this->getRecord()->news);
|
||||
}
|
||||
|
||||
public function getNoteLink(): string
|
||||
{
|
||||
$note = $this->getNote();
|
||||
if(!$note)
|
||||
if (!$note) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return ovk_scheme(true) . $_SERVER["HTTP_HOST"] . "/note" . $note->getPrettyId();
|
||||
}
|
||||
|
||||
function getBalance(): float
|
||||
public function getBalance(): float
|
||||
{
|
||||
return $this->getRecord()->coins;
|
||||
}
|
||||
|
||||
function getURL(): string
|
||||
public function getURL(): string
|
||||
{
|
||||
return $this->getRecord()->address;
|
||||
}
|
||||
|
||||
function getOrigin(): string
|
||||
public function getOrigin(): string
|
||||
{
|
||||
$parsed = parse_url($this->getURL());
|
||||
|
||||
|
@ -124,13 +132,13 @@ class Application extends RowModel
|
|||
);
|
||||
}
|
||||
|
||||
function getUsersCount(): int
|
||||
public function getUsersCount(): int
|
||||
{
|
||||
$cx = DatabaseConnection::i()->getContext();
|
||||
return sizeof($cx->table("app_users")->where("app", $this->getId()));
|
||||
}
|
||||
|
||||
function getInstallationEntry(User $user): ?array
|
||||
public function getInstallationEntry(User $user): ?array
|
||||
{
|
||||
$cx = DatabaseConnection::i()->getContext();
|
||||
$entry = $cx->table("app_users")->where([
|
||||
|
@ -138,66 +146,73 @@ class Application extends RowModel
|
|||
"user" => $user->getId(),
|
||||
])->fetch();
|
||||
|
||||
if(!$entry)
|
||||
return NULL;
|
||||
if (!$entry) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $entry->toArray();
|
||||
}
|
||||
|
||||
function getPermissions(User $user): array
|
||||
public function getPermissions(User $user): array
|
||||
{
|
||||
$permMask = 0;
|
||||
$installInfo = $this->getInstallationEntry($user);
|
||||
if(!$installInfo)
|
||||
if (!$installInfo) {
|
||||
$this->install($user);
|
||||
else
|
||||
} else {
|
||||
$permMask = $installInfo["access"];
|
||||
}
|
||||
|
||||
$res = [];
|
||||
for($i = 0; $i < sizeof(self::PERMS); $i++) {
|
||||
for ($i = 0; $i < sizeof(self::PERMS); $i++) {
|
||||
$checkVal = 1 << $i;
|
||||
if(($permMask & $checkVal) > 0)
|
||||
if (($permMask & $checkVal) > 0) {
|
||||
$res[] = self::PERMS[$i];
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
function isInstalledBy(User $user): bool
|
||||
public function isInstalledBy(User $user): bool
|
||||
{
|
||||
return !is_null($this->getInstallationEntry($user));
|
||||
}
|
||||
|
||||
function setNoteLink(?string $link): bool
|
||||
public function setNoteLink(?string $link): bool
|
||||
{
|
||||
if(!$link) {
|
||||
$this->stateChanges("news", NULL);
|
||||
if (!$link) {
|
||||
$this->stateChanges("news", null);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
preg_match("%note([0-9]+)_([0-9]+)$%", $link, $matches);
|
||||
if(sizeof($matches) != 3)
|
||||
if (sizeof($matches) != 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$owner = is_null($this->getRecord()) ? $this->changes["owner"] : $this->getRecord()->owner;
|
||||
[, $ownerId, $vid] = $matches;
|
||||
if($ownerId != $owner)
|
||||
if ($ownerId != $owner) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$note = (new Notes)->getNoteById((int) $ownerId, (int) $vid);
|
||||
if(!$note)
|
||||
$note = (new Notes())->getNoteById((int) $ownerId, (int) $vid);
|
||||
if (!$note) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->stateChanges("news", $note->getId());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function setAvatar(array $file): int
|
||||
public function setAvatar(array $file): int
|
||||
{
|
||||
if($file["error"] !== UPLOAD_ERR_OK)
|
||||
if ($file["error"] !== UPLOAD_ERR_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
try {
|
||||
$image = Image::fromFile($file["tmp_name"]);
|
||||
|
@ -206,9 +221,11 @@ class Application extends RowModel
|
|||
}
|
||||
|
||||
$hash = hash_file("adler32", $file["tmp_name"]);
|
||||
if(!is_dir($this->getAvatarsDir() . substr($hash, 0, 2)))
|
||||
if(!mkdir($this->getAvatarsDir() . substr($hash, 0, 2)))
|
||||
if (!is_dir($this->getAvatarsDir() . substr($hash, 0, 2))) {
|
||||
if (!mkdir($this->getAvatarsDir() . substr($hash, 0, 2))) {
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
|
||||
$image->resize(140, 140, Image::STRETCH);
|
||||
$image->save($this->getAvatarsDir() . substr($hash, 0, 2) . "/$hash" . "_app_avatar.png");
|
||||
|
@ -218,18 +235,20 @@ class Application extends RowModel
|
|||
return 0;
|
||||
}
|
||||
|
||||
function setPermission(User $user, string $perm, bool $enabled): bool
|
||||
public function setPermission(User $user, string $perm, bool $enabled): bool
|
||||
{
|
||||
$permMask = 0;
|
||||
$installInfo = $this->getInstallationEntry($user);
|
||||
if(!$installInfo)
|
||||
if (!$installInfo) {
|
||||
$this->install($user);
|
||||
else
|
||||
} else {
|
||||
$permMask = $installInfo["access"];
|
||||
}
|
||||
|
||||
$index = array_search($perm, self::PERMS);
|
||||
if($index === false)
|
||||
if ($index === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$permVal = 1 << $index;
|
||||
$permMask = $enabled ? ($permMask | $permVal) : ($permMask ^ $permVal);
|
||||
|
@ -245,26 +264,26 @@ class Application extends RowModel
|
|||
return true;
|
||||
}
|
||||
|
||||
function isEnabled(): bool
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->enabled;
|
||||
}
|
||||
|
||||
function enable(): void
|
||||
public function enable(): void
|
||||
{
|
||||
$this->stateChanges("enabled", 1);
|
||||
$this->save();
|
||||
}
|
||||
|
||||
function disable(): void
|
||||
public function disable(): void
|
||||
{
|
||||
$this->stateChanges("enabled", 0);
|
||||
$this->save();
|
||||
}
|
||||
|
||||
function install(User $user): void
|
||||
public function install(User $user): void
|
||||
{
|
||||
if(!$this->getInstallationEntry($user)) {
|
||||
if (!$this->getInstallationEntry($user)) {
|
||||
$cx = DatabaseConnection::i()->getContext();
|
||||
$cx->table("app_users")->insert([
|
||||
"app" => $this->getId(),
|
||||
|
@ -273,7 +292,7 @@ class Application extends RowModel
|
|||
}
|
||||
}
|
||||
|
||||
function uninstall(User $user): void
|
||||
public function uninstall(User $user): void
|
||||
{
|
||||
$cx = DatabaseConnection::i()->getContext();
|
||||
$cx->table("app_users")->where([
|
||||
|
@ -282,7 +301,7 @@ class Application extends RowModel
|
|||
])->delete();
|
||||
}
|
||||
|
||||
function addCoins(float $coins): float
|
||||
public function addCoins(float $coins): float
|
||||
{
|
||||
$res = $this->getBalance() + $coins;
|
||||
$this->stateChanges("coins", $res);
|
||||
|
@ -291,7 +310,7 @@ class Application extends RowModel
|
|||
return $res;
|
||||
}
|
||||
|
||||
function withdrawCoins(): void
|
||||
public function withdrawCoins(): void
|
||||
{
|
||||
$balance = $this->getBalance();
|
||||
$tax = ($balance / 100) * OPENVK_ROOT_CONF["openvk"]["preferences"]["apps"]["withdrawTax"];
|
||||
|
@ -303,14 +322,20 @@ class Application extends RowModel
|
|||
$owner->save();
|
||||
}
|
||||
|
||||
function delete(bool $softly = true): void
|
||||
public function delete(bool $softly = true): void
|
||||
{
|
||||
if($softly)
|
||||
if ($softly) {
|
||||
throw new \UnexpectedValueException("Can't delete apps softly.");
|
||||
} // why
|
||||
|
||||
$cx = DatabaseConnection::i()->getContext();
|
||||
$cx->table("app_users")->where("app", $this->getId())->delete();
|
||||
|
||||
parent::delete(false);
|
||||
}
|
||||
|
||||
public function getPublicationTime(): string
|
||||
{
|
||||
return tr("recently");
|
||||
}
|
||||
}
|
|
@ -1,23 +1,27 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use openvk\Web\Models\RowModel;
|
||||
|
||||
abstract class Attachable extends RowModel
|
||||
{
|
||||
function getId(): int
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->getRecord()->id;
|
||||
}
|
||||
|
||||
function getParents(): \Traversable
|
||||
public function getParents(): \Traversable
|
||||
{
|
||||
$sel = $this->getRecord()
|
||||
->related("attachments.attachable_id")
|
||||
->where("attachments.attachable_type", get_class($this));
|
||||
foreach($sel as $rel) {
|
||||
foreach ($sel as $rel) {
|
||||
$repoName = $rel->target_type . "s";
|
||||
$repoName = str_replace("Entities", "Repositories", $repoName);
|
||||
$repo = new $repoName;
|
||||
$repo = new $repoName();
|
||||
|
||||
yield $repo->get($rel->target_id);
|
||||
}
|
||||
|
@ -26,7 +30,7 @@ abstract class Attachable extends RowModel
|
|||
/**
|
||||
* Deletes together with all references.
|
||||
*/
|
||||
function delete(bool $softly = true): void
|
||||
public function delete(bool $softly = true): void
|
||||
{
|
||||
$this->getRecord()
|
||||
->related("attachments.attachable_id")
|
||||
|
|
508
Web/Models/Entities/Audio.php
Normal file
508
Web/Models/Entities/Audio.php
Normal file
|
@ -0,0 +1,508 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
use openvk\Web\Util\Shell\Exceptions\UnknownCommandException;
|
||||
use openvk\Web\Util\Shell\Shell;
|
||||
|
||||
/**
|
||||
* @method setName(string)
|
||||
* @method setPerformer(string)
|
||||
* @method setLyrics(string)
|
||||
* @method setExplicit(bool)
|
||||
*/
|
||||
class Audio extends Media
|
||||
{
|
||||
protected $tableName = "audios";
|
||||
protected $fileExtension = "mpd";
|
||||
|
||||
# Taken from winamp :D
|
||||
public const genres = [
|
||||
'A Cappella', 'Abstract', 'Acid', 'Acid Jazz', 'Acid Punk', 'Acoustic', 'AlternRock', 'Alternative', 'Ambient', 'Anime', 'Art Rock', 'Audio Theatre', 'Audiobook', 'Avantgarde', 'Ballad', 'Baroque', 'Bass', 'Beat', 'Bebob', 'Bhangra', 'Big Band', 'Big Beat', 'Black Metal', 'Bluegrass', 'Blues', 'Booty Bass', 'Breakbeat', 'BritPop', 'Cabaret', 'Celtic', 'Chamber Music', 'Chanson', 'Chillout', 'Chorus', 'Christian Gangsta Rap', 'Christian Rap', 'Christian Rock', 'Classic Rock', 'Classical', 'Club', 'Club-House', 'Comedy', 'Contemporary Christian', 'Country', 'Crossover', 'Cult', 'Dance', 'Dance Hall', 'Darkwave', 'Death Metal', 'Disco', 'Downtempo', 'Dream', 'Drum & Bass', 'Drum Solo', 'Dub', 'Dubstep', 'Duet', 'EBM', 'Easy Listening', 'Eclectic', 'Electro', 'Electroclash', 'Electronic', 'Emo', 'Ethnic', 'Euro-House', 'Euro-Techno', 'Eurodance', 'Experimental', 'Fast Fusion', 'Folk', 'Folk-Rock', 'Folklore', 'Freestyle', 'Funk', 'Fusion', 'G-Funk', 'Game', 'Gangsta Rap', 'Garage', 'Garage Rock', 'Global', 'Goa', 'Gospel', 'Gothic', 'Gothic Rock', 'Grunge', 'Hard Rock', 'Hardcore', 'Heavy Metal', 'Hip-Hop', 'House', 'Humour', 'IDM', 'Illbient', 'Indie', 'Indie Rock', 'Industrial', 'Industro-Goth', 'Instrumental', 'Instrumental Pop', 'Instrumental Rock', 'JPop', 'Jam Band', 'Jazz', 'Jazz+Funk', 'Jungle', 'Krautrock', 'Latin', 'Leftfield', 'Lo-Fi', 'Lounge', 'Math Rock', 'Meditative', 'Merengue', 'Metal', 'Musical', 'National Folk', 'Native American', 'Negerpunk', 'Neoclassical', 'Neue Deutsche Welle', 'New Age', 'New Romantic', 'New Wave', 'Noise', 'Nu-Breakz', 'Oldies', 'Opera', 'Other', 'Podcast', 'Polka', 'Polsk Punk', 'Pop', 'Pop / Funk', 'Pop-Folk', 'Porn Groove', 'Post-Punk', 'Post-Rock', 'Power Ballad', 'Pranks', 'Primus', 'Progressive Rock', 'Psybient', 'Psychedelic', 'Psychedelic Rock', 'Psychobilly', 'Psytrance', 'Punk', 'Punk Rock', 'R&B', 'Rap', 'Rave', 'Reggae', 'Retro', 'Revival', 'Rhythmic Soul', 'Rock', 'Rock & Roll', 'Salsa', 'Samba', 'Satire', 'Shoegaze', 'Showtunes', 'Ska', 'Slow Jam', 'Slow Rock', 'Sonata', 'Soul', 'Sound Clip', 'Soundtrack', 'Southern Rock', 'Space', 'Space Rock', 'Speech', 'Swing', 'Symphonic Rock', 'Symphony', 'Synthpop', 'Tango', 'Techno', 'Techno-Industrial', 'Terror', 'Thrash Metal', 'Top 40', 'Touhou', 'Trailer', 'Trance', 'Tribal', 'Trip-Hop', 'Trop Rock', 'Vocal', 'World Music',
|
||||
];
|
||||
|
||||
# Taken from: https://web.archive.org/web/20220322153107/https://dev.vk.com/reference/objects/audio-genres
|
||||
public const vkGenres = [
|
||||
"Rock" => 1,
|
||||
"Pop" => 2,
|
||||
"Rap" => 3,
|
||||
"Hip-Hop" => 3, # VK API lists №3 as Rap & Hip-Hop, but these genres are distinct in OpenVK
|
||||
"Easy Listening" => 4,
|
||||
"House" => 5,
|
||||
"Dance" => 5,
|
||||
"Instrumental" => 6,
|
||||
"Metal" => 7,
|
||||
"Alternative" => 21,
|
||||
"Dubstep" => 8,
|
||||
"Jazz" => 1001,
|
||||
"Blues" => 1001,
|
||||
"Drum & Bass" => 10,
|
||||
"Trance" => 11,
|
||||
"Chanson" => 12,
|
||||
"Ethnic" => 13,
|
||||
"Acoustic" => 14,
|
||||
"Vocal" => 14,
|
||||
"Reggae" => 15,
|
||||
"Classical" => 16,
|
||||
"Indie Pop" => 17,
|
||||
"Speech" => 19,
|
||||
"Disco" => 22,
|
||||
"Other" => 18,
|
||||
];
|
||||
|
||||
private function fileLength(string $filename): int
|
||||
{
|
||||
if (!Shell::commandAvailable("ffmpeg") || !Shell::commandAvailable("ffprobe")) {
|
||||
throw new \Exception();
|
||||
}
|
||||
|
||||
$error = null;
|
||||
$streams = Shell::ffprobe("-i", $filename, "-show_streams", "-select_streams a", "-loglevel error")->execute($error);
|
||||
if ($error !== 0) {
|
||||
throw new \DomainException("$filename is not recognized as media container");
|
||||
} elseif (empty($streams) || ctype_space($streams)) {
|
||||
throw new \DomainException("$filename does not contain any audio streams");
|
||||
}
|
||||
|
||||
$vstreams = Shell::ffprobe("-i", $filename, "-show_streams", "-select_streams v", "-loglevel error")->execute($error);
|
||||
|
||||
# check if audio has cover (attached_pic)
|
||||
preg_match("%attached_pic=([0-1])%", $vstreams, $hasCover);
|
||||
if (!empty($vstreams) && !ctype_space($vstreams) && ((int) ($hasCover[1]) !== 1)) {
|
||||
throw new \DomainException("$filename is a video");
|
||||
}
|
||||
|
||||
$durations = [];
|
||||
preg_match_all('%duration=([0-9\.]++)%', $streams, $durations);
|
||||
if (sizeof($durations[1]) === 0) {
|
||||
throw new \DomainException("$filename does not contain any meaningful audio streams");
|
||||
}
|
||||
|
||||
$length = 0;
|
||||
foreach ($durations[1] as $duration) {
|
||||
$duration = floatval($duration);
|
||||
if ($duration < 1.0 || $duration > 65536.0) {
|
||||
throw new \DomainException("$filename does not contain any meaningful audio streams");
|
||||
} else {
|
||||
$length = max($length, $duration);
|
||||
}
|
||||
}
|
||||
|
||||
return (int) round($length, 0, PHP_ROUND_HALF_EVEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function saveFile(string $filename, string $hash): bool
|
||||
{
|
||||
$duration = $this->fileLength($filename);
|
||||
|
||||
$kid = openssl_random_pseudo_bytes(16);
|
||||
$key = openssl_random_pseudo_bytes(16);
|
||||
$tok = openssl_random_pseudo_bytes(28);
|
||||
$ss = ceil($duration / 15);
|
||||
|
||||
$this->stateChanges("kid", $kid);
|
||||
$this->stateChanges("key", $key);
|
||||
$this->stateChanges("token", $tok);
|
||||
$this->stateChanges("segment_size", $ss);
|
||||
$this->stateChanges("length", $duration);
|
||||
|
||||
try {
|
||||
$args = [
|
||||
str_replace("enabled", "available", OPENVK_ROOT),
|
||||
str_replace("enabled", "available", $this->getBaseDir()),
|
||||
$hash,
|
||||
$filename,
|
||||
|
||||
bin2hex($kid),
|
||||
bin2hex($key),
|
||||
bin2hex($tok),
|
||||
$ss,
|
||||
];
|
||||
|
||||
if (Shell::isPowershell()) {
|
||||
Shell::powershell("-executionpolicy bypass", "-File", __DIR__ . "/../shell/processAudio.ps1", ...$args)
|
||||
->start();
|
||||
} else {
|
||||
Shell::bash(__DIR__ . "/../shell/processAudio.sh", ...$args) // Pls workkkkk
|
||||
->start(); // idk, not tested :")
|
||||
}
|
||||
|
||||
# Wait until processAudio will consume the file
|
||||
$start = time();
|
||||
while (file_exists($filename)) {
|
||||
if (time() - $start > 5) {
|
||||
throw new \RuntimeException("Timed out waiting FFMPEG");
|
||||
}
|
||||
}
|
||||
|
||||
} catch (UnknownCommandException $ucex) {
|
||||
exit(OPENVK_ROOT_CONF["openvk"]["debug"] ? "bash/pwsh is not installed" : VIDEOS_FRIENDLY_ERROR);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->getRecord()->name;
|
||||
}
|
||||
|
||||
public function getPerformer(): string
|
||||
{
|
||||
return $this->getRecord()->performer;
|
||||
}
|
||||
|
||||
public function getPerformers(): array
|
||||
{
|
||||
return explode(", ", $this->getRecord()->performer);
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->getPerformer() . " — " . $this->getTitle();
|
||||
}
|
||||
|
||||
public function getDownloadName(): string
|
||||
{
|
||||
return preg_replace('/[\\/:*?"<>|]/', '_', str_replace(' ', '_', $this->getName()));
|
||||
}
|
||||
|
||||
public function getGenre(): ?string
|
||||
{
|
||||
return $this->getRecord()->genre;
|
||||
}
|
||||
|
||||
public function getLyrics(): ?string
|
||||
{
|
||||
return !is_null($this->getRecord()->lyrics) ? htmlspecialchars($this->getRecord()->lyrics, ENT_DISALLOWED | ENT_XHTML) : null;
|
||||
}
|
||||
|
||||
public function getLength(): int
|
||||
{
|
||||
return $this->getRecord()->length;
|
||||
}
|
||||
|
||||
public function getFormattedLength(): string
|
||||
{
|
||||
$len = $this->getLength();
|
||||
$mins = floor($len / 60);
|
||||
$secs = $len - ($mins * 60);
|
||||
|
||||
return (
|
||||
str_pad((string) $mins, 2, "0", STR_PAD_LEFT)
|
||||
. ":" .
|
||||
str_pad((string) $secs, 2, "0", STR_PAD_LEFT)
|
||||
);
|
||||
}
|
||||
|
||||
public function getSegmentSize(): float
|
||||
{
|
||||
return $this->getRecord()->segment_size;
|
||||
}
|
||||
|
||||
public function getListens(): int
|
||||
{
|
||||
return $this->getRecord()->listens;
|
||||
}
|
||||
|
||||
public function getOriginalURL(bool $force = false): string
|
||||
{
|
||||
$disallowed = !OPENVK_ROOT_CONF["openvk"]["preferences"]["music"]["exposeOriginalURLs"] && !$force;
|
||||
if (!$this->isAvailable() || $disallowed) {
|
||||
return ovk_scheme(true)
|
||||
. $_SERVER["HTTP_HOST"] . ":"
|
||||
. $_SERVER["HTTP_PORT"]
|
||||
. "/assets/packages/static/openvk/audio/nomusic.mp3";
|
||||
}
|
||||
|
||||
$key = bin2hex($this->getRecord()->token);
|
||||
|
||||
return str_replace(".mpd", "_fragments", $this->getURL()) . "/original_$key.mp3";
|
||||
}
|
||||
|
||||
public function getURL(?bool $force = false): string
|
||||
{
|
||||
if ($this->isWithdrawn()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return parent::getURL();
|
||||
}
|
||||
|
||||
public function getKeys(): array
|
||||
{
|
||||
$keys[bin2hex($this->getRecord()->kid)] = bin2hex($this->getRecord()->key);
|
||||
|
||||
return $keys;
|
||||
}
|
||||
|
||||
public function isAnonymous(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isExplicit(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->explicit;
|
||||
}
|
||||
|
||||
public function isWithdrawn(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->withdrawn;
|
||||
}
|
||||
|
||||
public function isUnlisted(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->unlisted;
|
||||
}
|
||||
|
||||
# NOTICE may flush model to DB if it was just processed
|
||||
public function isAvailable(): bool
|
||||
{
|
||||
if ($this->getRecord()->processed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
# throttle requests to isAvailable to prevent DoS attack if filesystem is actually an S3 storage
|
||||
if (time() - $this->getRecord()->checked < 5) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$fragments = str_replace(".mpd", "_fragments", $this->getFileName());
|
||||
$original = "original_" . bin2hex($this->getRecord()->token) . ".mp3";
|
||||
if (file_exists("$fragments/$original")) {
|
||||
# Original gets uploaded after fragments
|
||||
$this->stateChanges("processed", 0x01);
|
||||
|
||||
return true;
|
||||
}
|
||||
} finally {
|
||||
$this->stateChanges("checked", time());
|
||||
$this->save();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isInLibraryOf($entity): bool
|
||||
{
|
||||
return sizeof(DatabaseConnection::i()->getContext()->table("audio_relations")->where([
|
||||
"entity" => $entity->getId() * ($entity instanceof Club ? -1 : 1),
|
||||
"audio" => $this->getId(),
|
||||
])) != 0;
|
||||
}
|
||||
|
||||
public function add($entity): bool
|
||||
{
|
||||
if ($this->isInLibraryOf($entity)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$entityId = $entity->getId() * ($entity instanceof Club ? -1 : 1);
|
||||
$audioRels = DatabaseConnection::i()->getContext()->table("audio_relations");
|
||||
if (sizeof($audioRels->where("entity", $entityId)) > 65536) {
|
||||
throw new \OverflowException("Can't have more than 65536 audios in a playlist");
|
||||
}
|
||||
|
||||
$audioRels->insert([
|
||||
"entity" => $entityId,
|
||||
"audio" => $this->getId(),
|
||||
]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function remove($entity): bool
|
||||
{
|
||||
if (!$this->isInLibraryOf($entity)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DatabaseConnection::i()->getContext()->table("audio_relations")->where([
|
||||
"entity" => $entity->getId() * ($entity instanceof Club ? -1 : 1),
|
||||
"audio" => $this->getId(),
|
||||
])->delete();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function listen($entity, Playlist $playlist = null): bool
|
||||
{
|
||||
$listensTable = DatabaseConnection::i()->getContext()->table("audio_listens");
|
||||
$lastListen = $listensTable->where([
|
||||
"entity" => $entity->getRealId(),
|
||||
"audio" => $this->getId(),
|
||||
])->order("index DESC")->fetch();
|
||||
|
||||
if (!$lastListen || (time() - $lastListen->time >= $this->getLength())) {
|
||||
$listensTable->insert([
|
||||
"entity" => $entity->getRealId(),
|
||||
"audio" => $this->getId(),
|
||||
"time" => time(),
|
||||
"playlist" => $playlist ? $playlist->getId() : null,
|
||||
]);
|
||||
|
||||
if ($entity instanceof User) {
|
||||
$this->stateChanges("listens", ($this->getListens() + 1));
|
||||
$this->save();
|
||||
|
||||
if ($playlist) {
|
||||
$playlist->incrementListens();
|
||||
$playlist->save();
|
||||
}
|
||||
}
|
||||
|
||||
$entity->setLast_played_track($this->getId());
|
||||
$entity->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$lastListen->update([
|
||||
"time" => time(),
|
||||
]);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns compatible with VK API 4.x, 5.x structure.
|
||||
*
|
||||
* Always sets album(_id) to NULL at this time.
|
||||
* If genre is not present in VK genre list, fallbacks to "Other".
|
||||
* The url and manifest properties will be set to false if the audio can't be played (processing, removed).
|
||||
*
|
||||
* Aside from standard VK properties, this method will also return some OVK extended props:
|
||||
* 1. added - Is in the library of $user?
|
||||
* 2. editable - Can be edited by $user?
|
||||
* 3. withdrawn - Removed due to copyright request?
|
||||
* 4. ready - Can be played at this time?
|
||||
* 5. genre_str - Full name of genre, NULL if it's undefined
|
||||
* 6. manifest - URL to MPEG-DASH manifest
|
||||
* 7. keys - ClearKey DRM keys
|
||||
* 8. explicit - Marked as NSFW?
|
||||
* 9. searchable - Can be found via search?
|
||||
* 10. unique_id - Unique ID of audio
|
||||
*
|
||||
* @notice that in case if exposeOriginalURLs is set to false in config, "url" will always contain link to nomusic.mp3,
|
||||
* unless $forceURLExposure is set to true.
|
||||
*
|
||||
* @notice may trigger db flush if the audio is not processed yet, use with caution on unsaved models.
|
||||
*
|
||||
* @param ?User $user user, relative to whom "added", "editable" will be set
|
||||
* @param bool $forceURLExposure force set "url" regardless of config
|
||||
*/
|
||||
public function toVkApiStruct(?User $user = null, bool $forceURLExposure = false): object
|
||||
{
|
||||
$obj = (object) [];
|
||||
$obj->unique_id = base64_encode((string) $this->getId());
|
||||
$obj->id = $obj->aid = $this->getVirtualId();
|
||||
$obj->artist = $this->getPerformer();
|
||||
$obj->title = $this->getTitle();
|
||||
$obj->duration = $this->getLength();
|
||||
$obj->album_id = $obj->album = null; # i forgor to implement
|
||||
$obj->url = false;
|
||||
$obj->manifest = false;
|
||||
$obj->keys = false;
|
||||
$obj->genre_id = $obj->genre = self::vkGenres[$this->getGenre() ?? ""] ?? 18; # return Other if no match
|
||||
$obj->genre_str = $this->getGenre();
|
||||
$obj->owner_id = $this->getOwner()->getId();
|
||||
if ($this->getOwner() instanceof Club) {
|
||||
$obj->owner_id *= -1;
|
||||
}
|
||||
|
||||
$obj->lyrics = null;
|
||||
if (!is_null($this->getLyrics())) {
|
||||
$obj->lyrics = $this->getId();
|
||||
}
|
||||
|
||||
$obj->added = $user && $this->isInLibraryOf($user);
|
||||
$obj->editable = $user && $this->canBeModifiedBy($user);
|
||||
$obj->searchable = !$this->isUnlisted();
|
||||
$obj->explicit = $this->isExplicit();
|
||||
$obj->withdrawn = $this->isWithdrawn();
|
||||
$obj->ready = $this->isAvailable() && !$obj->withdrawn;
|
||||
if ($obj->ready) {
|
||||
$obj->url = $this->getOriginalURL($forceURLExposure);
|
||||
$obj->manifest = $this->getURL();
|
||||
$obj->keys = $this->getKeys();
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
public function setOwner(int $oid): void
|
||||
{
|
||||
# WARNING: API implementation won't be able to handle groups like that, don't remove
|
||||
if ($oid <= 0) {
|
||||
throw new \OutOfRangeException("Only users can be owners of audio!");
|
||||
}
|
||||
|
||||
$this->stateChanges("owner", $oid);
|
||||
}
|
||||
|
||||
public function setGenre(string $genre): void
|
||||
{
|
||||
if (!in_array($genre, Audio::genres)) {
|
||||
$this->stateChanges("genre", null);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->stateChanges("genre", $genre);
|
||||
}
|
||||
|
||||
public function setCopyrightStatus(bool $withdrawn = true): void
|
||||
{
|
||||
$this->stateChanges("withdrawn", $withdrawn);
|
||||
}
|
||||
|
||||
public function setSearchability(bool $searchable = true): void
|
||||
{
|
||||
$this->stateChanges("unlisted", !$searchable);
|
||||
}
|
||||
|
||||
public function setToken(string $tok): void
|
||||
{
|
||||
throw new \LogicException("Changing keys is not supported.");
|
||||
}
|
||||
|
||||
public function setKid(string $kid): void
|
||||
{
|
||||
throw new \LogicException("Changing keys is not supported.");
|
||||
}
|
||||
|
||||
public function setKey(string $key): void
|
||||
{
|
||||
throw new \LogicException("Changing keys is not supported.");
|
||||
}
|
||||
|
||||
public function setLength(int $len): void
|
||||
{
|
||||
throw new \LogicException("Changing length is not supported.");
|
||||
}
|
||||
|
||||
public function setSegment_Size(int $len): void
|
||||
{
|
||||
throw new \LogicException("Changing length is not supported.");
|
||||
}
|
||||
|
||||
public function delete(bool $softly = true): void
|
||||
{
|
||||
$ctx = DatabaseConnection::i()->getContext();
|
||||
$ctx->table("audio_relations")->where("audio", $this->getId())
|
||||
->delete();
|
||||
$ctx->table("audio_listens")->where("audio", $this->getId())
|
||||
->delete();
|
||||
$ctx->table("playlist_relations")->where("media", $this->getId())
|
||||
->delete();
|
||||
|
||||
parent::delete($softly);
|
||||
}
|
||||
}
|
70
Web/Models/Entities/Ban.php
Normal file
70
Web/Models/Entities/Ban.php
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use openvk\Web\Models\RowModel;
|
||||
use openvk\Web\Util\DateTime;
|
||||
use openvk\Web\Models\Repositories\{Users};
|
||||
use Nette\Database\Table\ActiveRow;
|
||||
|
||||
class Ban extends RowModel
|
||||
{
|
||||
protected $tableName = "bans";
|
||||
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->getRecord()->id;
|
||||
}
|
||||
|
||||
public function getReason(): ?string
|
||||
{
|
||||
return $this->getRecord()->reason;
|
||||
}
|
||||
|
||||
public function getUser(): ?User
|
||||
{
|
||||
return (new Users())->get($this->getRecord()->user);
|
||||
}
|
||||
|
||||
public function getInitiator(): ?User
|
||||
{
|
||||
return (new Users())->get($this->getRecord()->initiator);
|
||||
}
|
||||
|
||||
public function getStartTime(): int
|
||||
{
|
||||
return $this->getRecord()->iat;
|
||||
}
|
||||
|
||||
public function getEndTime(): int
|
||||
{
|
||||
return $this->getRecord()->exp;
|
||||
}
|
||||
|
||||
public function getTime(): int
|
||||
{
|
||||
return $this->getRecord()->time;
|
||||
}
|
||||
|
||||
public function isPermanent(): bool
|
||||
{
|
||||
return $this->getEndTime() === 0;
|
||||
}
|
||||
|
||||
public function isRemovedManually(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->removed_manually;
|
||||
}
|
||||
|
||||
public function isOver(): bool
|
||||
{
|
||||
return $this->isRemovedManually();
|
||||
}
|
||||
|
||||
public function whoRemoved(): ?User
|
||||
{
|
||||
return (new Users())->get($this->getRecord()->removed_by);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use openvk\Web\Models\RowModel;
|
||||
use openvk\Web\Models\Entities\{User};
|
||||
use openvk\Web\Models\Repositories\{Users};
|
||||
|
@ -10,39 +14,39 @@ class BannedLink extends RowModel
|
|||
protected $tableName = "links_banned";
|
||||
private $overrideContentColumn = "reason";
|
||||
|
||||
function getId(): int
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->getRecord()->id;
|
||||
}
|
||||
|
||||
function getDomain(): string
|
||||
public function getDomain(): string
|
||||
{
|
||||
return $this->getRecord()->domain;
|
||||
}
|
||||
|
||||
function getReason(): string
|
||||
public function getReason(): string
|
||||
{
|
||||
return $this->getRecord()->reason ?? tr("url_is_banned_default_reason");
|
||||
}
|
||||
|
||||
function getInitiator(): ?User
|
||||
public function getInitiator(): ?User
|
||||
{
|
||||
return (new Users)->get($this->getRecord()->initiator);
|
||||
return (new Users())->get($this->getRecord()->initiator);
|
||||
}
|
||||
|
||||
function getComment(): string
|
||||
public function getComment(): string
|
||||
{
|
||||
return OPENVK_ROOT_CONF["openvk"]["preferences"]["susLinks"]["showReason"]
|
||||
? tr("url_is_banned_comment_r", OPENVK_ROOT_CONF["openvk"]["appearance"]["name"], $this->getReason())
|
||||
: tr("url_is_banned_comment", OPENVK_ROOT_CONF["openvk"]["appearance"]["name"]);
|
||||
}
|
||||
|
||||
function getRegexpRule(): string
|
||||
public function getRegexpRule(): string
|
||||
{
|
||||
return "/^" . $this->getDomain() . "\/" . $this->getRawRegexp() . "$/i";
|
||||
}
|
||||
|
||||
function getRawRegexp(): string
|
||||
public function getRawRegexp(): string
|
||||
{
|
||||
return $this->getRecord()->regexp_rule;
|
||||
}
|
||||
|
|
|
@ -1,206 +1,249 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use openvk\Web\Util\DateTime;
|
||||
use openvk\Web\Models\RowModel;
|
||||
use openvk\Web\Models\Entities\{User, Manager};
|
||||
use openvk\Web\Models\Repositories\{Users, Clubs, Albums, Managers};
|
||||
use openvk\Web\Models\Repositories\{Users, Clubs, Albums, Managers, Posts};
|
||||
use Nette\Database\Table\{ActiveRow, GroupedSelection};
|
||||
use Chandler\Database\DatabaseConnection as DB;
|
||||
use Chandler\Security\User as ChandlerUser;
|
||||
|
||||
class Club extends RowModel
|
||||
{
|
||||
use Traits\TBackDrops;
|
||||
use Traits\TSubscribable;
|
||||
use Traits\TAudioStatuses;
|
||||
use Traits\TIgnorable;
|
||||
protected $tableName = "groups";
|
||||
|
||||
const TYPE_GROUP = 1;
|
||||
const TYPE_PUBLIC = 1;
|
||||
const TYPE_EVENT = 2;
|
||||
public const TYPE_GROUP = 1;
|
||||
public const TYPE_PUBLIC = 1;
|
||||
public const TYPE_EVENT = 2;
|
||||
|
||||
const OPEN = 0;
|
||||
const CLOSED = 1;
|
||||
const PRIVATE = 2;
|
||||
public const OPEN = 0;
|
||||
public const CLOSED = 1;
|
||||
public const PRIVATE = 2;
|
||||
|
||||
const NOT_RELATED = 0;
|
||||
const SUBSCRIBED = 1;
|
||||
const REQUEST_SENT = 2;
|
||||
public const NOT_RELATED = 0;
|
||||
public const SUBSCRIBED = 1;
|
||||
public const REQUEST_SENT = 2;
|
||||
|
||||
function getId(): int
|
||||
public const WALL_CLOSED = 0;
|
||||
public const WALL_OPEN = 1;
|
||||
public const WALL_LIMITED = 2;
|
||||
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->getRecord()->id;
|
||||
}
|
||||
|
||||
function getAvatarPhoto(): ?Photo
|
||||
public function getAvatarPhoto(): ?Photo
|
||||
{
|
||||
$avAlbum = (new Albums)->getClubAvatarAlbum($this);
|
||||
$avAlbum = (new Albums())->getClubAvatarAlbum($this);
|
||||
$avCount = $avAlbum->getPhotosCount();
|
||||
$avPhotos = $avAlbum->getPhotos($avCount, 1);
|
||||
|
||||
return iterator_to_array($avPhotos)[0] ?? NULL;
|
||||
return iterator_to_array($avPhotos)[0] ?? null;
|
||||
}
|
||||
|
||||
function getAvatarUrl(string $size = "miniscule"): string
|
||||
public function getAvatarUrl(string $size = "miniscule", $avPhoto = null): string
|
||||
{
|
||||
$serverUrl = ovk_scheme(true) . $_SERVER["HTTP_HOST"];
|
||||
if (!$avPhoto) {
|
||||
$avPhoto = $this->getAvatarPhoto();
|
||||
}
|
||||
|
||||
return is_null($avPhoto) ? "$serverUrl/assets/packages/static/openvk/img/camera_200.png" : $avPhoto->getURLBySizeId($size);
|
||||
}
|
||||
|
||||
function getAvatarLink(): string
|
||||
public function getWallType(): int
|
||||
{
|
||||
return $this->getRecord()->wall;
|
||||
}
|
||||
|
||||
public function getAvatarLink(): string
|
||||
{
|
||||
$avPhoto = $this->getAvatarPhoto();
|
||||
if(!$avPhoto) return "javascript:void(0)";
|
||||
if (!$avPhoto) {
|
||||
return "javascript:void(0)";
|
||||
}
|
||||
|
||||
$pid = $avPhoto->getPrettyId();
|
||||
$aid = (new Albums)->getClubAvatarAlbum($this)->getId();
|
||||
$aid = (new Albums())->getClubAvatarAlbum($this)->getId();
|
||||
|
||||
return "/photo$pid?from=album$aid";
|
||||
}
|
||||
|
||||
function getURL(): string
|
||||
public function getURL(): string
|
||||
{
|
||||
if(!is_null($this->getShortCode()))
|
||||
if (!is_null($this->getShortCode())) {
|
||||
return "/" . $this->getShortCode();
|
||||
else
|
||||
} else {
|
||||
return "/club" . $this->getId();
|
||||
}
|
||||
}
|
||||
|
||||
function getName(): string
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->getRecord()->name;
|
||||
}
|
||||
|
||||
function getCanonicalName(): string
|
||||
public function getCanonicalName(): string
|
||||
{
|
||||
return $this->getName();
|
||||
}
|
||||
|
||||
function getOwner(): ?User
|
||||
public function getOwner(): ?User
|
||||
{
|
||||
return (new Users)->get($this->getRecord()->owner);
|
||||
return (new Users())->get($this->getRecord()->owner);
|
||||
}
|
||||
|
||||
function getOwnerComment(): string
|
||||
public function getOwnerComment(): string
|
||||
{
|
||||
return is_null($this->getRecord()->owner_comment) ? "" : $this->getRecord()->owner_comment;
|
||||
}
|
||||
|
||||
function isOwnerHidden(): bool
|
||||
public function isOwnerHidden(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->owner_hidden;
|
||||
}
|
||||
|
||||
function isOwnerClubPinned(): bool
|
||||
public function isOwnerClubPinned(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->owner_club_pinned;
|
||||
}
|
||||
|
||||
function getDescription(): ?string
|
||||
public function getDescription(): ?string
|
||||
{
|
||||
return $this->getRecord()->about;
|
||||
}
|
||||
|
||||
function getDescriptionHtml(): ?string
|
||||
public function getDescriptionHtml(): ?string
|
||||
{
|
||||
if(!is_null($this->getDescription()))
|
||||
if (!is_null($this->getDescription())) {
|
||||
return nl2br(htmlspecialchars($this->getDescription(), ENT_DISALLOWED | ENT_XHTML));
|
||||
else
|
||||
return NULL;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function getShortCode(): ?string
|
||||
public function getShortCode(): ?string
|
||||
{
|
||||
return $this->getRecord()->shortcode;
|
||||
}
|
||||
|
||||
function getBanReason(): ?string
|
||||
public function getBanReason(): ?string
|
||||
{
|
||||
return $this->getRecord()->block_reason;
|
||||
}
|
||||
|
||||
function getOpennesStatus(): int
|
||||
public function getOpennesStatus(): int
|
||||
{
|
||||
return $this->getRecord()->closed;
|
||||
}
|
||||
|
||||
function getAdministratorsListDisplay(): int
|
||||
public function getAdministratorsListDisplay(): int
|
||||
{
|
||||
return $this->getRecord()->administrators_list_display;
|
||||
}
|
||||
|
||||
function isEveryoneCanCreateTopics(): bool
|
||||
public function isEveryoneCanCreateTopics(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->everyone_can_create_topics;
|
||||
}
|
||||
|
||||
function isDisplayTopicsAboveWallEnabled(): bool
|
||||
public function isDisplayTopicsAboveWallEnabled(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->display_topics_above_wall;
|
||||
}
|
||||
|
||||
function isHideFromGlobalFeedEnabled(): bool
|
||||
public function isHideFromGlobalFeedEnabled(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->hide_from_global_feed;
|
||||
}
|
||||
|
||||
function getType(): int
|
||||
public function isHidingFromGlobalFeedEnforced(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->enforce_hiding_from_global_feed;
|
||||
}
|
||||
|
||||
public function getType(): int
|
||||
{
|
||||
return $this->getRecord()->type;
|
||||
}
|
||||
|
||||
function isVerified(): bool
|
||||
public function isVerified(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->verified;
|
||||
}
|
||||
|
||||
function isBanned(): bool
|
||||
public function isBanned(): bool
|
||||
{
|
||||
return !is_null($this->getBanReason());
|
||||
}
|
||||
|
||||
function canPost(): bool
|
||||
public function canPost(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->wall;
|
||||
}
|
||||
|
||||
|
||||
function setShortCode(?string $code = NULL): ?bool
|
||||
public function setShortCode(?string $code = null): ?bool
|
||||
{
|
||||
if(!is_null($code)) {
|
||||
if(!preg_match("%^[a-z][a-z0-9\\.\\_]{0,30}[a-z0-9]$%", $code))
|
||||
if (!is_null($code)) {
|
||||
if (!preg_match("%^[a-z][a-z0-9\\.\\_]{0,30}[a-z0-9]$%", $code)) {
|
||||
return false;
|
||||
if(in_array($code, OPENVK_ROOT_CONF["openvk"]["preferences"]["shortcodes"]["forbiddenNames"]))
|
||||
}
|
||||
if (in_array($code, OPENVK_ROOT_CONF["openvk"]["preferences"]["shortcodes"]["forbiddenNames"])) {
|
||||
return false;
|
||||
if(\Chandler\MVC\Routing\Router::i()->getMatchingRoute("/$code")[0]->presenter !== "UnknownTextRouteStrategy")
|
||||
}
|
||||
if (\Chandler\MVC\Routing\Router::i()->getMatchingRoute("/$code")[0]->presenter !== "UnknownTextRouteStrategy") {
|
||||
return false;
|
||||
}
|
||||
|
||||
$pUser = DB::i()->getContext()->table("profiles")->where("shortcode", $code)->fetch();
|
||||
if(!is_null($pUser))
|
||||
if (!is_null($pUser)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->stateChanges("shortcode", $code);
|
||||
return true;
|
||||
}
|
||||
|
||||
function isSubscriptionAccepted(User $user): bool
|
||||
public function setWall(int $type)
|
||||
{
|
||||
if ($type > 2 || $type < 0) {
|
||||
throw new \LogicException("Invalid wall");
|
||||
}
|
||||
|
||||
$this->stateChanges("wall", $type);
|
||||
}
|
||||
|
||||
public function isSubscriptionAccepted(User $user): bool
|
||||
{
|
||||
return !is_null($this->getRecord()->related("subscriptions.follower")->where([
|
||||
"follower" => $this->getId(),
|
||||
"target" => $user->getId(),
|
||||
])->fetch());;
|
||||
])->fetch());
|
||||
;
|
||||
}
|
||||
|
||||
function getPostViewStats(bool $unique = false): ?array
|
||||
public function getPostViewStats(bool $unique = false): ?array
|
||||
{
|
||||
$edb = eventdb();
|
||||
if(!$edb)
|
||||
return NULL;
|
||||
if (!$edb) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$subs = [];
|
||||
$viral = [];
|
||||
$total = [];
|
||||
for($i = 1; $i < 8; $i++) {
|
||||
for ($i = 1; $i < 8; $i++) {
|
||||
$begin = strtotime("-" . $i . "day midnight");
|
||||
$end = $i === 1 ? time() + 10 : strtotime("-" . ($i - 1) . "day midnight");
|
||||
|
||||
|
@ -224,7 +267,7 @@ class Club extends RowModel
|
|||
"shape" => "spline",
|
||||
"color" => "#597da3",
|
||||
],
|
||||
"name" => $unique ? "Полный охват" : "Все просмотры",
|
||||
"name" => $unique ? tr("full_coverage") : tr("all_views"),
|
||||
],
|
||||
"subs" => [
|
||||
"x" => array_reverse(range(1, 7)),
|
||||
|
@ -235,7 +278,7 @@ class Club extends RowModel
|
|||
"color" => "#b05c91",
|
||||
],
|
||||
"fill" => "tozeroy",
|
||||
"name" => $unique ? "Охват подписчиков" : "Просмотры подписчиков",
|
||||
"name" => $unique ? tr("subs_coverage") : tr("subs_views"),
|
||||
],
|
||||
"viral" => [
|
||||
"x" => array_reverse(range(1, 7)),
|
||||
|
@ -246,12 +289,12 @@ class Club extends RowModel
|
|||
"color" => "#4d9fab",
|
||||
],
|
||||
"fill" => "tozeroy",
|
||||
"name" => $unique ? "Виральный охват" : "Виральные просмотры",
|
||||
"name" => $unique ? tr("viral_coverage") : tr("viral_views"),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
function getSubscriptionStatus(User $user): bool
|
||||
public function getSubscriptionStatus(User $user): bool
|
||||
{
|
||||
$subbed = !is_null($this->getRecord()->related("subscriptions.target")->where([
|
||||
"target" => $this->getId(),
|
||||
|
@ -262,11 +305,11 @@ class Club extends RowModel
|
|||
return $subbed && ($this->getOpennesStatus() === static::CLOSED ? $this->isSubscriptionAccepted($user) : true);
|
||||
}
|
||||
|
||||
function getFollowersQuery(string $sort = "follower ASC"): GroupedSelection
|
||||
public function getFollowersQuery(string $sort = "follower ASC"): GroupedSelection
|
||||
{
|
||||
$query = $this->getRecord()->related("subscriptions.target");
|
||||
|
||||
if($this->getOpennesStatus() === static::OPEN) {
|
||||
if ($this->getOpennesStatus() === static::OPEN) {
|
||||
$query = $query->where("model", "openvk\\Web\\Models\\Entities\\Club")->order($sort);
|
||||
} else {
|
||||
return false;
|
||||
|
@ -275,56 +318,80 @@ class Club extends RowModel
|
|||
return $query->group("follower");
|
||||
}
|
||||
|
||||
function getFollowersCount(): int
|
||||
public function getFollowersCount(): int
|
||||
{
|
||||
return sizeof($this->getFollowersQuery());
|
||||
}
|
||||
|
||||
function getFollowers(int $page = 1, int $perPage = 6, string $sort = "follower ASC"): \Traversable
|
||||
public function getFollowers(int $page = 1, int $perPage = 6, string $sort = "follower ASC"): \Traversable
|
||||
{
|
||||
$rels = $this->getFollowersQuery($sort)->page($page, $perPage);
|
||||
|
||||
foreach($rels as $rel) {
|
||||
$rel = (new Users)->get($rel->follower);
|
||||
if(!$rel) continue;
|
||||
foreach ($rels as $rel) {
|
||||
$rel = (new Users())->get($rel->follower);
|
||||
if (!$rel) {
|
||||
continue;
|
||||
}
|
||||
|
||||
yield $rel;
|
||||
}
|
||||
}
|
||||
|
||||
function getManagers(int $page = 1, bool $ignoreHidden = false): \Traversable
|
||||
public function getSuggestedPostsCount(User $user = null)
|
||||
{
|
||||
$count = 0;
|
||||
|
||||
if (is_null($user)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->canBeModifiedBy($user)) {
|
||||
$count = (new Posts())->getSuggestedPostsCount($this->getId());
|
||||
} else {
|
||||
$count = (new Posts())->getSuggestedPostsCountByUser($this->getId(), $user->getId());
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
public function getManagers(int $page = 1, bool $ignoreHidden = false): \Traversable
|
||||
{
|
||||
$rels = $this->getRecord()->related("group_coadmins.club")->page($page, 6);
|
||||
if($ignoreHidden)
|
||||
if ($ignoreHidden) {
|
||||
$rels = $rels->where("hidden", false);
|
||||
}
|
||||
|
||||
foreach($rels as $rel) {
|
||||
$rel = (new Managers)->get($rel->id);
|
||||
if(!$rel) continue;
|
||||
foreach ($rels as $rel) {
|
||||
$rel = (new Managers())->get($rel->id);
|
||||
if (!$rel) {
|
||||
continue;
|
||||
}
|
||||
|
||||
yield $rel;
|
||||
}
|
||||
}
|
||||
|
||||
function getManager(User $user, bool $ignoreHidden = false): ?Manager
|
||||
public function getManager(User $user, bool $ignoreHidden = false): ?Manager
|
||||
{
|
||||
$manager = (new Managers)->getByUserAndClub($user->getId(), $this->getId());
|
||||
$manager = (new Managers())->getByUserAndClub($user->getId(), $this->getId());
|
||||
|
||||
if ($ignoreHidden && $manager !== NULL && $manager->isHidden())
|
||||
return NULL;
|
||||
if ($ignoreHidden && $manager !== null && $manager->isHidden()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $manager;
|
||||
}
|
||||
|
||||
function getManagersCount(bool $ignoreHidden = false): int
|
||||
public function getManagersCount(bool $ignoreHidden = false): int
|
||||
{
|
||||
if($ignoreHidden)
|
||||
if ($ignoreHidden) {
|
||||
return sizeof($this->getRecord()->related("group_coadmins.club")->where("hidden", false)) + (int) !$this->isOwnerHidden();
|
||||
}
|
||||
|
||||
return sizeof($this->getRecord()->related("group_coadmins.club")) + 1;
|
||||
}
|
||||
|
||||
function addManager(User $user, ?string $comment = NULL): void
|
||||
public function addManager(User $user, ?string $comment = null): void
|
||||
{
|
||||
DB::i()->getContext()->table("group_coadmins")->insert([
|
||||
"club" => $this->getId(),
|
||||
|
@ -333,7 +400,7 @@ class Club extends RowModel
|
|||
]);
|
||||
}
|
||||
|
||||
function removeManager(User $user): void
|
||||
public function removeManager(User $user): void
|
||||
{
|
||||
DB::i()->getContext()->table("group_coadmins")->where([
|
||||
"club" => $this->getId(),
|
||||
|
@ -341,54 +408,129 @@ class Club extends RowModel
|
|||
])->delete();
|
||||
}
|
||||
|
||||
function canBeModifiedBy(User $user): bool
|
||||
public function canBeModifiedBy(User $user): bool
|
||||
{
|
||||
$id = $user->getId();
|
||||
if($this->getOwner()->getId() === $id)
|
||||
if ($this->getOwner()->getId() === $id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !is_null($this->getRecord()->related("group_coadmins.club")->where("user", $id)->fetch());
|
||||
}
|
||||
|
||||
function getWebsite(): ?string
|
||||
public function getWebsite(): ?string
|
||||
{
|
||||
return $this->getRecord()->website;
|
||||
}
|
||||
|
||||
function getAlert(): ?string
|
||||
public function ban(string $reason): void
|
||||
{
|
||||
$this->setBlock_Reason($reason);
|
||||
$this->save();
|
||||
}
|
||||
|
||||
public function unban(): void
|
||||
{
|
||||
$this->setBlock_Reason(null);
|
||||
$this->save();
|
||||
}
|
||||
|
||||
public function canBeViewedBy(?User $user = null)
|
||||
{
|
||||
return is_null($this->getBanReason());
|
||||
}
|
||||
|
||||
public function getAlert(): ?string
|
||||
{
|
||||
return $this->getRecord()->alert;
|
||||
}
|
||||
|
||||
function toVkApiStruct(?User $user = NULL): object
|
||||
public function getRealId(): int
|
||||
{
|
||||
$res = [];
|
||||
return $this->getId() * -1;
|
||||
}
|
||||
|
||||
public function isEveryoneCanUploadAudios(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->everyone_can_upload_audios;
|
||||
}
|
||||
|
||||
public function canUploadAudio(?User $user): bool
|
||||
{
|
||||
if (!$user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->isEveryoneCanUploadAudios() || $this->canBeModifiedBy($user);
|
||||
}
|
||||
|
||||
public function canUploadDocs(?User $user): bool
|
||||
{
|
||||
if (!$user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->canBeModifiedBy($user);
|
||||
}
|
||||
|
||||
public function getAudiosCollectionSize()
|
||||
{
|
||||
return (new \openvk\Web\Models\Repositories\Audios())->getClubCollectionSize($this);
|
||||
}
|
||||
|
||||
public function toVkApiStruct(?User $user = null, string $fields = ''): object
|
||||
{
|
||||
$res = (object) [];
|
||||
|
||||
$res->id = $this->getId();
|
||||
$res->name = $this->getName();
|
||||
$res->screen_name = $this->getShortCode();
|
||||
$res->is_closed = 0;
|
||||
$res->deactivated = NULL;
|
||||
$res->is_admin = $this->canBeModifiedBy($user);
|
||||
$res->screen_name = $this->getShortCode() ?? "club" . $this->getId();
|
||||
$res->is_closed = false;
|
||||
$res->type = 'group';
|
||||
$res->is_member = $user ? (int) $this->getSubscriptionStatus($user) : 0;
|
||||
$res->deactivated = null;
|
||||
$res->can_access_closed = true;
|
||||
|
||||
if($this->canBeModifiedBy($user)) {
|
||||
$res->admin_level = 3;
|
||||
if (!is_array($fields)) {
|
||||
$fields = explode(',', $fields);
|
||||
}
|
||||
|
||||
$res->is_member = $this->getSubscriptionStatus($user) ? 1 : 0;
|
||||
|
||||
$res->type = "group";
|
||||
$res->photo_50 = $this->getAvatarUrl("miniscule");
|
||||
$res->photo_100 = $this->getAvatarUrl("tiny");
|
||||
$res->photo_200 = $this->getAvatarUrl("normal");
|
||||
|
||||
$res->can_create_topic = $this->canBeModifiedBy($user) ? 1 : ($this->isEveryoneCanCreateTopics() ? 1 : 0);
|
||||
|
||||
$res->can_post = $this->canBeModifiedBy($user) ? 1 : ($this->canPost() ? 1 : 0);
|
||||
|
||||
return (object) $res;
|
||||
$avatar_photo = $this->getAvatarPhoto();
|
||||
foreach ($fields as $field) {
|
||||
switch ($field) {
|
||||
case 'verified':
|
||||
$res->verified = (int) $this->isVerified();
|
||||
break;
|
||||
case 'site':
|
||||
$res->site = $this->getWebsite();
|
||||
break;
|
||||
case 'description':
|
||||
$res->description = $this->getDescription();
|
||||
break;
|
||||
case 'background':
|
||||
$res->background = $this->getBackDropPictureURLs();
|
||||
break;
|
||||
case 'photo_50':
|
||||
$res->photo_50 = $this->getAvatarUrl('miniscule', $avatar_photo);
|
||||
break;
|
||||
case 'photo_100':
|
||||
$res->photo_100 = $this->getAvatarUrl('tiny', $avatar_photo);
|
||||
break;
|
||||
case 'photo_200':
|
||||
$res->photo_200 = $this->getAvatarUrl('normal', $avatar_photo);
|
||||
break;
|
||||
case 'photo_max':
|
||||
$res->photo_max = $this->getAvatarUrl('original', $avatar_photo);
|
||||
break;
|
||||
case 'members_count':
|
||||
$res->members_count = $this->getFollowersCount();
|
||||
break;
|
||||
case 'real_id':
|
||||
$res->real_id = $this->getRealId();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
use Traits\TBackDrops;
|
||||
use Traits\TSubscribable;
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use openvk\Web\Models\Repositories\Clubs;
|
||||
use openvk\Web\Models\RowModel;
|
||||
use openvk\Web\Models\Entities\{Note};
|
||||
|
@ -9,52 +13,63 @@ class Comment extends Post
|
|||
protected $tableName = "comments";
|
||||
protected $upperNodeReferenceColumnName = "owner";
|
||||
|
||||
function getPrettyId(): string
|
||||
public function getPrettyId(): string
|
||||
{
|
||||
return $this->getRecord()->id;
|
||||
return (string) $this->getRecord()->id;
|
||||
}
|
||||
|
||||
function getVirtualId(): int
|
||||
public function getVirtualId(): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getTarget(): ?Postable
|
||||
public function getTarget(): ?Postable
|
||||
{
|
||||
$entityClassName = $this->getRecord()->model;
|
||||
$repoClassName = str_replace("Entities", "Repositories", $entityClassName) . "s";
|
||||
$entity = (new $repoClassName)->get($this->getRecord()->target);
|
||||
$entity = (new $repoClassName())->get($this->getRecord()->target);
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
public function getPageURL(): string
|
||||
{
|
||||
return '#';
|
||||
}
|
||||
|
||||
/**
|
||||
* May return fake owner (group), if flags are [1, (*)]
|
||||
*
|
||||
* @param bool $honourFlags - check flags
|
||||
*/
|
||||
function getOwner(bool $honourFlags = true, bool $real = false): RowModel
|
||||
public function getOwner(bool $honourFlags = true, bool $real = false): RowModel
|
||||
{
|
||||
if($honourFlags && $this->isPostedOnBehalfOfGroup()) {
|
||||
if($this->getTarget() instanceof Post)
|
||||
return (new Clubs)->get(abs($this->getTarget()->getTargetWall()));
|
||||
if ($honourFlags && $this->isPostedOnBehalfOfGroup()) {
|
||||
if ($this->getTarget() instanceof Post) {
|
||||
return (new Clubs())->get(abs($this->getTarget()->getTargetWall()));
|
||||
}
|
||||
|
||||
if($this->getTarget() instanceof Topic)
|
||||
if ($this->getTarget() instanceof Topic) {
|
||||
return $this->getTarget()->getClub();
|
||||
}
|
||||
}
|
||||
|
||||
return parent::getOwner($honourFlags, $real);
|
||||
}
|
||||
|
||||
function canBeDeletedBy(User $user): bool
|
||||
public function canBeDeletedBy(User $user = null): bool
|
||||
{
|
||||
if (!$user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->getOwner()->getId() == $user->getId() ||
|
||||
$this->getTarget()->getOwner()->getId() == $user->getId() ||
|
||||
$this->getTarget() instanceof Post && $this->getTarget()->getTargetWall() < 0 && (new Clubs)->get(abs($this->getTarget()->getTargetWall()))->canBeModifiedBy($user) ||
|
||||
$this->getTarget() instanceof Post && $this->getTarget()->getTargetWall() < 0 && (new Clubs())->get(abs($this->getTarget()->getTargetWall()))->canBeModifiedBy($user) ||
|
||||
$this->getTarget() instanceof Topic && $this->getTarget()->canBeModifiedBy($user);
|
||||
}
|
||||
|
||||
function toVkApiStruct(?User $user = NULL, bool $need_likes = false, bool $extended = false, ?Note $note = NULL): object
|
||||
public function toVkApiStruct(?User $user = null, bool $need_likes = false, bool $extended = false, ?Note $note = null): object
|
||||
{
|
||||
$res = (object) [];
|
||||
|
||||
|
@ -65,24 +80,110 @@ class Comment extends Post
|
|||
$res->attachments = [];
|
||||
$res->parents_stack = [];
|
||||
|
||||
if(!is_null($note)) {
|
||||
if (!is_null($note)) {
|
||||
$res->uid = $this->getOwner()->getId();
|
||||
$res->nid = $note->getId();
|
||||
$res->oid = $note->getOwner()->getId();
|
||||
}
|
||||
|
||||
foreach($this->getChildren() as $attachment) {
|
||||
if($attachment->isDeleted())
|
||||
foreach ($this->getChildren() as $attachment) {
|
||||
if ($attachment->isDeleted()) {
|
||||
continue;
|
||||
|
||||
$res->attachments[] = $attachment->toVkApiStruct();
|
||||
}
|
||||
|
||||
if($need_likes) {
|
||||
if ($attachment instanceof \openvk\Web\Models\Entities\Photo) {
|
||||
$res->attachments[] = $attachment->toVkApiStruct();
|
||||
} elseif ($attachment instanceof \openvk\Web\Models\Entities\Video) {
|
||||
$res->attachments[] = $attachment->toVkApiStruct($this->getUser());
|
||||
}
|
||||
}
|
||||
|
||||
if ($need_likes) {
|
||||
$res->count = $this->getLikesCount();
|
||||
$res->user_likes = (int)$this->hasLikeFrom($user);
|
||||
$res->user_likes = (int) $this->hasLikeFrom($user);
|
||||
$res->can_like = 1;
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function getURL(): string
|
||||
{
|
||||
return "/wall" . $this->getTarget()->getPrettyId() . "#_comment" . $this->getId();
|
||||
}
|
||||
|
||||
public function canBeViewedBy(?User $user = null): bool
|
||||
{
|
||||
if ($this->isDeleted() || $this->getTarget()->isDeleted()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->getTarget()->canBeViewedBy($user);
|
||||
}
|
||||
|
||||
public function isFromPostAuthor($target = null)
|
||||
{
|
||||
if (!$target) {
|
||||
$target = $this->getTarget();
|
||||
}
|
||||
|
||||
$target_owner = $target->getOwner();
|
||||
$comment_owner = $this->getOwner();
|
||||
|
||||
if ($target_owner->getRealId() === $comment_owner->getRealId()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
# TODO: make it work with signer_id
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function toNotifApiStruct()
|
||||
{
|
||||
$res = (object) [];
|
||||
|
||||
$res->id = $this->getId();
|
||||
$res->owner_id = $this->getOwner()->getId();
|
||||
$res->date = $this->getPublicationTime()->timestamp();
|
||||
$res->text = $this->getText(false);
|
||||
$res->post = null; # todo
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function canBeEditedBy(?User $user = null): bool
|
||||
{
|
||||
if (!$user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $user->getId() == $this->getOwner(false)->getId();
|
||||
}
|
||||
|
||||
public function getTargetURL(): string
|
||||
{
|
||||
$target = $this->getTarget();
|
||||
$target_name = 'wall';
|
||||
|
||||
if (!$target) {
|
||||
return '/404';
|
||||
}
|
||||
|
||||
switch (get_class($target)) {
|
||||
case 'openvk\Web\Models\Entities\Note':
|
||||
$target_name = 'note';
|
||||
break;
|
||||
case 'openvk\Web\Models\Entities\Photo':
|
||||
$target_name = 'photo';
|
||||
break;
|
||||
case 'openvk\Web\Models\Entities\Video':
|
||||
$target_name = 'video';
|
||||
break;
|
||||
case 'openvk\Web\Models\Entities\Topic':
|
||||
$target_name = 'topic';
|
||||
break;
|
||||
}
|
||||
|
||||
return $target_name . $target->getPrettyId();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
use Chandler\Signaling\SignalManager;
|
||||
use Chandler\Security\Authenticator;
|
||||
|
@ -27,8 +31,8 @@ class Correspondence
|
|||
*/
|
||||
private $messages;
|
||||
|
||||
const CAP_BEHAVIOUR_END_MESSAGE_ID = 1;
|
||||
const CAP_BEHAVIOUR_START_MESSAGE_ID = 2;
|
||||
public const CAP_BEHAVIOUR_END_MESSAGE_ID = 1;
|
||||
public const CAP_BEHAVIOUR_START_MESSAGE_ID = 2;
|
||||
|
||||
/**
|
||||
* Correspondence constructor.
|
||||
|
@ -38,7 +42,7 @@ class Correspondence
|
|||
* @param $correspondent - first correspondent
|
||||
* @param $anotherCorrespondents - another correspondent
|
||||
*/
|
||||
function __construct(RowModel $correspondent, RowModel $anotherCorrespondent)
|
||||
public function __construct(RowModel $correspondent, RowModel $anotherCorrespondent)
|
||||
{
|
||||
$this->correspondents = [$correspondent, $anotherCorrespondent];
|
||||
$this->messages = DatabaseConnection::i()->getContext()->table("messages");
|
||||
|
@ -49,7 +53,7 @@ class Correspondence
|
|||
*
|
||||
* @returns string - URL
|
||||
*/
|
||||
function getURL(): string
|
||||
public function getURL(): string
|
||||
{
|
||||
$id = $this->correspondents[1]->getId();
|
||||
$id = get_class($this->correspondents[1]) === 'openvk\Web\Models\Entities\Club' ? $id * -1 : $id;
|
||||
|
@ -57,7 +61,7 @@ class Correspondence
|
|||
return "/im?sel=$id";
|
||||
}
|
||||
|
||||
function getID(): int
|
||||
public function getID(): int
|
||||
{
|
||||
$id = $this->correspondents[1]->getId();
|
||||
$id = get_class($this->correspondents[1]) === 'openvk\Web\Models\Entities\Club' ? $id * -1 : $id;
|
||||
|
@ -70,7 +74,7 @@ class Correspondence
|
|||
*
|
||||
* @returns RowModel[] Array of correspondents (usually two)
|
||||
*/
|
||||
function getCorrespondents(): array
|
||||
public function getCorrespondents(): array
|
||||
{
|
||||
return $this->correspondents;
|
||||
}
|
||||
|
@ -84,38 +88,42 @@ class Correspondence
|
|||
* @param $limit - messages per page (defaults to default per page count)
|
||||
* @returns \Traversable - iterable messages cursor
|
||||
*/
|
||||
function getMessages(int $capBehavior = 1, ?int $cap = NULL, ?int $limit = NULL, ?int $padding = NULL, bool $reverse = false): array
|
||||
public function getMessages(int $capBehavior = 1, ?int $cap = null, ?int $limit = null, ?int $padding = null, bool $reverse = false): array
|
||||
{
|
||||
$query = file_get_contents(__DIR__ . "/../sql/get-messages.tsql");
|
||||
$params = [
|
||||
[get_class($this->correspondents[0]), get_class($this->correspondents[1])],
|
||||
[$this->correspondents[0]->getId(), $this->correspondents[1]->getId()],
|
||||
[$limit ?? OPENVK_DEFAULT_PER_PAGE]
|
||||
[$limit ?? OPENVK_DEFAULT_PER_PAGE],
|
||||
];
|
||||
$params = array_merge($params[0], $params[1], array_reverse($params[0]), array_reverse($params[1]), $params[2]);
|
||||
|
||||
if ($limit === NULL)
|
||||
DatabaseConnection::i()->getConnection()->query("UPDATE messages SET unread = 0 WHERE sender_id = ".$this->correspondents[1]->getId());
|
||||
if ($limit === null) {
|
||||
DatabaseConnection::i()->getConnection()->query("UPDATE messages SET unread = 0 WHERE sender_id = " . $this->correspondents[1]->getId());
|
||||
}
|
||||
|
||||
if(is_null($cap)) {
|
||||
if (is_null($cap)) {
|
||||
$query = str_replace("\n AND (`id` > ?)", "", $query);
|
||||
} else {
|
||||
if($capBehavior === 1)
|
||||
if ($capBehavior === 1) {
|
||||
$query = str_replace("\n AND (`id` > ?)", "\n AND (`id` < ?)", $query);
|
||||
}
|
||||
|
||||
array_unshift($params, $cap);
|
||||
}
|
||||
|
||||
if(is_null($padding))
|
||||
if (is_null($padding)) {
|
||||
$query = str_replace("\nOFFSET\n?", "", $query);
|
||||
else
|
||||
} else {
|
||||
$params[] = $padding;
|
||||
}
|
||||
|
||||
if($reverse)
|
||||
if ($reverse) {
|
||||
$query = str_replace("`created` DESC", "`created` ASC", $query);
|
||||
}
|
||||
|
||||
$msgs = DatabaseConnection::i()->getConnection()->query($query, ...$params);
|
||||
$msgs = array_map(function($message) {
|
||||
$msgs = array_map(function ($message) {
|
||||
$message = new ActiveRow((array) $message, $this->messages); #Directly creating ActiveRow is faster than making query
|
||||
|
||||
return new Message($message);
|
||||
|
@ -129,10 +137,10 @@ class Correspondence
|
|||
*
|
||||
* @returns Message|null - message, if any
|
||||
*/
|
||||
function getPreviewMessage(): ?Message
|
||||
public function getPreviewMessage(): ?Message
|
||||
{
|
||||
$messages = $this->getMessages(1, NULL, 1);
|
||||
return $messages[0] ?? NULL;
|
||||
$messages = $this->getMessages(1, null, 1, 0);
|
||||
return $messages[0] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -141,17 +149,18 @@ class Correspondence
|
|||
* @deprecated
|
||||
* @returns Message|false - resulting message, or false in case of non-successful transaction
|
||||
*/
|
||||
function sendMessage(Message $message, bool $dontReverse = false)
|
||||
public function sendMessage(Message $message, bool $dontReverse = false)
|
||||
{
|
||||
if(!$dontReverse) {
|
||||
$user = (new Users)->getByChandlerUser(Authenticator::i()->getUser());
|
||||
if(!$user)
|
||||
if (!$dontReverse) {
|
||||
$user = (new Users())->getByChandlerUser(Authenticator::i()->getUser());
|
||||
if (!$user) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$ids = [$this->correspondents[0]->getId(), $this->correspondents[1]->getId()];
|
||||
$classes = [get_class($this->correspondents[0]), get_class($this->correspondents[1])];
|
||||
if(!$dontReverse && $ids[1] === $user->getId()) {
|
||||
if (!$dontReverse && $ids[1] === $user->getId()) {
|
||||
$ids = array_reverse($ids);
|
||||
$classes = array_reverse($classes);
|
||||
}
|
||||
|
@ -164,10 +173,10 @@ class Correspondence
|
|||
$message->setUnread(1);
|
||||
$message->save();
|
||||
|
||||
DatabaseConnection::i()->getConnection()->query("UPDATE messages SET unread = 0 WHERE sender_id = ".$this->correspondents[1]->getId());
|
||||
DatabaseConnection::i()->getConnection()->query("UPDATE messages SET unread = 0 WHERE sender_id = " . $this->correspondents[1]->getId());
|
||||
|
||||
# да
|
||||
if($ids[0] !== $ids[1]) {
|
||||
if ($ids[0] !== $ids[1]) {
|
||||
$event = new NewMessageEvent($message);
|
||||
(SignalManager::i())->triggerEvent($event, $ids[1]);
|
||||
}
|
||||
|
|
441
Web/Models/Entities/Document.php
Normal file
441
Web/Models/Entities/Document.php
Normal file
|
@ -0,0 +1,441 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use openvk\Web\Models\Repositories\{Clubs, Users, Photos};
|
||||
use openvk\Web\Models\Entities\{Photo};
|
||||
use openvk\Web\Models\RowModel;
|
||||
use Nette\InvalidStateException as ISE;
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
|
||||
class Document extends Media
|
||||
{
|
||||
protected $tableName = "documents";
|
||||
protected $fileExtension = "gif";
|
||||
private $tmp_format = null;
|
||||
|
||||
public const VKAPI_TYPE_TEXT = 1;
|
||||
public const VKAPI_TYPE_ARCHIVE = 2;
|
||||
public const VKAPI_TYPE_GIF = 3;
|
||||
public const VKAPI_TYPE_IMAGE = 4;
|
||||
public const VKAPI_TYPE_AUDIO = 5;
|
||||
public const VKAPI_TYPE_VIDEO = 6;
|
||||
public const VKAPI_TYPE_BOOKS = 7;
|
||||
public const VKAPI_TYPE_UNKNOWN = 8;
|
||||
|
||||
public const VKAPI_FOLDER_PRIVATE = 0;
|
||||
public const VKAPI_FOLDER_STUDY = 1;
|
||||
public const VKAPI_FOLDER_BOOK = 2;
|
||||
public const VKAPI_FOLDER_PUBLIC = 3;
|
||||
|
||||
protected function pathFromHash(string $hash): string
|
||||
{
|
||||
$dir = $this->getBaseDir() . substr($hash, 0, 2);
|
||||
if (!is_dir($dir)) {
|
||||
mkdir($dir);
|
||||
}
|
||||
|
||||
return "$dir/$hash." . $this->getFileExtension();
|
||||
}
|
||||
|
||||
public function getURL(): string
|
||||
{
|
||||
$hash = $this->getRecord()->hash;
|
||||
$filetype = $this->getFileExtension();
|
||||
|
||||
switch (OPENVK_ROOT_CONF["openvk"]["preferences"]["uploads"]["mode"]) {
|
||||
default:
|
||||
case "default":
|
||||
case "basic":
|
||||
return "http://" . $_SERVER['HTTP_HOST'] . "/blob_" . substr($hash, 0, 2) . "/$hash.$filetype";
|
||||
break;
|
||||
case "accelerated":
|
||||
return "http://" . $_SERVER['HTTP_HOST'] . "/openvk-datastore/$hash.$filetype";
|
||||
break;
|
||||
case "server":
|
||||
$settings = (object) OPENVK_ROOT_CONF["openvk"]["preferences"]["uploads"]["server"];
|
||||
return (
|
||||
$settings->protocol ?? ovk_scheme() .
|
||||
"://" . $settings->host .
|
||||
$settings->path .
|
||||
substr($hash, 0, 2) . "/$hash.$filetype"
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected function saveFile(string $filename, string $hash): bool
|
||||
{
|
||||
move_uploaded_file($filename, $this->pathFromHash($hash));
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function makePreview(string $tmp_name, string $filename, int $owner): bool
|
||||
{
|
||||
$preview_photo = new Photo();
|
||||
$preview_photo->setOwner($owner);
|
||||
$preview_photo->setDescription("internal use");
|
||||
$preview_photo->setCreated(time());
|
||||
$preview_photo->setSystem(1);
|
||||
$preview_photo->setFile([
|
||||
"tmp_name" => $tmp_name,
|
||||
"error" => 0,
|
||||
]);
|
||||
$preview_photo->save();
|
||||
$this->stateChanges("preview", "photo_" . $preview_photo->getId());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function updateHash(string $hash): bool
|
||||
{
|
||||
$this->stateChanges("hash", $hash);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function setFile(array $file): void
|
||||
{
|
||||
if ($file["error"] !== UPLOAD_ERR_OK) {
|
||||
throw new ISE("File uploaded is corrupted");
|
||||
}
|
||||
|
||||
$original_name = $file["name"];
|
||||
$file_format = end(explode(".", $original_name));
|
||||
$file_size = $file["size"];
|
||||
$type = Document::detectTypeByFormat($file_format);
|
||||
|
||||
if (!$file_format) {
|
||||
throw new \TypeError("No file format");
|
||||
}
|
||||
|
||||
if (!in_array(mb_strtolower($file_format), OPENVK_ROOT_CONF["openvk"]["preferences"]["docs"]["allowedFormats"])) {
|
||||
throw new \TypeError("Forbidden file format");
|
||||
}
|
||||
|
||||
if ($file_size < 1 || $file_size > (OPENVK_ROOT_CONF["openvk"]["preferences"]["docs"]["maxSize"] * 1024 * 1024)) {
|
||||
throw new \ValueError("Invalid filesize");
|
||||
}
|
||||
|
||||
$hash = hash_file("whirlpool", $file["tmp_name"]);
|
||||
$this->stateChanges("original_name", ovk_proc_strtr($original_name, 255));
|
||||
$this->tmp_format = mb_strtolower($file_format);
|
||||
$this->stateChanges("format", mb_strtolower($file_format));
|
||||
$this->stateChanges("filesize", $file_size);
|
||||
$this->stateChanges("hash", $hash);
|
||||
$this->stateChanges("access_key", bin2hex(random_bytes(9)));
|
||||
$this->stateChanges("type", $type);
|
||||
|
||||
if (in_array($type, [3, 4])) {
|
||||
$this->makePreview($file["tmp_name"], $original_name, $file["preview_owner"]);
|
||||
}
|
||||
|
||||
$this->saveFile($file["tmp_name"], $hash);
|
||||
}
|
||||
|
||||
public function hasPreview(): bool
|
||||
{
|
||||
return $this->getRecord()->preview != null;
|
||||
}
|
||||
|
||||
public function isOwnerHidden(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->owner_hidden;
|
||||
}
|
||||
|
||||
public function isCopy(): bool
|
||||
{
|
||||
return $this->getRecord()->copy_of != null;
|
||||
}
|
||||
|
||||
public function isLicensed(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isUnsafe(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isAnonymous(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isPrivate(): bool
|
||||
{
|
||||
return $this->getFolder() == Document::VKAPI_FOLDER_PRIVATE;
|
||||
}
|
||||
|
||||
public function isImage(): bool
|
||||
{
|
||||
return in_array($this->getVKAPIType(), [3, 4]);
|
||||
}
|
||||
|
||||
public function isBook(): bool
|
||||
{
|
||||
return in_array($this->getFileExtension(), ["pdf"]);
|
||||
}
|
||||
|
||||
public function isAudio(): bool
|
||||
{
|
||||
return in_array($this->getVKAPIType(), [Document::VKAPI_TYPE_AUDIO]);
|
||||
}
|
||||
|
||||
public function isGif(): bool
|
||||
{
|
||||
return $this->getVKAPIType() == 3;
|
||||
}
|
||||
|
||||
public function isCopiedBy($user = null): bool
|
||||
{
|
||||
if (!$user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($user->getRealId() === $this->getOwnerID()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return DatabaseConnection::i()->getContext()->table("documents")->where([
|
||||
"owner" => $user->getRealId(),
|
||||
"copy_of" => $this->getId(),
|
||||
"deleted" => 0,
|
||||
])->count() > 0;
|
||||
}
|
||||
|
||||
public function copy(User $user): Document
|
||||
{
|
||||
$item = DatabaseConnection::i()->getContext()->table("documents")->where([
|
||||
"owner" => $user->getId(),
|
||||
"copy_of" => $this->getId(),
|
||||
]);
|
||||
if ($item->count() > 0) {
|
||||
$older = new Document($item->fetch());
|
||||
}
|
||||
|
||||
$this_document_array = $this->getRecord()->toArray();
|
||||
|
||||
$new_document = new Document();
|
||||
$new_document->setOwner($user->getId());
|
||||
$new_document->updateHash($this_document_array["hash"]);
|
||||
$new_document->setOwner_hidden(1);
|
||||
$new_document->setCopy_of($this->getId());
|
||||
$new_document->setName($this->getId());
|
||||
$new_document->setOriginal_name($this->getOriginalName());
|
||||
$new_document->setAccess_key(bin2hex(random_bytes(9)));
|
||||
$new_document->setFormat($this_document_array["format"]);
|
||||
$new_document->setType($this->getVKAPIType());
|
||||
$new_document->setFolder_id(0);
|
||||
$new_document->setPreview($this_document_array["preview"]);
|
||||
$new_document->setTags($this_document_array["tags"]);
|
||||
$new_document->setFilesize($this_document_array["filesize"]);
|
||||
|
||||
$new_document->save();
|
||||
|
||||
return $new_document;
|
||||
}
|
||||
|
||||
public function setTags(?string $tags): bool
|
||||
{
|
||||
if (is_null($tags)) {
|
||||
$this->stateChanges("tags", null);
|
||||
return true;
|
||||
}
|
||||
|
||||
$parsed = explode(",", $tags);
|
||||
if (sizeof($parsed) < 1 || $parsed[0] == "") {
|
||||
$this->stateChanges("tags", null);
|
||||
return true;
|
||||
}
|
||||
|
||||
$result = "";
|
||||
foreach ($parsed as $tag) {
|
||||
$result .= trim($tag) . ($tag != end($parsed) ? "," : '');
|
||||
}
|
||||
|
||||
$this->stateChanges("tags", ovk_proc_strtr($result, 500));
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getOwner(bool $real = false): RowModel
|
||||
{
|
||||
$oid = (int) $this->getRecord()->owner;
|
||||
if ($oid > 0) {
|
||||
return (new Users())->get($oid);
|
||||
} else {
|
||||
return (new Clubs())->get($oid * -1);
|
||||
}
|
||||
}
|
||||
|
||||
public function getFileExtension(): string
|
||||
{
|
||||
if ($this->tmp_format) {
|
||||
return $this->tmp_format;
|
||||
}
|
||||
|
||||
return $this->getRecord()->format;
|
||||
}
|
||||
|
||||
public function getPrettyId(): string
|
||||
{
|
||||
return $this->getVirtualId() . "_" . $this->getId();
|
||||
}
|
||||
|
||||
public function getPrettiestId(): string
|
||||
{
|
||||
return $this->getVirtualId() . "_" . $this->getId() . "_" . $this->getAccessKey();
|
||||
}
|
||||
|
||||
public function getOriginal(): Document
|
||||
{
|
||||
return $this->getRecord()->copy_of;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->getRecord()->name;
|
||||
}
|
||||
|
||||
public function getOriginalName(): string
|
||||
{
|
||||
return $this->getRecord()->original_name;
|
||||
}
|
||||
|
||||
public function getVKAPIType(): int
|
||||
{
|
||||
return $this->getRecord()->type;
|
||||
}
|
||||
|
||||
public function getFolder(): int
|
||||
{
|
||||
return $this->getRecord()->folder_id;
|
||||
}
|
||||
|
||||
public function getTags(): array
|
||||
{
|
||||
$tags = $this->getRecord()->tags;
|
||||
if (!$tags) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return explode(",", $tags ?? "");
|
||||
}
|
||||
|
||||
public function getFilesize(): int
|
||||
{
|
||||
return $this->getRecord()->filesize;
|
||||
}
|
||||
|
||||
public function getPreview(): ?RowModel
|
||||
{
|
||||
$preview_array = $this->getRecord()->preview;
|
||||
$preview = explode(",", $this->getRecord()->preview)[0];
|
||||
$model = null;
|
||||
$exploded = explode("_", $preview);
|
||||
|
||||
switch ($exploded[0]) {
|
||||
case "photo":
|
||||
$model = (new Photos())->get((int) $exploded[1]);
|
||||
break;
|
||||
}
|
||||
|
||||
return $model;
|
||||
}
|
||||
|
||||
public function getOwnerID(): int
|
||||
{
|
||||
return $this->getRecord()->owner;
|
||||
}
|
||||
|
||||
public function toApiPreview(): object
|
||||
{
|
||||
$preview = $this->getPreview();
|
||||
if ($preview instanceof Photo) {
|
||||
return (object) [
|
||||
"photo" => [
|
||||
"sizes" => array_values($preview->getVkApiSizes()),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
public function canBeModifiedBy(User $user = null): bool
|
||||
{
|
||||
if (!$user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->getOwnerID() < 0) {
|
||||
return (new Clubs())->get(abs($this->getOwnerID()))->canBeModifiedBy($user);
|
||||
}
|
||||
|
||||
return $this->getOwnerID() === $user->getId();
|
||||
}
|
||||
|
||||
public function toVkApiStruct(?User $user = null, bool $return_tags = false): object
|
||||
{
|
||||
$res = new \stdClass();
|
||||
$res->id = $this->getId();
|
||||
$res->owner_id = $this->getVirtualId();
|
||||
$res->title = $this->getName();
|
||||
$res->size = $this->getFilesize();
|
||||
$res->ext = $this->getFileExtension();
|
||||
$res->url = $this->getURL();
|
||||
$res->date = $this->getPublicationTime()->timestamp();
|
||||
$res->type = $this->getVKAPIType();
|
||||
$res->is_hidden = (int) $this->isOwnerHidden();
|
||||
$res->is_licensed = (int) $this->isLicensed();
|
||||
$res->is_unsafe = (int) $this->isUnsafe();
|
||||
$res->folder_id = (int) $this->getFolder();
|
||||
$res->access_key = $this->getAccessKey();
|
||||
$res->private_url = "";
|
||||
if ($user) {
|
||||
$res->can_manage = $this->canBeModifiedBy($user);
|
||||
}
|
||||
|
||||
if ($this->hasPreview()) {
|
||||
$res->preview = $this->toApiPreview();
|
||||
}
|
||||
|
||||
if ($return_tags) {
|
||||
$res->tags = $this->getTags();
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function delete(bool $softly = true, bool $all_copies = false): void
|
||||
{
|
||||
if ($all_copies) {
|
||||
$ctx = DatabaseConnection::i()->getContext();
|
||||
$ctx->table("documents")->where("copy_of", $this->getId())->delete();
|
||||
}
|
||||
parent::delete($softly);
|
||||
}
|
||||
|
||||
public static function detectTypeByFormat(string $format)
|
||||
{
|
||||
switch (mb_strtolower($format)) {
|
||||
case "txt": case "docx": case "doc": case "odt": case "pptx": case "ppt": case "xlsx": case "xls": case "md":
|
||||
return 1;
|
||||
case "zip": case "rar": case "7z":
|
||||
return 2;
|
||||
case "gif": case "apng":
|
||||
return 3;
|
||||
case "jpg": case "jpeg": case "png": case "psd": case "ps": case "webp":
|
||||
return 4;
|
||||
case "mp3":
|
||||
return 5;
|
||||
case "mp4": case "avi":
|
||||
return 6;
|
||||
case "pdf": case "djvu": case "epub": case "fb2":
|
||||
return 7;
|
||||
default:
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use openvk\Web\Models\Repositories\Users;
|
||||
use openvk\Web\Models\RowModel;
|
||||
use openvk\Web\Util\DateTime;
|
||||
|
@ -8,7 +12,7 @@ class EmailChangeVerification extends PasswordReset
|
|||
{
|
||||
protected $tableName = "email_change_verifications";
|
||||
|
||||
function getNewEmail(): string
|
||||
public function getNewEmail(): string
|
||||
{
|
||||
return $this->getRecord()->new_email;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use openvk\Web\Models\Repositories\Users;
|
||||
use openvk\Web\Models\RowModel;
|
||||
use openvk\Web\Util\DateTime;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use openvk\Web\Util\DateTime;
|
||||
use openvk\Web\Models\RowModel;
|
||||
use openvk\Web\Models\Entities\User;
|
||||
|
@ -7,33 +11,33 @@ use Nette\Utils\{Image, ImageException};
|
|||
|
||||
class Gift extends RowModel
|
||||
{
|
||||
const IMAGE_MAXSIZE = 131072;
|
||||
const IMAGE_BINARY = 0;
|
||||
const IMAGE_BASE64 = 1;
|
||||
const IMAGE_URL = 2;
|
||||
public const IMAGE_MAXSIZE = 131072;
|
||||
public const IMAGE_BINARY = 0;
|
||||
public const IMAGE_BASE64 = 1;
|
||||
public const IMAGE_URL = 2;
|
||||
|
||||
const PERIOD_IGNORE = 0;
|
||||
const PERIOD_SET = 1;
|
||||
const PERIOD_SET_IF_NONE = 2;
|
||||
public const PERIOD_IGNORE = 0;
|
||||
public const PERIOD_SET = 1;
|
||||
public const PERIOD_SET_IF_NONE = 2;
|
||||
|
||||
protected $tableName = "gifts";
|
||||
|
||||
function getName(): string
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->getRecord()->internal_name;
|
||||
}
|
||||
|
||||
function getPrice(): int
|
||||
public function getPrice(): int
|
||||
{
|
||||
return $this->getRecord()->price;
|
||||
}
|
||||
|
||||
function getUsages(): int
|
||||
public function getUsages(): int
|
||||
{
|
||||
return $this->getRecord()->usages;
|
||||
}
|
||||
|
||||
function getUsagesBy(User $user, ?int $since = NULL): int
|
||||
public function getUsagesBy(User $user, ?int $since = null): int
|
||||
{
|
||||
$sent = $this->getRecord()
|
||||
->related("gift_user_relations.gift")
|
||||
|
@ -43,17 +47,18 @@ class Gift extends RowModel
|
|||
return sizeof($sent);
|
||||
}
|
||||
|
||||
function getUsagesLeft(User $user): float
|
||||
public function getUsagesLeft(User $user): float
|
||||
{
|
||||
if($this->getLimit() === INF)
|
||||
if ($this->getLimit() === INF) {
|
||||
return INF;
|
||||
}
|
||||
|
||||
return max(0, $this->getLimit() - $this->getUsagesBy($user));
|
||||
}
|
||||
|
||||
function getImage(int $type = 0): /* ?binary */ string
|
||||
public function getImage(int $type = 0): /* ?binary */ string
|
||||
{
|
||||
switch($type) {
|
||||
switch ($type) {
|
||||
default:
|
||||
case static::IMAGE_BINARY:
|
||||
return $this->getRecord()->image ?? "";
|
||||
|
@ -67,45 +72,45 @@ class Gift extends RowModel
|
|||
}
|
||||
}
|
||||
|
||||
function getLimit(): float
|
||||
public function getLimit(): float
|
||||
{
|
||||
$limit = $this->getRecord()->limit;
|
||||
|
||||
return !$limit ? INF : (float) $limit;
|
||||
}
|
||||
|
||||
function getLimitResetTime(): ?DateTime
|
||||
public function getLimitResetTime(): ?DateTime
|
||||
{
|
||||
return is_null($t = $this->getRecord()->limit_period) ? NULL : new DateTime($t);
|
||||
return is_null($t = $this->getRecord()->limit_period) ? null : new DateTime($t);
|
||||
}
|
||||
|
||||
function getUpdateDate(): DateTime
|
||||
public function getUpdateDate(): DateTime
|
||||
{
|
||||
return new DateTime($this->getRecord()->updated);
|
||||
}
|
||||
|
||||
function canUse(User $user): bool
|
||||
public function canUse(User $user): bool
|
||||
{
|
||||
return $this->getUsagesLeft($user) > 0;
|
||||
}
|
||||
|
||||
function isFree(): bool
|
||||
public function isFree(): bool
|
||||
{
|
||||
return $this->getPrice() === 0;
|
||||
}
|
||||
|
||||
function used(): void
|
||||
public function used(): void
|
||||
{
|
||||
$this->stateChanges("usages", $this->getUsages() + 1);
|
||||
$this->save();
|
||||
}
|
||||
|
||||
function setName(string $name): void
|
||||
public function setName(string $name): void
|
||||
{
|
||||
$this->stateChanges("internal_name", $name);
|
||||
}
|
||||
|
||||
function setImage(string $file): bool
|
||||
public function setImage(string $file): bool
|
||||
{
|
||||
$imgBlob;
|
||||
try {
|
||||
|
@ -113,11 +118,11 @@ class Gift extends RowModel
|
|||
$image->resize(512, 512, Image::SHRINK_ONLY);
|
||||
|
||||
$imgBlob = $image->toString(Image::PNG);
|
||||
} catch(ImageException $ex) {
|
||||
} catch (ImageException $ex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(strlen($imgBlob) > (2**24 - 1)) {
|
||||
if (strlen($imgBlob) > (2 ** 24 - 1)) {
|
||||
return false;
|
||||
} else {
|
||||
$this->stateChanges("updated", time());
|
||||
|
@ -127,18 +132,18 @@ class Gift extends RowModel
|
|||
return true;
|
||||
}
|
||||
|
||||
function setLimit(?float $limit = NULL, int $periodBehaviour = 0): void
|
||||
public function setLimit(?float $limit = null, int $periodBehaviour = 0): void
|
||||
{
|
||||
$limit ??= $this->getLimit();
|
||||
$limit = $limit === INF ? NULL : (int) $limit;
|
||||
$limit = $limit === INF ? null : (int) $limit;
|
||||
$this->stateChanges("limit", $limit);
|
||||
|
||||
if(!$limit) {
|
||||
$this->stateChanges("limit_period", NULL);
|
||||
if (!$limit) {
|
||||
$this->stateChanges("limit_period", null);
|
||||
return;
|
||||
}
|
||||
|
||||
switch($periodBehaviour) {
|
||||
switch ($periodBehaviour) {
|
||||
default:
|
||||
case static::PERIOD_IGNORE:
|
||||
break;
|
||||
|
@ -148,14 +153,15 @@ class Gift extends RowModel
|
|||
break;
|
||||
|
||||
case static::PERIOD_SET_IF_NONE:
|
||||
if(is_null($this->getRecord()) || is_null($this->getRecord()->limit_period))
|
||||
if (is_null($this->getRecord()) || is_null($this->getRecord()->limit_period)) {
|
||||
$this->stateChanges("limit_period", time());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function delete(bool $softly = true): void
|
||||
public function delete(bool $softly = true): void
|
||||
{
|
||||
$this->getRecord()->related("gift_relations.gift")->delete();
|
||||
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use Chandler\Database\DatabaseConnection as DB;
|
||||
use openvk\Web\Models\Repositories\Gifts;
|
||||
use openvk\Web\Models\RowModel;
|
||||
|
@ -18,8 +22,9 @@ class GiftCategory extends RowModel
|
|||
|
||||
private function createLocalizationIfNotExists(string $language): void
|
||||
{
|
||||
if(!is_null($this->getLocalization($language)->fetch()))
|
||||
if (!is_null($this->getLocalization($language)->fetch())) {
|
||||
return;
|
||||
}
|
||||
|
||||
DB::i()->getContext()->table("gift_categories_locales")->insert([
|
||||
"category" => $this->getId(),
|
||||
|
@ -29,7 +34,7 @@ class GiftCategory extends RowModel
|
|||
]);
|
||||
}
|
||||
|
||||
function getSlug(): string
|
||||
public function getSlug(): string
|
||||
{
|
||||
return str_replace("ʹ", "-", Transliterator::createFromRules(
|
||||
":: Any-Latin;"
|
||||
|
@ -42,22 +47,24 @@ class GiftCategory extends RowModel
|
|||
)->transliterate($this->getName()));
|
||||
}
|
||||
|
||||
function getThumbnailURL(): string
|
||||
public function getThumbnailURL(): string
|
||||
{
|
||||
$primeGift = iterator_to_array($this->getGifts(1, 1))[0];
|
||||
$serverUrl = ovk_scheme(true) . $_SERVER["SERVER_NAME"];
|
||||
if(!$primeGift)
|
||||
if (!$primeGift) {
|
||||
return "$serverUrl/assets/packages/static/openvk/img/camera_200.png";
|
||||
}
|
||||
|
||||
return $primeGift->getImage(Gift::IMAGE_URL);
|
||||
}
|
||||
|
||||
function getName(string $language = "_", bool $returnNull = false): ?string
|
||||
public function getName(string $language = "_", bool $returnNull = false): ?string
|
||||
{
|
||||
$loc = $this->getLocalization($language)->fetch();
|
||||
if(!$loc) {
|
||||
if($returnNull)
|
||||
return NULL;
|
||||
if (!$loc) {
|
||||
if ($returnNull) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $language === "_" ? "Unlocalized" : $this->getName();
|
||||
}
|
||||
|
@ -65,12 +72,13 @@ class GiftCategory extends RowModel
|
|||
return $loc->name;
|
||||
}
|
||||
|
||||
function getDescription(string $language = "_", bool $returnNull = false): ?string
|
||||
public function getDescription(string $language = "_", bool $returnNull = false): ?string
|
||||
{
|
||||
$loc = $this->getLocalization($language)->fetch();
|
||||
if(!$loc) {
|
||||
if($returnNull)
|
||||
return NULL;
|
||||
if (!$loc) {
|
||||
if ($returnNull) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $language === "_" ? "Unlocalized" : $this->getDescription();
|
||||
}
|
||||
|
@ -78,34 +86,36 @@ class GiftCategory extends RowModel
|
|||
return $loc->description;
|
||||
}
|
||||
|
||||
function getGifts(int $page = -1, ?int $perPage = NULL, &$count = nullptr): \Traversable
|
||||
public function getGifts(int $page = -1, ?int $perPage = null, &$count = nullptr): \Traversable
|
||||
{
|
||||
$gifts = $this->getRecord()->related("gift_relations.category");
|
||||
if($page !== -1) {
|
||||
if ($page !== -1) {
|
||||
$count = $gifts->count();
|
||||
$gifts = $gifts->page($page, $perPage ?? OPENVK_DEFAULT_PER_PAGE);
|
||||
}
|
||||
|
||||
foreach($gifts as $rel)
|
||||
yield (new Gifts)->get($rel->gift);
|
||||
foreach ($gifts as $rel) {
|
||||
yield (new Gifts())->get($rel->gift);
|
||||
}
|
||||
}
|
||||
|
||||
function isMagical(): bool
|
||||
public function isMagical(): bool
|
||||
{
|
||||
return !is_null($this->getRecord()->autoquery);
|
||||
}
|
||||
|
||||
function hasGift(Gift $gift): bool
|
||||
public function hasGift(Gift $gift): bool
|
||||
{
|
||||
$rels = $this->getRecord()->related("gift_relations.category");
|
||||
|
||||
return $rels->where("gift", $gift->getId())->count() > 0;
|
||||
}
|
||||
|
||||
function addGift(Gift $gift): void
|
||||
public function addGift(Gift $gift): void
|
||||
{
|
||||
if($this->hasGift($gift))
|
||||
if ($this->hasGift($gift)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DB::i()->getContext()->table("gift_relations")->insert([
|
||||
"category" => $this->getId(),
|
||||
|
@ -113,10 +123,11 @@ class GiftCategory extends RowModel
|
|||
]);
|
||||
}
|
||||
|
||||
function removeGift(Gift $gift): void
|
||||
public function removeGift(Gift $gift): void
|
||||
{
|
||||
if(!$this->hasGift($gift))
|
||||
if (!$this->hasGift($gift)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DB::i()->getContext()->table("gift_relations")->where([
|
||||
"category" => $this->getId(),
|
||||
|
@ -124,7 +135,7 @@ class GiftCategory extends RowModel
|
|||
])->delete();
|
||||
}
|
||||
|
||||
function setName(string $language, string $name): void
|
||||
public function setName(string $language, string $name): void
|
||||
{
|
||||
$this->createLocalizationIfNotExists($language);
|
||||
$this->getLocalization($language)->update([
|
||||
|
@ -132,7 +143,7 @@ class GiftCategory extends RowModel
|
|||
]);
|
||||
}
|
||||
|
||||
function setDescription(string $language, string $description): void
|
||||
public function setDescription(string $language, string $description): void
|
||||
{
|
||||
$this->createLocalizationIfNotExists($language);
|
||||
$this->getLocalization($language)->update([
|
||||
|
@ -140,16 +151,17 @@ class GiftCategory extends RowModel
|
|||
]);
|
||||
}
|
||||
|
||||
function setAutoQuery(?array $query = NULL): void
|
||||
public function setAutoQuery(?array $query = null): void
|
||||
{
|
||||
if(is_null($query)) {
|
||||
$this->stateChanges("autoquery", NULL);
|
||||
if (is_null($query)) {
|
||||
$this->stateChanges("autoquery", null);
|
||||
return;
|
||||
}
|
||||
|
||||
$allowedColumns = ["price", "usages"];
|
||||
if(array_diff_key($query, array_flip($allowedColumns)))
|
||||
if (array_diff_key($query, array_flip($allowedColumns))) {
|
||||
throw new \LogicException("Invalid query");
|
||||
}
|
||||
|
||||
$this->stateChanges("autoquery", serialize($query));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use openvk\Web\Models\RowModel;
|
||||
use openvk\Web\Util\DateTime;
|
||||
|
||||
|
@ -7,39 +11,39 @@ class IP extends RowModel
|
|||
{
|
||||
protected $tableName = "ip";
|
||||
|
||||
const RL_RESET = 0;
|
||||
const RL_CANEXEC = 1;
|
||||
const RL_VIOLATION = 2;
|
||||
const RL_BANNED = 3;
|
||||
public const RL_RESET = 0;
|
||||
public const RL_CANEXEC = 1;
|
||||
public const RL_VIOLATION = 2;
|
||||
public const RL_BANNED = 3;
|
||||
|
||||
function getIp(): string
|
||||
public function getIp(): string
|
||||
{
|
||||
return inet_ntop($this->getRecord()->ip);
|
||||
}
|
||||
|
||||
function getDiscoveryDate(): DateTime
|
||||
public function getDiscoveryDate(): DateTime
|
||||
{
|
||||
return new DateTime($this->getRecord()->first_seen);
|
||||
}
|
||||
|
||||
function isBanned(): bool
|
||||
public function isBanned(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->banned;
|
||||
}
|
||||
|
||||
function ban(): void
|
||||
public function ban(): void
|
||||
{
|
||||
$this->stateChanges("banned", true);
|
||||
$this->save();
|
||||
}
|
||||
|
||||
function pardon(): void
|
||||
public function pardon(): void
|
||||
{
|
||||
$this->stateChanges("banned", false);
|
||||
$this->save();
|
||||
}
|
||||
|
||||
function clear(): void
|
||||
public function clear(): void
|
||||
{
|
||||
$this->stateChanges("rate_limit_counter_start", 0);
|
||||
$this->stateChanges("rate_limit_counter", 0);
|
||||
|
@ -48,7 +52,7 @@ class IP extends RowModel
|
|||
$this->save();
|
||||
}
|
||||
|
||||
function rateLimit(int $actionComplexity = 1): int
|
||||
public function rateLimit(int $actionComplexity = 1): int
|
||||
{
|
||||
$counterSessionStart = $this->getRecord()->rate_limit_counter_start;
|
||||
$vCounterSessionStart = $this->getRecord()->rate_limit_violation_counter_start;
|
||||
|
@ -59,20 +63,20 @@ class IP extends RowModel
|
|||
$config = (object) OPENVK_ROOT_CONF["openvk"]["preferences"]["security"]["rateLimits"];
|
||||
|
||||
try {
|
||||
if((time() - $config->time) > $counterSessionStart) {
|
||||
if ((time() - $config->time) > $counterSessionStart) {
|
||||
$counterSessionStart = time();
|
||||
$aCounter = $actionComplexity;
|
||||
|
||||
return static::RL_RESET;
|
||||
}
|
||||
|
||||
if(($aCounter + $actionComplexity) <= $config->actions) {
|
||||
if (($aCounter + $actionComplexity) <= $config->actions) {
|
||||
$aCounter += $actionComplexity;
|
||||
|
||||
return static::RL_CANEXEC;
|
||||
}
|
||||
|
||||
if((time() - $config->maxViolationsAge) > $vCounterSessionStart) {
|
||||
if ((time() - $config->maxViolationsAge) > $vCounterSessionStart) {
|
||||
$vCounterSessionStart = time();
|
||||
$vCounter = 1;
|
||||
|
||||
|
@ -80,7 +84,7 @@ class IP extends RowModel
|
|||
}
|
||||
|
||||
$vCounter += 1;
|
||||
if($vCounter >= $config->maxViolations) {
|
||||
if ($vCounter >= $config->maxViolations) {
|
||||
$this->stateChanges("banned", true);
|
||||
|
||||
return static::RL_BANNED;
|
||||
|
@ -92,24 +96,26 @@ class IP extends RowModel
|
|||
$this->stateChanges("rate_limit_counter", $aCounter);
|
||||
$this->stateChanges("rate_limit_violation_counter_start", $vCounterSessionStart);
|
||||
$this->stateChanges("rate_limit_violation_counter", $vCounter);
|
||||
$this->save();
|
||||
$this->save(false);
|
||||
}
|
||||
}
|
||||
|
||||
function setIp(string $ip): void
|
||||
public function setIp(string $ip): void
|
||||
{
|
||||
$ip = inet_pton($ip);
|
||||
if(!$ip)
|
||||
if (!$ip) {
|
||||
throw new \UnexpectedValueException("Malformed IP address");
|
||||
}
|
||||
|
||||
$this->stateChanges("ip", $ip);
|
||||
}
|
||||
|
||||
function save(): void
|
||||
public function save(?bool $log = false): void
|
||||
{
|
||||
if(is_null($this->getRecord()))
|
||||
if (is_null($this->getRecord())) {
|
||||
$this->stateChanges("first_seen", time());
|
||||
}
|
||||
|
||||
parent::save();
|
||||
parent::save($log);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use openvk\Web\Util\DateTime;
|
||||
use openvk\Web\Models\RowModel;
|
||||
use openvk\Web\Models\Entities\{Photo, Message, Correspondence};
|
||||
|
@ -10,47 +14,46 @@ use Chandler\Security\User as ChandlerUser;
|
|||
|
||||
class Manager extends RowModel
|
||||
{
|
||||
use Traits\TSubscribable;
|
||||
protected $tableName = "group_coadmins";
|
||||
|
||||
function getId(): int
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->getRecord()->id;
|
||||
}
|
||||
|
||||
function getUserId(): int
|
||||
public function getUserId(): int
|
||||
{
|
||||
return $this->getRecord()->user;
|
||||
}
|
||||
|
||||
function getUser(): ?User
|
||||
public function getUser(): ?User
|
||||
{
|
||||
return (new Users)->get($this->getRecord()->user);
|
||||
return (new Users())->get($this->getRecord()->user);
|
||||
}
|
||||
|
||||
function getClubId(): int
|
||||
public function getClubId(): int
|
||||
{
|
||||
return $this->getRecord()->club;
|
||||
}
|
||||
|
||||
function getClub(): ?Club
|
||||
public function getClub(): ?Club
|
||||
{
|
||||
return (new Clubs)->get($this->getRecord()->club);
|
||||
return (new Clubs())->get($this->getRecord()->club);
|
||||
}
|
||||
|
||||
function getComment(): string
|
||||
public function getComment(): string
|
||||
{
|
||||
return is_null($this->getRecord()->comment) ? "" : $this->getRecord()->comment;
|
||||
}
|
||||
|
||||
function isHidden(): bool
|
||||
public function isHidden(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->hidden;
|
||||
}
|
||||
|
||||
function isClubPinned(): bool
|
||||
public function isClubPinned(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->club_pinned;
|
||||
}
|
||||
|
||||
use Traits\TSubscribable;
|
||||
}
|
||||
|
|
|
@ -1,29 +1,35 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use Nette\InvalidStateException as ISE;
|
||||
|
||||
abstract class Media extends Postable
|
||||
{
|
||||
protected $fileExtension = "oct"; #octet stream xddd
|
||||
protected $upperNodeReferenceColumnName = "owner";
|
||||
protected $processingPlaceholder = NULL;
|
||||
protected $processingPlaceholder = null;
|
||||
protected $processingTime = 30;
|
||||
|
||||
function __destruct()
|
||||
public function __destruct()
|
||||
{
|
||||
#Remove data, if model wasn't presisted
|
||||
if(isset($this->changes["hash"]))
|
||||
if (isset($this->changes["hash"])) {
|
||||
unlink($this->pathFromHash($this->changes["hash"]));
|
||||
}
|
||||
}
|
||||
|
||||
protected function getBaseDir(): string
|
||||
{
|
||||
$uploadSettings = OPENVK_ROOT_CONF["openvk"]["preferences"]["uploads"];
|
||||
if($uploadSettings["mode"] === "server" && $uploadSettings["server"]["kind"] === "cdn")
|
||||
if ($uploadSettings["mode"] === "server" && $uploadSettings["server"]["kind"] === "cdn") {
|
||||
return $uploadSettings["server"]["directory"];
|
||||
else
|
||||
} else {
|
||||
return OPENVK_ROOT . "/storage/";
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkIfFileIsProcessed(): bool
|
||||
{
|
||||
|
@ -35,26 +41,29 @@ abstract class Media extends Postable
|
|||
protected function pathFromHash(string $hash): string
|
||||
{
|
||||
$dir = $this->getBaseDir() . substr($hash, 0, 2);
|
||||
if(!is_dir($dir))
|
||||
if (!is_dir($dir)) {
|
||||
mkdir($dir);
|
||||
}
|
||||
|
||||
return "$dir/$hash." . $this->fileExtension;
|
||||
}
|
||||
|
||||
function getFileName(): string
|
||||
public function getFileName(): string
|
||||
{
|
||||
return $this->pathFromHash($this->getRecord()->hash);
|
||||
}
|
||||
|
||||
function getURL(): string
|
||||
public function getURL(): string
|
||||
{
|
||||
if(!is_null($this->processingPlaceholder))
|
||||
if(!$this->isProcessed())
|
||||
if (!is_null($this->processingPlaceholder)) {
|
||||
if (!$this->isProcessed()) {
|
||||
return "/assets/packages/static/openvk/$this->processingPlaceholder.$this->fileExtension";
|
||||
}
|
||||
}
|
||||
|
||||
$hash = $this->getRecord()->hash;
|
||||
|
||||
switch(OPENVK_ROOT_CONF["openvk"]["preferences"]["uploads"]["mode"]) {
|
||||
switch (OPENVK_ROOT_CONF["openvk"]["preferences"]["uploads"]["mode"]) {
|
||||
default:
|
||||
case "default":
|
||||
case "basic":
|
||||
|
@ -75,22 +84,25 @@ abstract class Media extends Postable
|
|||
}
|
||||
}
|
||||
|
||||
function getDescription(): ?string
|
||||
public function getDescription(): ?string
|
||||
{
|
||||
return $this->getRecord()->description;
|
||||
}
|
||||
|
||||
protected function isProcessed(): bool
|
||||
{
|
||||
if(is_null($this->processingPlaceholder))
|
||||
if (is_null($this->processingPlaceholder)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if($this->getRecord()->processed)
|
||||
if ($this->getRecord()->processed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$timeDiff = time() - $this->getRecord()->last_checked;
|
||||
if($timeDiff < $this->processingTime)
|
||||
if ($timeDiff < $this->processingTime) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$res = $this->checkIfFileIsProcessed();
|
||||
$this->stateChanges("last_checked", time());
|
||||
|
@ -100,20 +112,21 @@ abstract class Media extends Postable
|
|||
return $res;
|
||||
}
|
||||
|
||||
function isDeleted(): bool
|
||||
public function isDeleted(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->deleted;
|
||||
}
|
||||
|
||||
function setHash(string $hash): void
|
||||
public function setHash(string $hash): void
|
||||
{
|
||||
throw new ISE("Setting file hash manually is forbidden");
|
||||
}
|
||||
|
||||
function setFile(array $file): void
|
||||
public function setFile(array $file): void
|
||||
{
|
||||
if($file["error"] !== UPLOAD_ERR_OK)
|
||||
if ($file["error"] !== UPLOAD_ERR_OK) {
|
||||
throw new ISE("File uploaded is corrupted");
|
||||
}
|
||||
|
||||
$hash = hash_file("whirlpool", $file["tmp_name"]);
|
||||
$this->saveFile($file["tmp_name"], $hash);
|
||||
|
@ -121,29 +134,31 @@ abstract class Media extends Postable
|
|||
$this->stateChanges("hash", $hash);
|
||||
}
|
||||
|
||||
function save(): void
|
||||
public function save(?bool $log = false): void
|
||||
{
|
||||
if(!is_null($this->processingPlaceholder) && is_null($this->getRecord())) {
|
||||
if (!is_null($this->processingPlaceholder) && is_null($this->getRecord())) {
|
||||
$this->stateChanges("processed", 0);
|
||||
$this->stateChanges("last_checked", time());
|
||||
}
|
||||
|
||||
parent::save();
|
||||
parent::save($log);
|
||||
}
|
||||
|
||||
function delete(bool $softly = true): void
|
||||
public function delete(bool $softly = true): void
|
||||
{
|
||||
$deleteQuirk = ovkGetQuirk("blobs.erase-upon-deletion");
|
||||
if($deleteQuirk === 2 || ($deleteQuirk === 1 && !$softly))
|
||||
if ($deleteQuirk === 2 || ($deleteQuirk === 1 && !$softly)) {
|
||||
@unlink($this->getFileName());
|
||||
}
|
||||
|
||||
parent::delete($softly);
|
||||
}
|
||||
|
||||
function undelete(): void
|
||||
public function undelete(): void
|
||||
{
|
||||
if(ovkGetQuirk("blobs.erase-upon-deletion") === 2)
|
||||
if (ovkGetQuirk("blobs.erase-upon-deletion") === 2) {
|
||||
throw new \LogicException("Can't undelete model which is tied to blob, because of config constraint (quriks.yml:blobs.erase-upon-deletion)");
|
||||
}
|
||||
|
||||
parent::undelete();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use Nette\Database\Table\ActiveRow;
|
||||
use openvk\Web\Util\DateTime;
|
||||
use openvk\Web\Models\RowModel;
|
||||
|
@ -10,6 +14,7 @@ use Chandler\Database\DatabaseConnection;
|
|||
|
||||
abstract class MediaCollection extends RowModel
|
||||
{
|
||||
use Traits\TOwnable;
|
||||
protected $relTableName;
|
||||
protected $entityTableName;
|
||||
protected $entityClassName;
|
||||
|
@ -17,9 +22,19 @@ abstract class MediaCollection extends RowModel
|
|||
|
||||
protected $specialNames = [];
|
||||
|
||||
private $relations;
|
||||
protected $relations;
|
||||
|
||||
function __construct(?ActiveRow $ar = NULL)
|
||||
/**
|
||||
* Maximum amount of items Collection can have
|
||||
*/
|
||||
public const MAX_ITEMS = INF;
|
||||
|
||||
/**
|
||||
* Maximum amount of Collections with same "owner" allowed
|
||||
*/
|
||||
public const MAX_COUNT = INF;
|
||||
|
||||
public function __construct(?ActiveRow $ar = null)
|
||||
{
|
||||
parent::__construct($ar);
|
||||
|
||||
|
@ -28,96 +43,123 @@ abstract class MediaCollection extends RowModel
|
|||
|
||||
private function entitySuitable(RowModel $entity): bool
|
||||
{
|
||||
if(($class = get_class($entity)) !== $this->entityClassName)
|
||||
if (($class = get_class($entity)) !== $this->entityClassName) {
|
||||
throw new \UnexpectedValueException("This MediaCollection can only store '$this->entityClassName' (not '$class').");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getOwner(): RowModel
|
||||
public function getOwner(): RowModel
|
||||
{
|
||||
$oid = $this->getRecord()->owner;
|
||||
if($oid > 0)
|
||||
return (new Users)->get($oid);
|
||||
else
|
||||
return (new Clubs)->get($oid * -1);
|
||||
if ($oid > 0) {
|
||||
return (new Users())->get($oid);
|
||||
} else {
|
||||
return (new Clubs())->get($oid * -1);
|
||||
}
|
||||
}
|
||||
|
||||
function getPrettyId(): string
|
||||
public function getPrettyId(): string
|
||||
{
|
||||
return $this->getRecord()->owner . "_" . $this->getRecord()->id;
|
||||
}
|
||||
|
||||
function getName(): string
|
||||
public function getName(): string
|
||||
{
|
||||
$special = $this->getRecord()->special_type;
|
||||
if($special === 0)
|
||||
if ($special === 0) {
|
||||
return $this->getRecord()->name;
|
||||
}
|
||||
|
||||
$sName = $this->specialNames[$special];
|
||||
if(!$sName)
|
||||
if (!$sName) {
|
||||
return $this->getRecord()->name;
|
||||
}
|
||||
|
||||
if($sName[0] === "_")
|
||||
if ($sName[0] === "_") {
|
||||
$sName = tr(substr($sName, 1));
|
||||
}
|
||||
|
||||
return $sName;
|
||||
}
|
||||
|
||||
function getDescription(): ?string
|
||||
public function getDescription(): ?string
|
||||
{
|
||||
return $this->getRecord()->description;
|
||||
}
|
||||
|
||||
abstract function getCoverURL(): ?string;
|
||||
abstract public function getCoverURL(): ?string;
|
||||
|
||||
function fetch(int $page = 1, ?int $perPage = NULL): \Traversable
|
||||
public function fetchClassic(int $offset = 0, ?int $limit = null): \Traversable
|
||||
{
|
||||
$related = $this->getRecord()->related("$this->relTableName.collection")->page($page, $perPage ?? OPENVK_DEFAULT_PER_PAGE)->order("media ASC");
|
||||
foreach($related as $rel) {
|
||||
$related = $this->getRecord()->related("$this->relTableName.collection")
|
||||
->limit($limit ?? OPENVK_DEFAULT_PER_PAGE, $offset)
|
||||
->order("media ASC");
|
||||
|
||||
foreach ($related as $rel) {
|
||||
$media = $rel->ref($this->entityTableName, "media");
|
||||
if(!$media)
|
||||
if (!$media) {
|
||||
continue;
|
||||
}
|
||||
|
||||
yield new $this->entityClassName($media);
|
||||
}
|
||||
}
|
||||
|
||||
function size(): int
|
||||
public function fetch(int $page = 1, ?int $perPage = null): \Traversable
|
||||
{
|
||||
$page = max(1, $page);
|
||||
$perPage ??= OPENVK_DEFAULT_PER_PAGE;
|
||||
|
||||
return $this->fetchClassic($perPage * ($page - 1), $perPage);
|
||||
}
|
||||
|
||||
public function size(): int
|
||||
{
|
||||
return sizeof($this->getRecord()->related("$this->relTableName.collection"));
|
||||
}
|
||||
|
||||
function getCreationTime(): DateTime
|
||||
public function getCreationTime(): DateTime
|
||||
{
|
||||
return new DateTime($this->getRecord()->created);
|
||||
}
|
||||
|
||||
function getPublicationTime(): DateTime
|
||||
public function getPublicationTime(): DateTime
|
||||
{
|
||||
return $this->getCreationTime();
|
||||
}
|
||||
|
||||
function getEditTime(): ?DateTime
|
||||
public function getEditTime(): ?DateTime
|
||||
{
|
||||
$edited = $this->getRecord()->edited;
|
||||
if(is_null($edited)) return NULL;
|
||||
if (is_null($edited)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new DateTime($edited);
|
||||
}
|
||||
|
||||
function isCreatedBySystem(): bool
|
||||
public function isCreatedBySystem(): bool
|
||||
{
|
||||
return $this->getRecord()->special_type !== 0;
|
||||
}
|
||||
|
||||
function add(RowModel $entity): bool
|
||||
public function add(RowModel $entity): bool
|
||||
{
|
||||
$this->entitySuitable($entity);
|
||||
|
||||
if(!$this->allowDuplicates)
|
||||
if($this->has($entity))
|
||||
if (!$this->allowDuplicates) {
|
||||
if ($this->has($entity)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (self::MAX_ITEMS != INF) {
|
||||
if (sizeof($this->relations->where("collection", $this->getId())) > self::MAX_ITEMS) {
|
||||
throw new \OutOfBoundsException("Collection is full");
|
||||
}
|
||||
}
|
||||
|
||||
$this->relations->insert([
|
||||
"collection" => $this->getId(),
|
||||
|
@ -127,17 +169,17 @@ abstract class MediaCollection extends RowModel
|
|||
return true;
|
||||
}
|
||||
|
||||
function remove(RowModel $entity): void
|
||||
public function remove(RowModel $entity): bool
|
||||
{
|
||||
$this->entitySuitable($entity);
|
||||
|
||||
$this->relations->where([
|
||||
return $this->relations->where([
|
||||
"collection" => $this->getId(),
|
||||
"media" => $entity->getId(),
|
||||
])->delete();
|
||||
])->delete() > 0;
|
||||
}
|
||||
|
||||
function has(RowModel $entity): bool
|
||||
public function has(RowModel $entity): bool
|
||||
{
|
||||
$this->entitySuitable($entity);
|
||||
|
||||
|
@ -149,5 +191,35 @@ abstract class MediaCollection extends RowModel
|
|||
return !is_null($rel);
|
||||
}
|
||||
|
||||
use Traits\TOwnable;
|
||||
public function save(?bool $log = false): void
|
||||
{
|
||||
$thisTable = DatabaseConnection::i()->getContext()->table($this->tableName);
|
||||
if (self::MAX_COUNT != INF) {
|
||||
if (isset($this->changes["owner"])) {
|
||||
if (sizeof($thisTable->where("owner", $this->changes["owner"])) > self::MAX_COUNT) {
|
||||
throw new \OutOfBoundsException("Maximum amount of collections");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_null($this->getRecord())) {
|
||||
if (!isset($this->changes["created"])) {
|
||||
$this->stateChanges("created", time());
|
||||
} else {
|
||||
$this->stateChanges("edited", time());
|
||||
}
|
||||
}
|
||||
|
||||
parent::save($log);
|
||||
}
|
||||
|
||||
public function delete(bool $softly = true): void
|
||||
{
|
||||
if (!$softly) {
|
||||
$this->relations->where("collection", $this->getId())
|
||||
->delete();
|
||||
}
|
||||
|
||||
parent::delete($softly);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
use openvk\Web\Models\Repositories\Clubs;
|
||||
use openvk\Web\Models\Repositories\Users;
|
||||
|
@ -12,6 +16,8 @@ use openvk\Web\Util\DateTime;
|
|||
*/
|
||||
class Message extends RowModel
|
||||
{
|
||||
use Traits\TRichText;
|
||||
use Traits\TAttachmentHost;
|
||||
protected $tableName = "messages";
|
||||
|
||||
/**
|
||||
|
@ -21,12 +27,13 @@ class Message extends RowModel
|
|||
*
|
||||
* @returns User|Club
|
||||
*/
|
||||
function getSender(): ?RowModel
|
||||
public function getSender(): ?RowModel
|
||||
{
|
||||
if($this->getRecord()->sender_type === 'openvk\Web\Models\Entities\User')
|
||||
return (new Users)->get($this->getRecord()->sender_id);
|
||||
else if($this->getRecord()->sender_type === 'openvk\Web\Models\Entities\Club')
|
||||
return (new Clubs)->get($this->getRecord()->sender_id);
|
||||
if ($this->getRecord()->sender_type === 'openvk\Web\Models\Entities\User') {
|
||||
return (new Users())->get($this->getRecord()->sender_id);
|
||||
} elseif ($this->getRecord()->sender_type === 'openvk\Web\Models\Entities\Club') {
|
||||
return (new Clubs())->get($this->getRecord()->sender_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -36,15 +43,16 @@ class Message extends RowModel
|
|||
*
|
||||
* @returns User|Club
|
||||
*/
|
||||
function getRecipient(): ?RowModel
|
||||
public function getRecipient(): ?RowModel
|
||||
{
|
||||
if($this->getRecord()->recipient_type === 'openvk\Web\Models\Entities\User')
|
||||
return (new Users)->get($this->getRecord()->recipient_id);
|
||||
else if($this->getRecord()->recipient_type === 'openvk\Web\Models\Entities\Club')
|
||||
return (new Clubs)->get($this->getRecord()->recipient_id);
|
||||
if ($this->getRecord()->recipient_type === 'openvk\Web\Models\Entities\User') {
|
||||
return (new Users())->get($this->getRecord()->recipient_id);
|
||||
} elseif ($this->getRecord()->recipient_type === 'openvk\Web\Models\Entities\Club') {
|
||||
return (new Clubs())->get($this->getRecord()->recipient_id);
|
||||
}
|
||||
}
|
||||
|
||||
function getUnreadState(): int
|
||||
public function getUnreadState(): int
|
||||
{
|
||||
trigger_error("TODO: use isUnread", E_USER_DEPRECATED);
|
||||
|
||||
|
@ -56,17 +64,17 @@ class Message extends RowModel
|
|||
*
|
||||
* @returns DateTime
|
||||
*/
|
||||
function getSendTime(): DateTime
|
||||
public function getSendTime(): DateTime
|
||||
{
|
||||
return new DateTime($this->getRecord()->created);
|
||||
}
|
||||
|
||||
function getSendTimeHumanized(): string
|
||||
public function getSendTimeHumanized(): string
|
||||
{
|
||||
$dateTime = new DateTime($this->getRecord()->created);
|
||||
|
||||
if($dateTime->format("%d.%m.%y") == ovk_strftime_safe("%d.%m.%y", time())) {
|
||||
return $dateTime->format("%T %p");
|
||||
if ($dateTime->format("%d.%m.%y") == ovk_strftime_safe("%d.%m.%y", time())) {
|
||||
return $dateTime->format("%T");
|
||||
} else {
|
||||
return $dateTime->format("%d.%m.%y");
|
||||
}
|
||||
|
@ -77,10 +85,12 @@ class Message extends RowModel
|
|||
*
|
||||
* @returns DateTime|null
|
||||
*/
|
||||
function getEditTime(): ?DateTime
|
||||
public function getEditTime(): ?DateTime
|
||||
{
|
||||
$edited = $this->getRecord()->edited;
|
||||
if(is_null($edited)) return NULL;
|
||||
if (is_null($edited)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new DateTime($edited);
|
||||
}
|
||||
|
@ -92,12 +102,12 @@ class Message extends RowModel
|
|||
*
|
||||
* @returns false
|
||||
*/
|
||||
function isAd(): bool
|
||||
public function isAd(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
function isUnread(): bool
|
||||
public function isUnread(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->unread;
|
||||
}
|
||||
|
@ -107,13 +117,13 @@ class Message extends RowModel
|
|||
*
|
||||
* @returns array
|
||||
*/
|
||||
function simplify(): array
|
||||
public function simplify(): array
|
||||
{
|
||||
$author = $this->getSender();
|
||||
|
||||
$attachments = [];
|
||||
foreach($this->getChildren() as $attachment) {
|
||||
if($attachment instanceof Photo) {
|
||||
foreach ($this->getChildren() as $attachment) {
|
||||
if ($attachment instanceof Photo) {
|
||||
$attachments[] = [
|
||||
"type" => "photo",
|
||||
"link" => "/photo" . $attachment->getPrettyId(),
|
||||
|
@ -123,7 +133,11 @@ class Message extends RowModel
|
|||
],
|
||||
];
|
||||
} else {
|
||||
throw new \Exception("Unknown attachment type: " . get_class($attachment));
|
||||
$attachments[] = [
|
||||
"type" => "unknown",
|
||||
];
|
||||
|
||||
# throw new \Exception("Unknown attachment type: " . get_class($attachment));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,18 +147,15 @@ class Message extends RowModel
|
|||
"id" => $author->getId(),
|
||||
"link" => $_SERVER['REQUEST_SCHEME'] . "://" . $_SERVER['HTTP_HOST'] . $author->getURL(),
|
||||
"avatar" => $author->getAvatarUrl(),
|
||||
"name" => $author->getFirstName().$unreadmsg,
|
||||
"name" => $author->getFirstName() . $unreadmsg,
|
||||
],
|
||||
"timing" => [
|
||||
"sent" => (string) $this->getSendTimeHumanized(),
|
||||
"edited" => is_null($this->getEditTime()) ? NULL : (string) $this->getEditTime(),
|
||||
"edited" => is_null($this->getEditTime()) ? null : (string) $this->getEditTime(),
|
||||
],
|
||||
"text" => $this->getText(),
|
||||
"read" => !$this->isUnread(),
|
||||
"attachments" => $attachments,
|
||||
];
|
||||
}
|
||||
|
||||
use Traits\TRichText;
|
||||
use Traits\TAttachmentHost;
|
||||
}
|
||||
|
|
75
Web/Models/Entities/NoSpamLog.php
Normal file
75
Web/Models/Entities/NoSpamLog.php
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use openvk\Web\Models\RowModel;
|
||||
use openvk\Web\Util\DateTime;
|
||||
use openvk\Web\Models\Repositories\{Users};
|
||||
use Nette\Database\Table\ActiveRow;
|
||||
|
||||
class NoSpamLog extends RowModel
|
||||
{
|
||||
protected $tableName = "noSpam_templates";
|
||||
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->getRecord()->id;
|
||||
}
|
||||
|
||||
public function getUser(): ?User
|
||||
{
|
||||
return (new Users())->get($this->getRecord()->user);
|
||||
}
|
||||
|
||||
public function getModel(): string
|
||||
{
|
||||
return $this->getRecord()->model;
|
||||
}
|
||||
|
||||
public function getRegex(): ?string
|
||||
{
|
||||
return $this->getRecord()->regex;
|
||||
}
|
||||
|
||||
public function getRequest(): ?string
|
||||
{
|
||||
return $this->getRecord()->request;
|
||||
}
|
||||
|
||||
public function getCount(): int
|
||||
{
|
||||
return $this->getRecord()->count;
|
||||
}
|
||||
|
||||
public function getTime(): DateTime
|
||||
{
|
||||
return new DateTime($this->getRecord()->time);
|
||||
}
|
||||
|
||||
public function getItems(): ?array
|
||||
{
|
||||
return explode(",", $this->getRecord()->items);
|
||||
}
|
||||
|
||||
public function getTypeRaw(): int
|
||||
{
|
||||
return $this->getRecord()->ban_type;
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
switch ($this->getTypeRaw()) {
|
||||
case 1: return "О";
|
||||
case 2: return "Б";
|
||||
case 3: return "ОБ";
|
||||
default: return (string) $this->getTypeRaw();
|
||||
}
|
||||
}
|
||||
|
||||
public function isRollbacked(): bool
|
||||
{
|
||||
return !is_null($this->getRecord()->rollback);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use HTMLPurifier_Config;
|
||||
use HTMLPurifier;
|
||||
|
||||
|
@ -75,12 +79,13 @@ class Note extends Postable
|
|||
"underline",
|
||||
]);
|
||||
|
||||
$source = NULL;
|
||||
if(is_null($this->getRecord())) {
|
||||
if(isset($this->changes["source"]))
|
||||
$source = null;
|
||||
if (is_null($this->getRecord())) {
|
||||
if (isset($this->changes["source"])) {
|
||||
$source = $this->changes["source"];
|
||||
else
|
||||
} else {
|
||||
throw new \LogicException("Can't render note without content set.");
|
||||
}
|
||||
} else {
|
||||
$source = $this->getRecord()->source;
|
||||
}
|
||||
|
@ -89,23 +94,24 @@ class Note extends Postable
|
|||
return $purifier->purify($source);
|
||||
}
|
||||
|
||||
function getName(): string
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->getRecord()->name;
|
||||
}
|
||||
|
||||
function getPreview(int $length = 25): string
|
||||
public function getPreview(int $length = 25): string
|
||||
{
|
||||
return ovk_proc_strtr(strip_tags($this->getRecord()->source), $length);
|
||||
}
|
||||
|
||||
function getText(): string
|
||||
public function getText(): string
|
||||
{
|
||||
if(is_null($this->getRecord()))
|
||||
if (is_null($this->getRecord())) {
|
||||
return $this->renderHTML();
|
||||
}
|
||||
|
||||
$cached = $this->getRecord()->cached_content;
|
||||
if(!$cached) {
|
||||
if (!$cached) {
|
||||
$cached = $this->renderHTML();
|
||||
$this->setCached_Content($cached);
|
||||
$this->save();
|
||||
|
@ -114,24 +120,33 @@ class Note extends Postable
|
|||
return $cached;
|
||||
}
|
||||
|
||||
function getSource(): string
|
||||
public function getSource(): string
|
||||
{
|
||||
return $this->getRecord()->source;
|
||||
}
|
||||
|
||||
function toVkApiStruct(): object
|
||||
public function canBeViewedBy(?User $user = null): bool
|
||||
{
|
||||
if ($this->isDeleted() || $this->getOwner()->isDeleted()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->getOwner()->getPrivacyPermission('notes.read', $user) && $this->getOwner()->canBeViewedBy($user);
|
||||
}
|
||||
|
||||
public function toVkApiStruct(): object
|
||||
{
|
||||
$res = (object) [];
|
||||
|
||||
$res->type = "note";
|
||||
$res->id = $this->getId();
|
||||
$res->id = $this->getVirtualId();
|
||||
$res->owner_id = $this->getOwner()->getId();
|
||||
$res->title = $this->getName();
|
||||
$res->text = $this->getText();
|
||||
$res->date = $this->getPublicationTime()->timestamp();
|
||||
$res->comments = $this->getCommentsCount();
|
||||
$res->read_comments = $this->getCommentsCount();
|
||||
$res->view_url = "/note".$this->getOwner()->getId()."_".$this->getId();
|
||||
$res->view_url = "/note" . $this->getOwner()->getId() . "_" . $this->getVirtualId();
|
||||
$res->privacy_view = 1;
|
||||
$res->can_comment = 1;
|
||||
$res->text_wiki = "r";
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities\Notifications;
|
||||
|
||||
use openvk\Web\Models\Entities\{User, Club};
|
||||
|
||||
final class ClubModeratorNotification extends Notification
|
||||
{
|
||||
protected $actionCode = 5;
|
||||
|
||||
function __construct(User $recipient, Club $group, User $admin)
|
||||
public function __construct(User $recipient, Club $group, User $admin)
|
||||
{
|
||||
parent::__construct($recipient, $group, $admin, time(), "");
|
||||
}
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities\Notifications;
|
||||
|
||||
use openvk\Web\Models\Entities\User;
|
||||
|
||||
final class CoinsTransferNotification extends Notification
|
||||
{
|
||||
protected $actionCode = 9602;
|
||||
|
||||
function __construct(User $receiver, User $sender, int $value, string $message)
|
||||
public function __construct(User $receiver, User $sender, int $value, string $message)
|
||||
{
|
||||
parent::__construct($receiver, $receiver, $sender, time(), $value . " " . $message);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities\Notifications;
|
||||
|
||||
use openvk\Web\Models\Entities\{User, Post, Comment};
|
||||
|
||||
final class CommentNotification extends Notification
|
||||
{
|
||||
protected $actionCode = 2;
|
||||
|
||||
function __construct(User $recipient, Comment $comment, $postable, User $commenter)
|
||||
public function __construct(User $recipient, Comment $comment, $postable, User $commenter)
|
||||
{
|
||||
parent::__construct($recipient, $postable, $commenter, time(), ovk_proc_strtr(strip_tags($comment->getText()), 400));
|
||||
}
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities\Notifications;
|
||||
|
||||
use openvk\Web\Models\Entities\User;
|
||||
|
||||
final class FriendRemovalNotification extends Notification
|
||||
{
|
||||
protected $actionCode = 4;
|
||||
|
||||
function __construct(User $recipient, User $friend, User $remover)
|
||||
public function __construct(User $recipient, User $friend, User $remover)
|
||||
{
|
||||
parent::__construct($recipient, $friend, $remover, time(), "");
|
||||
}
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities\Notifications;
|
||||
|
||||
use openvk\Web\Models\Entities\{User, Gift};
|
||||
|
||||
final class GiftNotification extends Notification
|
||||
{
|
||||
protected $actionCode = 9601;
|
||||
|
||||
function __construct(User $receiver, User $sender, Gift $gift, ?string $comment)
|
||||
public function __construct(User $receiver, User $sender, Gift $gift, ?string $comment)
|
||||
{
|
||||
parent::__construct($receiver, $gift, $sender, time(), $comment ?? "");
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities\Notifications;
|
||||
|
||||
use openvk\Web\Models\Entities\{User, Post};
|
||||
|
||||
final class LikeNotification extends Notification
|
||||
|
@ -7,7 +11,7 @@ final class LikeNotification extends Notification
|
|||
protected $actionCode = 0;
|
||||
protected $threshold = 120;
|
||||
|
||||
function __construct(User $recipient, Post $post, User $liker)
|
||||
public function __construct(User $recipient, Post $post, User $liker)
|
||||
{
|
||||
parent::__construct($recipient, $post, $liker, time(), "");
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities\Notifications;
|
||||
|
||||
use openvk\Web\Models\Entities\Postable;
|
||||
use openvk\Web\Models\Entities\User;
|
||||
|
||||
|
@ -7,7 +11,7 @@ final class MentionNotification extends Notification
|
|||
{
|
||||
protected $actionCode = 4;
|
||||
|
||||
function __construct(User $recipient, Postable $discussionHost, $mentioner, string $quote = "")
|
||||
public function __construct(User $recipient, Postable $discussionHost, $mentioner, string $quote = "")
|
||||
{
|
||||
parent::__construct($recipient, $mentioner, $discussionHost, time(), $quote);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities\Notifications;
|
||||
|
||||
use openvk\Web\Models\Entities\{User, Club};
|
||||
|
||||
final class NewSuggestedPostsNotification extends Notification
|
||||
{
|
||||
protected $actionCode = 7;
|
||||
|
||||
public function __construct(User $owner, Club $group)
|
||||
{
|
||||
parent::__construct($owner, $owner, $group, time(), "");
|
||||
}
|
||||
}
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities\Notifications;
|
||||
|
||||
use openvk\Web\Models\RowModel;
|
||||
use openvk\Web\Models\Entities\{User};
|
||||
use openvk\Web\Util\DateTime;
|
||||
|
@ -13,10 +17,10 @@ class Notification
|
|||
private $time;
|
||||
private $data;
|
||||
|
||||
protected $actionCode = NULL;
|
||||
protected $actionCode = null;
|
||||
protected $threshold = -1;
|
||||
|
||||
function __construct(User $recipient, $originModel, $targetModel, ?int $time = NULL, string $data = "")
|
||||
public function __construct(User $recipient, $originModel, $targetModel, ?int $time = null, string $data = "")
|
||||
{
|
||||
$this->recipient = $recipient;
|
||||
$this->originModel = $originModel;
|
||||
|
@ -30,39 +34,39 @@ class Notification
|
|||
return (int) json_decode(file_get_contents(__DIR__ . "/../../../../data/modelCodes.json"), true)[get_class($model)];
|
||||
}
|
||||
|
||||
function reverseModelOrder(): bool
|
||||
public function reverseModelOrder(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
function getActionCode(): int
|
||||
public function getActionCode(): int
|
||||
{
|
||||
return $this->actionCode;
|
||||
}
|
||||
|
||||
function setActionCode(int $code): void
|
||||
public function setActionCode(int $code): void
|
||||
{
|
||||
$this->actionCode = $this->actionCode ?? $code;
|
||||
$this->actionCode ??= $code;
|
||||
}
|
||||
|
||||
function getTemplatePath(): string
|
||||
public function getTemplatePath(): string
|
||||
{
|
||||
return implode("_", [
|
||||
"./../components/notifications/$this->actionCode/",
|
||||
$this->encodeType($this->originModel),
|
||||
$this->encodeType($this->targetModel),
|
||||
".xml"
|
||||
".xml",
|
||||
]);
|
||||
}
|
||||
|
||||
function getRecipient(): User
|
||||
public function getRecipient(): User
|
||||
{
|
||||
return $this->recipient;
|
||||
}
|
||||
|
||||
function getModel(int $index): RowModel
|
||||
public function getModel(int $index): RowModel
|
||||
{
|
||||
switch($index) {
|
||||
switch ($index) {
|
||||
case 0:
|
||||
return $this->originModel;
|
||||
case 1:
|
||||
|
@ -70,20 +74,21 @@ class Notification
|
|||
}
|
||||
}
|
||||
|
||||
function getData(): string
|
||||
public function getData(): string
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
function getDateTime(): DateTime
|
||||
public function getDateTime(): DateTime
|
||||
{
|
||||
return new DateTime($this->time);
|
||||
}
|
||||
|
||||
function emit(): bool
|
||||
public function emit(): bool
|
||||
{
|
||||
if(!($e = eventdb()))
|
||||
if (!($e = eventdb())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$data = [
|
||||
"recipient" => $this->recipient->getId(),
|
||||
|
@ -97,20 +102,21 @@ class Notification
|
|||
];
|
||||
|
||||
$edb = $e->getConnection();
|
||||
if($this->threshold !== -1) {
|
||||
if ($this->threshold !== -1) {
|
||||
# Event is thersholded, check if there is similar event
|
||||
$query = <<<'QUERY'
|
||||
SELECT * FROM `notifications` WHERE `recipientType`=0 AND `recipientId`=? AND `originModelType`=? AND `originModelId`=? AND `targetModelType`=? AND `targetModelId`=? AND `modelAction`=? AND `additionalData`=? AND `timestamp` > (? - ?)
|
||||
QUERY;
|
||||
QUERY;
|
||||
$result = $edb->query($query, ...array_merge(array_values($data), [ $this->threshold ]));
|
||||
if($result->getRowCount() > 0)
|
||||
if ($result->getRowCount() > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$edb->query("INSERT INTO notifications VALUES (0, ?, ?, ?, ?, ?, ?, ?, ?)", ...array_values($data));
|
||||
|
||||
$kafkaConf = OPENVK_ROOT_CONF["openvk"]["credentials"]["notificationsBroker"];
|
||||
if($kafkaConf["enable"]) {
|
||||
if ($kafkaConf["enable"]) {
|
||||
$kafkaConf = $kafkaConf["kafka"];
|
||||
$brokerConf = new Conf();
|
||||
$brokerConf->set("log_level", (string) LOG_DEBUG);
|
||||
|
@ -132,4 +138,138 @@ QUERY;
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getVkApiInfo()
|
||||
{
|
||||
$origin_m = $this->encodeType($this->originModel);
|
||||
$target_m = $this->encodeType($this->targetModel);
|
||||
|
||||
$info = [
|
||||
"type" => "",
|
||||
"parent" => null,
|
||||
"feedback" => null,
|
||||
];
|
||||
|
||||
switch ($this->getActionCode()) {
|
||||
case 0:
|
||||
$info["type"] = "like_post";
|
||||
$info["parent"] = $this->getModel(0)->toNotifApiStruct();
|
||||
$info["feedback"] = $this->getModel(1)->toVkApiStruct();
|
||||
break;
|
||||
case 1:
|
||||
$info["type"] = "copy_post";
|
||||
$info["parent"] = $this->getModel(0)->toNotifApiStruct();
|
||||
$info["feedback"] = null; # todo
|
||||
break;
|
||||
case 2:
|
||||
switch ($origin_m) {
|
||||
case 19:
|
||||
$info["type"] = "comment_video";
|
||||
$info["parent"] = $this->getModel(0)->toNotifApiStruct();
|
||||
$info["feedback"] = null; # айди коммента не сохраняется в бд( ну пиздец блять
|
||||
break;
|
||||
case 13:
|
||||
$info["type"] = "comment_photo";
|
||||
$info["parent"] = $this->getModel(0)->toNotifApiStruct();
|
||||
$info["feedback"] = null;
|
||||
break;
|
||||
# unstandart (vk forgor about notes)
|
||||
case 10:
|
||||
$info["type"] = "comment_note";
|
||||
$info["parent"] = $this->getModel(0)->toVkApiStruct();
|
||||
$info["feedback"] = null;
|
||||
break;
|
||||
case 14:
|
||||
$info["type"] = "comment_post";
|
||||
$info["parent"] = $this->getModel(0)->toNotifApiStruct();
|
||||
$info["feedback"] = null;
|
||||
break;
|
||||
# unused (users don't have topics bruh)
|
||||
case 21:
|
||||
$info["type"] = "comment_topic";
|
||||
$info["parent"] = $this->getModel(0)->toVkApiStruct(0, 90);
|
||||
break;
|
||||
default:
|
||||
$info["type"] = "comment_unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case 3:
|
||||
$info["type"] = "wall";
|
||||
$info["feedback"] = $this->getModel(0)->toNotifApiStruct();
|
||||
break;
|
||||
case 4:
|
||||
switch ($target_m) {
|
||||
case 14:
|
||||
$info["type"] = "mention";
|
||||
$info["feedback"] = $this->getModel(1)->toNotifApiStruct();
|
||||
break;
|
||||
case 19:
|
||||
$info["type"] = "mention_comment_video";
|
||||
$info["parent"] = $this->getModel(1)->toNotifApiStruct();
|
||||
break;
|
||||
case 13:
|
||||
$info["type"] = "mention_comment_photo";
|
||||
$info["parent"] = $this->getModel(1)->toNotifApiStruct();
|
||||
break;
|
||||
# unstandart
|
||||
case 10:
|
||||
$info["type"] = "mention_comment_note";
|
||||
$info["parent"] = $this->getModel(1)->toVkApiStruct();
|
||||
break;
|
||||
case 21:
|
||||
$info["type"] = "mention_comments";
|
||||
break;
|
||||
default:
|
||||
$info["type"] = "mention_comment_unknown";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
$info["type"] = "make_you_admin";
|
||||
$info["parent"] = $this->getModel(0)->toVkApiStruct($this->getModel(1));
|
||||
break;
|
||||
# Нужно доделать после мержа #935
|
||||
case 6:
|
||||
$info["type"] = "wall_publish";
|
||||
break;
|
||||
# В вк не было такого уведомления, так что unstandart
|
||||
case 7:
|
||||
$info["type"] = "new_posts_in_club";
|
||||
break;
|
||||
# В вк при передаче подарков приходит сообщение, а не уведомление, так что unstandart
|
||||
case 9601:
|
||||
$info["type"] = "sent_gift";
|
||||
$info["parent"] = $this->getModel(1)->toVkApiStruct($this->getModel(1));
|
||||
break;
|
||||
case 9602:
|
||||
$info["type"] = "voices_transfer";
|
||||
$info["parent"] = $this->getModel(1)->toVkApiStruct($this->getModel(1));
|
||||
break;
|
||||
case 9603:
|
||||
$info["type"] = "up_rating";
|
||||
$info["parent"] = $this->getModel(1)->toVkApiStruct($this->getModel(1));
|
||||
$info["parent"]->count = $this->getData();
|
||||
break;
|
||||
default:
|
||||
$info["type"] = null;
|
||||
break;
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
public function toVkApiStruct()
|
||||
{
|
||||
$res = (object) [];
|
||||
|
||||
$info = $this->getVkApiInfo();
|
||||
$res->type = $info["type"];
|
||||
$res->date = $this->getDateTime()->timestamp();
|
||||
$res->parent = $info["parent"];
|
||||
$res->feedback = $info["feedback"];
|
||||
$res->reply = null; # Ответы на комментарии не реализованы
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities\Notifications;
|
||||
|
||||
use openvk\Web\Models\Entities\{User, Club, Post};
|
||||
|
||||
final class PostAcceptedNotification extends Notification
|
||||
{
|
||||
protected $actionCode = 6;
|
||||
|
||||
public function __construct(User $author, Post $post, Club $group)
|
||||
{
|
||||
parent::__construct($author, $post, $group, time(), "");
|
||||
}
|
||||
}
|
|
@ -1,12 +1,16 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities\Notifications;
|
||||
|
||||
use openvk\Web\Models\Entities\User;
|
||||
|
||||
final class RatingUpNotification extends Notification
|
||||
{
|
||||
protected $actionCode = 9603;
|
||||
|
||||
function __construct(User $receiver, User $sender, int $value, string $message)
|
||||
public function __construct(User $receiver, User $sender, int $value, string $message)
|
||||
{
|
||||
parent::__construct($receiver, $receiver, $sender, time(), $value . " " . $message);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities\Notifications;
|
||||
|
||||
use openvk\Web\Models\Entities\{User, Post};
|
||||
|
||||
final class RepostNotification extends Notification
|
||||
|
@ -7,7 +11,7 @@ final class RepostNotification extends Notification
|
|||
protected $actionCode = 1;
|
||||
protected $threshold = 120;
|
||||
|
||||
function __construct(User $recipient, Post $post, User $reposter)
|
||||
public function __construct(User $recipient, Post $post, User $reposter)
|
||||
{
|
||||
parent::__construct($recipient, $post, $reposter, time(), "");
|
||||
}
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities\Notifications;
|
||||
|
||||
use openvk\Web\Models\Entities\{User, Post};
|
||||
|
||||
final class WallPostNotification extends Notification
|
||||
{
|
||||
protected $actionCode = 3;
|
||||
|
||||
function __construct(User $recipient, Post $post, User $poster)
|
||||
public function __construct(User $recipient, Post $post, User $poster)
|
||||
{
|
||||
parent::__construct($recipient, $post, $poster, time(), ovk_proc_strtr($post->getText(), 10));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use openvk\Web\Models\Repositories\Users;
|
||||
use openvk\Web\Models\RowModel;
|
||||
use openvk\Web\Util\DateTime;
|
||||
|
@ -8,22 +12,22 @@ class PasswordReset extends RowModel
|
|||
{
|
||||
protected $tableName = "password_resets";
|
||||
|
||||
function getUser(): User
|
||||
public function getUser(): User
|
||||
{
|
||||
return (new Users)->get($this->getRecord()->profile);
|
||||
return (new Users())->get($this->getRecord()->profile);
|
||||
}
|
||||
|
||||
function getKey(): string
|
||||
public function getKey(): string
|
||||
{
|
||||
return $this->getRecord()->key;
|
||||
}
|
||||
|
||||
function getToken(): string
|
||||
public function getToken(): string
|
||||
{
|
||||
return $this->getKey();
|
||||
}
|
||||
|
||||
function getCreationTime(): DateTime
|
||||
public function getCreationTime(): DateTime
|
||||
{
|
||||
return new DateTime($this->getRecord()->timestamp);
|
||||
}
|
||||
|
@ -32,7 +36,7 @@ class PasswordReset extends RowModel
|
|||
* User can request password reset only if he does not have any "new" password resets.
|
||||
* Password reset becomes "old" after 5 minutes and one second.
|
||||
*/
|
||||
function isNew(): bool
|
||||
public function isNew(): bool
|
||||
{
|
||||
return $this->getRecord()->timestamp > (time() - (5 * MINUTE));
|
||||
}
|
||||
|
@ -40,25 +44,25 @@ class PasswordReset extends RowModel
|
|||
/**
|
||||
* Token is valid only for 3 days.
|
||||
*/
|
||||
function isStillValid(): bool
|
||||
public function isStillValid(): bool
|
||||
{
|
||||
return $this->getRecord()->timestamp > (time() - (3 * DAY));
|
||||
}
|
||||
|
||||
function verify(string $token): bool
|
||||
public function verify(string $token): bool
|
||||
{
|
||||
try {
|
||||
return $this->isStillValid() ? sodium_memcmp($this->getKey(), $token) : false;
|
||||
} catch(\SodiumException $ex) {
|
||||
} catch (\SodiumException $ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function save(): void
|
||||
public function save(?bool $log = false): void
|
||||
{
|
||||
$this->stateChanges("key", base64_encode(openssl_random_pseudo_bytes(46)));
|
||||
$this->stateChanges("timestamp", time());
|
||||
|
||||
parent::save();
|
||||
parent::save($log);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use MessagePack\MessagePack;
|
||||
use Nette\Utils\ImageException;
|
||||
use Nette\Utils\UnknownImageFileException;
|
||||
|
@ -14,7 +18,7 @@ class Photo extends Media
|
|||
protected $tableName = "photos";
|
||||
protected $fileExtension = "jpeg";
|
||||
|
||||
const ALLOWED_SIDE_MULTIPLIER = 7;
|
||||
public const ALLOWED_SIDE_MULTIPLIER = 7;
|
||||
|
||||
/**
|
||||
* @throws \ImagickException
|
||||
|
@ -25,25 +29,29 @@ class Photo extends Media
|
|||
{
|
||||
$res = [false];
|
||||
$requiresProportion = ((string) $size["requireProp"]) != "none";
|
||||
if($requiresProportion) {
|
||||
if ($requiresProportion) {
|
||||
$props = explode(":", (string) $size["requireProp"]);
|
||||
$px = (int) $props[0];
|
||||
$py = (int) $props[1];
|
||||
if(($image->getImageWidth() / $image->getImageHeight()) > ($px / $py)) {
|
||||
if (($image->getImageWidth() / $image->getImageHeight()) > ($px / $py)) {
|
||||
$height = (int) ceil(($px * $image->getImageWidth()) / $py);
|
||||
$image->cropImage($image->getImageWidth(), $height, 0, 0);
|
||||
$res[0] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($size["maxSize"])) {
|
||||
if (isset($size["maxSize"])) {
|
||||
$maxSize = (int) $size["maxSize"];
|
||||
$sizes = Image::calculateSize($image->getImageWidth(), $image->getImageHeight(), $maxSize, $maxSize, Image::SHRINK_ONLY | Image::FIT);
|
||||
$image->resizeImage($sizes[0], $sizes[1], \Imagick::FILTER_HERMITE, 1);
|
||||
} else if(isset($size["maxResolution"])) {
|
||||
} elseif (isset($size["maxResolution"])) {
|
||||
$resolution = explode("x", (string) $size["maxResolution"]);
|
||||
$sizes = Image::calculateSize(
|
||||
$image->getImageWidth(), $image->getImageHeight(), (int) $resolution[0], (int) $resolution[1], Image::SHRINK_ONLY | Image::FIT
|
||||
$image->getImageWidth(),
|
||||
$image->getImageHeight(),
|
||||
(int) $resolution[0],
|
||||
(int) $resolution[1],
|
||||
Image::SHRINK_ONLY | Image::FIT
|
||||
);
|
||||
$image->resizeImage($sizes[0], $sizes[1], \Imagick::FILTER_HERMITE, 1);
|
||||
} else {
|
||||
|
@ -52,10 +60,11 @@ class Photo extends Media
|
|||
|
||||
$res[1] = $image->getImageWidth();
|
||||
$res[2] = $image->getImageHeight();
|
||||
if($res[1] <= 300 || $res[2] <= 300)
|
||||
if ($res[1] <= 300 || $res[2] <= 300) {
|
||||
$image->writeImage("$outputDir/$size[id].gif");
|
||||
else
|
||||
} else {
|
||||
$image->writeImage("$outputDir/$size[id].jpeg");
|
||||
}
|
||||
|
||||
$res[3] = true;
|
||||
$image->destroy();
|
||||
|
@ -66,29 +75,32 @@ class Photo extends Media
|
|||
|
||||
private function saveImageResizedCopies(?\Imagick $image, string $filename, string $hash): void
|
||||
{
|
||||
if(!$image) {
|
||||
$image = new \Imagick;
|
||||
if (!$image) {
|
||||
$image = new \Imagick();
|
||||
$image->readImage($filename);
|
||||
}
|
||||
|
||||
$dir = dirname($this->pathFromHash($hash));
|
||||
$dir = "$dir/$hash" . "_cropped";
|
||||
if(!is_dir($dir)) {
|
||||
if (!is_dir($dir)) {
|
||||
@unlink($dir); # Added to transparently bypass issues with dead pesudofolders summoned by buggy SWIFT impls (selectel)
|
||||
mkdir($dir);
|
||||
}
|
||||
|
||||
$sizes = simplexml_load_file(OPENVK_ROOT . "/data/photosizes.xml");
|
||||
if(!$sizes)
|
||||
if (!$sizes) {
|
||||
throw new \RuntimeException("Could not load photosizes.xml!");
|
||||
}
|
||||
|
||||
$sizesMeta = [];
|
||||
if(OPENVK_ROOT_CONF["openvk"]["preferences"]["photos"]["photoSaving"] === "quick") {
|
||||
foreach($sizes->Size as $size)
|
||||
$sizesMeta[(string)$size["id"]] = [false, false, false, false];
|
||||
if (OPENVK_ROOT_CONF["openvk"]["preferences"]["photos"]["photoSaving"] === "quick") {
|
||||
foreach ($sizes->Size as $size) {
|
||||
$sizesMeta[(string) $size["id"]] = [false, false, false, false];
|
||||
}
|
||||
} else {
|
||||
foreach($sizes->Size as $size)
|
||||
$sizesMeta[(string)$size["id"]] = $this->resizeImage(clone $image, $dir, $size);
|
||||
foreach ($sizes->Size as $size) {
|
||||
$sizesMeta[(string) $size["id"]] = $this->resizeImage(clone $image, $dir, $size);
|
||||
}
|
||||
}
|
||||
|
||||
$sizesMeta = MessagePack::pack($sizesMeta);
|
||||
|
@ -97,16 +109,33 @@ class Photo extends Media
|
|||
|
||||
protected function saveFile(string $filename, string $hash): bool
|
||||
{
|
||||
$image = new \Imagick;
|
||||
$image->readImage($filename);
|
||||
$h = $image->getImageHeight();
|
||||
$w = $image->getImageWidth();
|
||||
if(($h >= ($w * Photo::ALLOWED_SIDE_MULTIPLIER)) || ($w >= ($h * Photo::ALLOWED_SIDE_MULTIPLIER)))
|
||||
$input_image = new \Imagick();
|
||||
$input_image->readImage($filename);
|
||||
$h = $input_image->getImageHeight();
|
||||
$w = $input_image->getImageWidth();
|
||||
if (($h >= ($w * Photo::ALLOWED_SIDE_MULTIPLIER)) || ($w >= ($h * Photo::ALLOWED_SIDE_MULTIPLIER))) {
|
||||
throw new ISE("Invalid layout: image is too wide/short");
|
||||
}
|
||||
|
||||
# gif fix 10.01.2025
|
||||
if ($input_image->getImageFormat() === 'GIF') {
|
||||
$input_image->setIteratorIndex(0);
|
||||
}
|
||||
|
||||
# png workaround (transparency to white)
|
||||
$image = new \Imagick();
|
||||
$bg = new \ImagickPixel('white');
|
||||
$image->newImage($w, $h, $bg);
|
||||
$image->compositeImage($input_image, \Imagick::COMPOSITE_OVER, 0, 0);
|
||||
|
||||
$sizes = Image::calculateSize(
|
||||
$image->getImageWidth(), $image->getImageHeight(), 8192, 4320, Image::SHRINK_ONLY | Image::FIT
|
||||
$image->getImageWidth(),
|
||||
$image->getImageHeight(),
|
||||
8192,
|
||||
4320,
|
||||
Image::SHRINK_ONLY | Image::FIT
|
||||
);
|
||||
|
||||
$image->resizeImage($sizes[0], $sizes[1], \Imagick::FILTER_HERMITE, 1);
|
||||
$image->writeImage($this->pathFromHash($hash));
|
||||
$this->saveImageResizedCopies($image, $filename, $hash);
|
||||
|
@ -114,52 +143,54 @@ class Photo extends Media
|
|||
return true;
|
||||
}
|
||||
|
||||
function crop(real $left, real $top, real $width, real $height): void
|
||||
public function crop(float $left, float $top, float $width, float $height): void
|
||||
{
|
||||
if(isset($this->changes["hash"]))
|
||||
if (isset($this->changes["hash"])) {
|
||||
$hash = $this->changes["hash"];
|
||||
else if(!is_null($this->getRecord()))
|
||||
} elseif (!is_null($this->getRecord())) {
|
||||
$hash = $this->getRecord()->hash;
|
||||
else
|
||||
} else {
|
||||
throw new ISE("Cannot crop uninitialized image. Please call setFile(\$_FILES[...]) first.");
|
||||
}
|
||||
|
||||
$image = Image::fromFile($this->pathFromHash($hash));
|
||||
$image->crop($left, $top, $width, $height);
|
||||
$image->save($this->pathFromHash($hash));
|
||||
}
|
||||
|
||||
function isolate(): void
|
||||
public function isolate(): void
|
||||
{
|
||||
if(is_null($this->getRecord()))
|
||||
if (is_null($this->getRecord())) {
|
||||
throw new ISE("Cannot isolate unpresisted image. Please save() it first.");
|
||||
}
|
||||
|
||||
DB::i()->getContext()->table("album_relations")->where("media", $this->getRecord()->id)->delete();
|
||||
}
|
||||
|
||||
function getSizes(bool $upgrade = false, bool $forceUpdate = false): ?array
|
||||
public function getSizes(bool $upgrade = false, bool $forceUpdate = false): ?array
|
||||
{
|
||||
$sizes = $this->getRecord()->sizes;
|
||||
if(!$sizes || $forceUpdate) {
|
||||
if($forceUpdate || $upgrade || OPENVK_ROOT_CONF["openvk"]["preferences"]["photos"]["upgradeStructure"]) {
|
||||
if (!$sizes || $forceUpdate) {
|
||||
if ($forceUpdate || $upgrade || OPENVK_ROOT_CONF["openvk"]["preferences"]["photos"]["upgradeStructure"]) {
|
||||
$hash = $this->getRecord()->hash;
|
||||
$this->saveImageResizedCopies(NULL, $this->pathFromHash($hash), $hash);
|
||||
$this->saveImageResizedCopies(null, $this->pathFromHash($hash), $hash);
|
||||
$this->save();
|
||||
|
||||
return $this->getSizes();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return null;
|
||||
}
|
||||
|
||||
$res = [];
|
||||
$sizes = MessagePack::unpack($sizes);
|
||||
foreach($sizes as $id => $meta) {
|
||||
if(isset($meta[3]) && !$meta[3]) {
|
||||
foreach ($sizes as $id => $meta) {
|
||||
if (isset($meta[3]) && !$meta[3]) {
|
||||
$res[$id] = (object) [
|
||||
"url" => ovk_scheme(true) . $_SERVER["HTTP_HOST"] . "/photos/thumbnails/" . $this->getId() . "_$id.jpeg",
|
||||
"width" => NULL,
|
||||
"height" => NULL,
|
||||
"crop" => NULL
|
||||
"width" => null,
|
||||
"height" => null,
|
||||
"crop" => null,
|
||||
];
|
||||
continue;
|
||||
}
|
||||
|
@ -172,7 +203,7 @@ class Photo extends Media
|
|||
"url" => $url,
|
||||
"width" => $meta[1],
|
||||
"height" => $meta[2],
|
||||
"crop" => $meta[0]
|
||||
"crop" => $meta[0],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -181,44 +212,50 @@ class Photo extends Media
|
|||
"url" => $this->getURL(),
|
||||
"width" => $x,
|
||||
"height" => $y,
|
||||
"crop" => false
|
||||
"crop" => false,
|
||||
];
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
function forceSize(string $sizeName): bool
|
||||
public function forceSize(string $sizeName): bool
|
||||
{
|
||||
$hash = $this->getRecord()->hash;
|
||||
$sizes = MessagePack::unpack($this->getRecord()->sizes);
|
||||
$size = $sizes[$sizeName] ?? false;
|
||||
if(!$size)
|
||||
if (!$size) {
|
||||
return $size;
|
||||
}
|
||||
|
||||
if(!isset($size[3]) || $size[3] === true)
|
||||
if (!isset($size[3]) || $size[3] === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$path = $this->pathFromHash($hash);
|
||||
$dir = dirname($this->pathFromHash($hash));
|
||||
$dir = "$dir/$hash" . "_cropped";
|
||||
if(!is_dir($dir)) {
|
||||
if (!is_dir($dir)) {
|
||||
@unlink($dir);
|
||||
mkdir($dir);
|
||||
}
|
||||
|
||||
$sizeMetas = simplexml_load_file(OPENVK_ROOT . "/data/photosizes.xml");
|
||||
if(!$sizeMetas)
|
||||
if (!$sizeMetas) {
|
||||
throw new \RuntimeException("Could not load photosizes.xml!");
|
||||
}
|
||||
|
||||
$sizeInfo = NULL;
|
||||
foreach($sizeMetas->Size as $size)
|
||||
if($size["id"] == $sizeName)
|
||||
$sizeInfo = null;
|
||||
foreach ($sizeMetas->Size as $size) {
|
||||
if ($size["id"] == $sizeName) {
|
||||
$sizeInfo = $size;
|
||||
}
|
||||
}
|
||||
|
||||
if(!$sizeInfo)
|
||||
if (!$sizeInfo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$pic = new \Imagick;
|
||||
$pic = new \Imagick();
|
||||
$pic->readImage($path);
|
||||
$sizes[$sizeName] = $this->resizeImage($pic, $dir, $sizeInfo);
|
||||
|
||||
|
@ -228,22 +265,25 @@ class Photo extends Media
|
|||
return $sizes[$sizeName][3];
|
||||
}
|
||||
|
||||
function getVkApiSizes(): ?array
|
||||
public function getVkApiSizes(): ?array
|
||||
{
|
||||
$res = [];
|
||||
$sizes = $this->getSizes();
|
||||
if(!$sizes)
|
||||
return NULL;
|
||||
if (!$sizes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$manifest = simplexml_load_file(OPENVK_ROOT . "/data/photosizes.xml");
|
||||
if(!$manifest)
|
||||
return NULL;
|
||||
if (!$manifest) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$mappings = [];
|
||||
foreach($manifest->Size as $size)
|
||||
foreach ($manifest->Size as $size) {
|
||||
$mappings[(string) $size["id"]] = (string) $size["vkId"];
|
||||
}
|
||||
|
||||
foreach($sizes as $id => $meta) {
|
||||
foreach ($sizes as $id => $meta) {
|
||||
$type = $mappings[$id] ?? $id;
|
||||
$meta->type = $type;
|
||||
$res[$type] = $meta;
|
||||
|
@ -252,24 +292,26 @@ class Photo extends Media
|
|||
return $res;
|
||||
}
|
||||
|
||||
function getURLBySizeId(string $size): string
|
||||
public function getURLBySizeId(string $size): string
|
||||
{
|
||||
$sizes = $this->getSizes();
|
||||
if(!$sizes)
|
||||
if (!$sizes) {
|
||||
return $this->getURL();
|
||||
}
|
||||
|
||||
$size = $sizes[$size];
|
||||
if(!$size)
|
||||
if (!$size) {
|
||||
return $this->getURL();
|
||||
}
|
||||
|
||||
return $size->url;
|
||||
}
|
||||
|
||||
function getDimensions(): array
|
||||
public function getDimensions(): array
|
||||
{
|
||||
$x = $this->getRecord()->width;
|
||||
$y = $this->getRecord()->height;
|
||||
if(!$x) { # no sizes in database
|
||||
if (!$x) { # no sizes in database
|
||||
$hash = $this->getRecord()->hash;
|
||||
$image = Image::fromFile($this->pathFromHash($hash));
|
||||
|
||||
|
@ -283,32 +325,33 @@ class Photo extends Media
|
|||
return [$x, $y];
|
||||
}
|
||||
|
||||
function getPageURL(): string
|
||||
public function getPageURL(): string
|
||||
{
|
||||
if($this->isAnonymous())
|
||||
if ($this->isAnonymous()) {
|
||||
return "/photos/" . base_convert((string) $this->getId(), 10, 32);
|
||||
}
|
||||
|
||||
return "/photo" . $this->getPrettyId();
|
||||
}
|
||||
|
||||
function getAlbum(): ?Album
|
||||
public function getAlbum(): ?Album
|
||||
{
|
||||
return (new Albums)->getAlbumByPhotoId($this);
|
||||
return (new Albums())->getAlbumByPhotoId($this);
|
||||
}
|
||||
|
||||
function toVkApiStruct(bool $photo_sizes = true, bool $extended = false): object
|
||||
public function toVkApiStruct(bool $photo_sizes = true, bool $extended = false): object
|
||||
{
|
||||
$res = (object) [];
|
||||
|
||||
$res->id = $res->pid = $this->getVirtualId();
|
||||
$res->owner_id = $res->user_id = $this->getOwner()->getId();
|
||||
$res->aid = $res->album_id = NULL;
|
||||
$res->aid = $res->album_id = null;
|
||||
$res->width = $this->getDimensions()[0];
|
||||
$res->height = $this->getDimensions()[1];
|
||||
$res->date = $res->created = $this->getPublicationTime()->timestamp();
|
||||
|
||||
if($photo_sizes) {
|
||||
$res->sizes = $this->getVkApiSizes();
|
||||
if ($photo_sizes) {
|
||||
$res->sizes = array_values($this->getVkApiSizes());
|
||||
$res->src_small = $res->photo_75 = $this->getURLBySizeId("miniscule");
|
||||
$res->src = $res->photo_130 = $this->getURLBySizeId("tiny");
|
||||
$res->src_big = $res->photo_604 = $this->getURLBySizeId("normal");
|
||||
|
@ -318,7 +361,7 @@ class Photo extends Media
|
|||
$res->src_original = $res->url = $this->getURLBySizeId("UPLOADED_MAXRES");
|
||||
}
|
||||
|
||||
if($extended) {
|
||||
if ($extended) {
|
||||
$res->likes = $this->getLikesCount(); # их нету но пусть будут
|
||||
$res->comments = $this->getCommentsCount();
|
||||
$res->tags = 0;
|
||||
|
@ -329,9 +372,22 @@ class Photo extends Media
|
|||
return $res;
|
||||
}
|
||||
|
||||
static function fastMake(int $owner, string $description = "", array $file, ?Album $album = NULL, bool $anon = false): Photo
|
||||
public function canBeViewedBy(?User $user = null): bool
|
||||
{
|
||||
$photo = new static;
|
||||
if ($this->isDeleted() || $this->getOwner()->isDeleted()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_null($this->getAlbum())) {
|
||||
return $this->getAlbum()->canBeViewedBy($user);
|
||||
} else {
|
||||
return $this->getOwner()->canBeViewedBy($user);
|
||||
}
|
||||
}
|
||||
|
||||
public static function fastMake(int $owner, string $description = "", array $file, ?Album $album = null, bool $anon = false): Photo
|
||||
{
|
||||
$photo = new static();
|
||||
$photo->setOwner($owner);
|
||||
$photo->setDescription(iconv_substr($description, 0, 36) . "...");
|
||||
$photo->setAnonymous($anon);
|
||||
|
@ -339,7 +395,7 @@ class Photo extends Media
|
|||
$photo->setFile($file);
|
||||
$photo->save();
|
||||
|
||||
if(!is_null($album)) {
|
||||
if (!is_null($album)) {
|
||||
$album->addPhoto($photo);
|
||||
$album->setEdited(time());
|
||||
$album->save();
|
||||
|
@ -347,4 +403,20 @@ class Photo extends Media
|
|||
|
||||
return $photo;
|
||||
}
|
||||
|
||||
public function toNotifApiStruct()
|
||||
{
|
||||
$res = (object) [];
|
||||
|
||||
$res->id = $this->getVirtualId();
|
||||
$res->owner_id = $this->getOwner()->getId();
|
||||
$res->aid = 0;
|
||||
$res->src = $this->getURLBySizeId("tiny");
|
||||
$res->src_big = $this->getURLBySizeId("normal");
|
||||
$res->src_small = $this->getURLBySizeId("miniscule");
|
||||
$res->text = $this->getDescription();
|
||||
$res->created = $this->getPublicationTime()->timestamp();
|
||||
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
|
|
300
Web/Models/Entities/Playlist.php
Normal file
300
Web/Models/Entities/Playlist.php
Normal file
|
@ -0,0 +1,300 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
use Nette\Database\Table\ActiveRow;
|
||||
use openvk\Web\Models\Repositories\Audios;
|
||||
use openvk\Web\Models\Repositories\Photos;
|
||||
use openvk\Web\Models\RowModel;
|
||||
use openvk\Web\Models\Entities\Photo;
|
||||
|
||||
/**
|
||||
* @method setName(string $name)
|
||||
* @method setDescription(?string $desc)
|
||||
*/
|
||||
class Playlist extends MediaCollection
|
||||
{
|
||||
protected $tableName = "playlists";
|
||||
protected $relTableName = "playlist_relations";
|
||||
protected $entityTableName = "audios";
|
||||
protected $entityClassName = 'openvk\Web\Models\Entities\Audio';
|
||||
protected $allowDuplicates = false;
|
||||
|
||||
private $importTable;
|
||||
|
||||
public const MAX_COUNT = 1000;
|
||||
public const MAX_ITEMS = 10000;
|
||||
|
||||
public function __construct(?ActiveRow $ar = null)
|
||||
{
|
||||
parent::__construct($ar);
|
||||
|
||||
$this->importTable = DatabaseConnection::i()->getContext()->table("playlist_imports");
|
||||
}
|
||||
|
||||
public function getCoverURL(string $size = "normal"): ?string
|
||||
{
|
||||
$photo = (new Photos())->get((int) $this->getRecord()->cover_photo_id);
|
||||
return is_null($photo) ? "/assets/packages/static/openvk/img/song.jpg" : $photo->getURLBySizeId($size);
|
||||
}
|
||||
|
||||
public function getLength(): int
|
||||
{
|
||||
return $this->getRecord()->length;
|
||||
}
|
||||
|
||||
public function fetchClassic(int $offset = 0, ?int $limit = null): \Traversable
|
||||
{
|
||||
$related = $this->getRecord()->related("$this->relTableName.collection")
|
||||
->limit($limit ?? OPENVK_DEFAULT_PER_PAGE, $offset)
|
||||
->order("index ASC");
|
||||
|
||||
foreach ($related as $rel) {
|
||||
$media = $rel->ref($this->entityTableName, "media");
|
||||
if (!$media) {
|
||||
continue;
|
||||
}
|
||||
|
||||
yield new $this->entityClassName($media);
|
||||
}
|
||||
}
|
||||
|
||||
public function getAudios(int $offset = 0, ?int $limit = null, ?int $shuffleSeed = null): \Traversable
|
||||
{
|
||||
if (!$shuffleSeed) {
|
||||
foreach ($this->fetchClassic($offset, $limit) as $e) {
|
||||
yield $e;
|
||||
} # No, I can't return, it will break with []
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$ids = [];
|
||||
foreach ($this->relations->select("media AS i")->where("collection", $this->getId()) as $rel) {
|
||||
$ids[] = $rel->i;
|
||||
}
|
||||
|
||||
$ids = knuth_shuffle($ids, $shuffleSeed);
|
||||
$ids = array_slice($ids, $offset, $limit ?? OPENVK_DEFAULT_PER_PAGE);
|
||||
foreach ($ids as $id) {
|
||||
yield (new Audios())->get($id);
|
||||
}
|
||||
}
|
||||
|
||||
public function add(RowModel $audio): bool
|
||||
{
|
||||
if ($res = parent::add($audio)) {
|
||||
$this->stateChanges("length", $this->getRecord()->length + $audio->getLength());
|
||||
$this->save();
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function remove(RowModel $audio): bool
|
||||
{
|
||||
if ($res = parent::remove($audio)) {
|
||||
$this->stateChanges("length", $this->getRecord()->length - $audio->getLength());
|
||||
$this->save();
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function isBookmarkedBy(RowModel $entity): bool
|
||||
{
|
||||
$id = $entity->getId();
|
||||
if ($entity instanceof Club) {
|
||||
$id *= -1;
|
||||
}
|
||||
|
||||
return !is_null($this->importTable->where([
|
||||
"entity" => $id,
|
||||
"playlist" => $this->getId(),
|
||||
])->fetch());
|
||||
}
|
||||
|
||||
public function bookmark(RowModel $entity): bool
|
||||
{
|
||||
if ($this->isBookmarkedBy($entity)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$id = $entity->getId();
|
||||
if ($entity instanceof Club) {
|
||||
$id *= -1;
|
||||
}
|
||||
|
||||
if ($this->importTable->where("entity", $id)->count() > self::MAX_COUNT) {
|
||||
throw new \OutOfBoundsException("Maximum amount of playlists");
|
||||
}
|
||||
|
||||
$this->importTable->insert([
|
||||
"entity" => $id,
|
||||
"playlist" => $this->getId(),
|
||||
]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function unbookmark(RowModel $entity): bool
|
||||
{
|
||||
$id = $entity->getId();
|
||||
if ($entity instanceof Club) {
|
||||
$id *= -1;
|
||||
}
|
||||
|
||||
$count = $this->importTable->where([
|
||||
"entity" => $id,
|
||||
"playlist" => $this->getId(),
|
||||
])->delete();
|
||||
|
||||
return $count > 0;
|
||||
}
|
||||
|
||||
public function getDescription(): ?string
|
||||
{
|
||||
return $this->getRecord()->description;
|
||||
}
|
||||
|
||||
public function getDescriptionHTML(): ?string
|
||||
{
|
||||
return htmlspecialchars($this->getRecord()->description, ENT_DISALLOWED | ENT_XHTML);
|
||||
}
|
||||
|
||||
public function getListens()
|
||||
{
|
||||
return $this->getRecord()->listens;
|
||||
}
|
||||
|
||||
public function toVkApiStruct(?User $user = null): object
|
||||
{
|
||||
$oid = $this->getOwner()->getId();
|
||||
if ($this->getOwner() instanceof Club) {
|
||||
$oid *= -1;
|
||||
}
|
||||
|
||||
return (object) [
|
||||
"id" => $this->getId(),
|
||||
"owner_id" => $oid,
|
||||
"title" => $this->getName(),
|
||||
"description" => $this->getDescription(),
|
||||
"size" => $this->size(),
|
||||
"length" => $this->getLength(),
|
||||
"created" => $this->getCreationTime()->timestamp(),
|
||||
"modified" => $this->getEditTime() ? $this->getEditTime()->timestamp() : null,
|
||||
"accessible" => $this->canBeViewedBy($user),
|
||||
"editable" => $this->canBeModifiedBy($user),
|
||||
"bookmarked" => $this->isBookmarkedBy($user),
|
||||
"listens" => $this->getListens(),
|
||||
"cover_url" => $this->getCoverURL(),
|
||||
"searchable" => !$this->isUnlisted(),
|
||||
];
|
||||
}
|
||||
|
||||
public function setLength(): void
|
||||
{
|
||||
throw new \LogicException("Can't set length of playlist manually");
|
||||
}
|
||||
|
||||
public function resetLength(): bool
|
||||
{
|
||||
$this->stateChanges("length", 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function delete(bool $softly = true): void
|
||||
{
|
||||
$ctx = DatabaseConnection::i()->getContext();
|
||||
$ctx->table("playlist_imports")->where("playlist", $this->getId())
|
||||
->delete();
|
||||
|
||||
parent::delete($softly);
|
||||
}
|
||||
|
||||
public function hasAudio(Audio $audio): bool
|
||||
{
|
||||
$ctx = DatabaseConnection::i()->getContext();
|
||||
return !is_null($ctx->table("playlist_relations")->where([
|
||||
"collection" => $this->getId(),
|
||||
"media" => $audio->getId(),
|
||||
])->fetch());
|
||||
}
|
||||
|
||||
public function getCoverPhotoId(): ?int
|
||||
{
|
||||
return $this->getRecord()->cover_photo_id;
|
||||
}
|
||||
|
||||
public function getCoverPhoto(): ?Photo
|
||||
{
|
||||
return (new Photos())->get((int) $this->getRecord()->cover_photo_id);
|
||||
}
|
||||
|
||||
public function canBeModifiedBy(User $user): bool
|
||||
{
|
||||
if (!$user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->getOwner() instanceof User) {
|
||||
return $user->getId() == $this->getOwner()->getId();
|
||||
} else {
|
||||
return $this->getOwner()->canBeModifiedBy($user);
|
||||
}
|
||||
}
|
||||
|
||||
public function getLengthInMinutes(): int
|
||||
{
|
||||
return (int) round($this->getLength() / 60, PHP_ROUND_HALF_DOWN);
|
||||
}
|
||||
|
||||
public function fastMakeCover(int $owner, array $file)
|
||||
{
|
||||
$cover = new Photo();
|
||||
$cover->setOwner($owner);
|
||||
$cover->setDescription("Playlist cover image");
|
||||
$cover->setFile($file);
|
||||
$cover->setCreated(time());
|
||||
$cover->save();
|
||||
|
||||
$this->setCover_photo_id($cover->getId());
|
||||
|
||||
return $cover;
|
||||
}
|
||||
|
||||
public function getURL(): string
|
||||
{
|
||||
return "/playlist" . $this->getOwner()->getRealId() . "_" . $this->getId();
|
||||
}
|
||||
|
||||
public function incrementListens()
|
||||
{
|
||||
$this->stateChanges("listens", ($this->getListens() + 1));
|
||||
}
|
||||
|
||||
public function getMetaDescription(): string
|
||||
{
|
||||
$length = $this->getLengthInMinutes();
|
||||
|
||||
$props = [];
|
||||
$props[] = tr("audios_count", $this->size());
|
||||
$props[] = "<span id='listensCount'>" . tr("listens_count", $this->getListens()) . "</span>";
|
||||
if ($length > 0) {
|
||||
$props[] = tr("minutes_count", $length);
|
||||
}
|
||||
$props[] = tr("created_playlist") . " " . $this->getPublicationTime();
|
||||
# if($this->getEditTime()) $props[] = tr("updated_playlist") . " " . $this->getEditTime();
|
||||
|
||||
return implode(" • ", $props);
|
||||
}
|
||||
|
||||
public function isUnlisted(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->unlisted;
|
||||
}
|
||||
}
|
|
@ -1,10 +1,14 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use openvk\Web\Models\Exceptions\TooMuchOptionsException;
|
||||
use openvk\Web\Util\DateTime;
|
||||
use \UnexpectedValueException;
|
||||
use UnexpectedValueException;
|
||||
use Nette\InvalidStateException;
|
||||
use openvk\Web\Models\Repositories\Users;
|
||||
use openvk\Web\Models\Repositories\{Users, Posts};
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
use openvk\Web\Models\Exceptions\PollLockedException;
|
||||
use openvk\Web\Models\Exceptions\AlreadyVotedException;
|
||||
|
@ -16,48 +20,56 @@ class Poll extends Attachable
|
|||
|
||||
private $choicesToPersist = [];
|
||||
|
||||
function getTitle(): string
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->getRecord()->title;
|
||||
}
|
||||
|
||||
function getMetaDescription(): string
|
||||
public 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());
|
||||
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
|
||||
public function getOwner(): User
|
||||
{
|
||||
return (new Users)->get($this->getRecord()->owner);
|
||||
return (new Users())->get($this->getRecord()->owner);
|
||||
}
|
||||
|
||||
function getOptions(): array
|
||||
public function getOptions(): array
|
||||
{
|
||||
$options = $this->getRecord()->related("poll_options.poll");
|
||||
$res = [];
|
||||
foreach($options as $opt)
|
||||
foreach ($options as $opt) {
|
||||
$res[$opt->id] = $opt->name;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
function getUserVote(User $user): ?array
|
||||
public 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;
|
||||
if ($votedOpts->count() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$res = [];
|
||||
foreach($votedOpts as $votedOpt) {
|
||||
foreach ($votedOpts as $votedOpt) {
|
||||
$option = $ctx->table("poll_options")->get($votedOpt->option);
|
||||
$res[] = [$option->id, $option->name];
|
||||
}
|
||||
|
@ -65,39 +77,42 @@ class Poll extends Attachable
|
|||
return $res;
|
||||
}
|
||||
|
||||
function getVoters(int $optionId, int $page = 1, ?int $perPage = NULL): array
|
||||
public function getVoters(int $optionId, int $page = 1, ?int $perPage = null): array
|
||||
{
|
||||
$res = [];
|
||||
$ctx = DatabaseConnection::i()->getContext();
|
||||
$perPage = $perPage ?? OPENVK_DEFAULT_PER_PAGE;
|
||||
$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);
|
||||
foreach ($voters->page($page, $perPage) as $vote) {
|
||||
$res[] = (new Users())->get($vote->user);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
function getVoterCount(?int $optionId = NULL): int
|
||||
public function getVoterCount(?int $optionId = null): int
|
||||
{
|
||||
$votes = DatabaseConnection::i()->getContext()->table("poll_votes");
|
||||
if(!$optionId)
|
||||
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
|
||||
public function getResults(?User $user = null): object
|
||||
{
|
||||
$ctx = DatabaseConnection::i()->getContext();
|
||||
$voted = NULL;
|
||||
if(!is_null($user))
|
||||
$voted = null;
|
||||
if (!is_null($user)) {
|
||||
$voted = $this->getUserVote($user);
|
||||
}
|
||||
|
||||
$result = (object) [];
|
||||
$result->totalVotes = $this->getVoterCount();
|
||||
|
||||
$unsOptions = [];
|
||||
foreach($this->getOptions() as $id => $title) {
|
||||
foreach ($this->getOptions() as $id => $title) {
|
||||
$option = (object) [];
|
||||
$option->id = $id;
|
||||
$option->name = $title;
|
||||
|
@ -105,86 +120,95 @@ class Poll extends Attachable
|
|||
$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
|
||||
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++)
|
||||
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
|
||||
public function isAnonymous(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->is_anonymous;
|
||||
}
|
||||
|
||||
function isMultipleChoice(): bool
|
||||
public function isMultipleChoice(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->allows_multiple;
|
||||
}
|
||||
|
||||
function isRevotable(): bool
|
||||
public function isRevotable(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->can_revote;
|
||||
}
|
||||
|
||||
function endsAt(): ?DateTime
|
||||
public function endsAt(): ?DateTime
|
||||
{
|
||||
if(!$this->getRecord()->until)
|
||||
return NULL;
|
||||
if (!$this->getRecord()->until) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new DateTime($this->getRecord()->until);
|
||||
}
|
||||
|
||||
function hasEnded(): bool
|
||||
public function hasEnded(): bool
|
||||
{
|
||||
if($this->getRecord()->ended)
|
||||
if ($this->getRecord()->ended) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!is_null($this->getRecord()->until))
|
||||
if (!is_null($this->getRecord()->until)) {
|
||||
return time() >= $this->getRecord()->until;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function hasVoted(User $user): bool
|
||||
public function hasVoted(User $user): bool
|
||||
{
|
||||
return !is_null($this->getUserVote($user));
|
||||
}
|
||||
|
||||
function canVote(User $user): bool
|
||||
public function canVote(User $user): bool
|
||||
{
|
||||
return !$this->hasEnded() && !$this->hasVoted($user);
|
||||
return !$this->hasEnded() && !$this->hasVoted($user) && !is_null($this->getAttachedPost()) && $this->getAttachedPost()->getSuggestionType() == 0;
|
||||
}
|
||||
|
||||
function vote(User $user, array $optionIds): void
|
||||
public function vote(User $user, array $optionIds): void
|
||||
{
|
||||
if($this->hasEnded())
|
||||
throw new PollLockedException;
|
||||
if ($this->hasEnded()) {
|
||||
throw new PollLockedException();
|
||||
}
|
||||
|
||||
if($this->hasVoted($user))
|
||||
throw new AlreadyVotedException;
|
||||
if ($this->hasVoted($user)) {
|
||||
throw new AlreadyVotedException();
|
||||
}
|
||||
|
||||
$optionIds = array_map(function($x) { return (int) $x; }, array_unique($optionIds));
|
||||
$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 (empty($optionIds) || (sizeof($optionIds) > 1 && !$this->isMultipleChoice())) {
|
||||
throw new UnexpectedValueException();
|
||||
}
|
||||
|
||||
if(sizeof(array_diff($optionIds, $validOpts)) > 0)
|
||||
throw new InvalidOptionException;
|
||||
if (sizeof(array_diff($optionIds, $validOpts)) > 0) {
|
||||
throw new InvalidOptionException();
|
||||
}
|
||||
|
||||
foreach($optionIds as $opt) {
|
||||
foreach ($optionIds as $opt) {
|
||||
DatabaseConnection::i()->getContext()->table("poll_votes")->insert([
|
||||
"user" => $user->getId(),
|
||||
"poll" => $this->getId(),
|
||||
|
@ -193,63 +217,68 @@ class Poll extends Attachable
|
|||
}
|
||||
}
|
||||
|
||||
function revokeVote(User $user): void
|
||||
public function revokeVote(User $user): void
|
||||
{
|
||||
if(!$this->isRevotable())
|
||||
throw new PollLockedException;
|
||||
if (!$this->isRevotable()) {
|
||||
throw new PollLockedException();
|
||||
}
|
||||
|
||||
$this->getRecord()->related("poll_votes.poll")
|
||||
->where("user", $user->getId())->delete();
|
||||
}
|
||||
|
||||
function setOwner(User $owner): void
|
||||
public function setOwner(User $owner): void
|
||||
{
|
||||
$this->stateChanges("owner", $owner->getId());
|
||||
}
|
||||
|
||||
function setEndDate(int $timestamp): void
|
||||
public function setEndDate(int $timestamp): void
|
||||
{
|
||||
if(!is_null($this->getRecord()))
|
||||
throw new PollLockedException;
|
||||
if (!is_null($this->getRecord())) {
|
||||
throw new PollLockedException();
|
||||
}
|
||||
|
||||
$this->stateChanges("until", $timestamp);
|
||||
}
|
||||
|
||||
function setEnded(): void
|
||||
public function setEnded(): void
|
||||
{
|
||||
$this->stateChanges("ended", 1);
|
||||
}
|
||||
|
||||
function setOptions(array $options): void
|
||||
public function setOptions(array $options): void
|
||||
{
|
||||
if(!is_null($this->getRecord()))
|
||||
throw new PollLockedException;
|
||||
if (!is_null($this->getRecord())) {
|
||||
throw new PollLockedException();
|
||||
}
|
||||
|
||||
if(sizeof($options) > ovkGetQuirk("polls.max-opts"))
|
||||
throw new TooMuchOptionsException;
|
||||
if (sizeof($options) > ovkGetQuirk("polls.max-opts")) {
|
||||
throw new TooMuchOptionsException();
|
||||
}
|
||||
|
||||
$this->choicesToPersist = $options;
|
||||
}
|
||||
|
||||
function setRevotability(bool $canReVote): void
|
||||
public function setRevotability(bool $canReVote): void
|
||||
{
|
||||
if(!is_null($this->getRecord()))
|
||||
throw new PollLockedException;
|
||||
if (!is_null($this->getRecord())) {
|
||||
throw new PollLockedException();
|
||||
}
|
||||
|
||||
$this->stateChanges("can_revote", $canReVote);
|
||||
}
|
||||
|
||||
function setAnonymity(bool $anonymous): void
|
||||
public function setAnonymity(bool $anonymous): void
|
||||
{
|
||||
$this->stateChanges("is_anonymous", $anonymous);
|
||||
}
|
||||
|
||||
function setMultipleChoice(bool $mc): void
|
||||
public function setMultipleChoice(bool $mc): void
|
||||
{
|
||||
$this->stateChanges("allows_multiple", $mc);
|
||||
}
|
||||
|
||||
function importXML(User $owner, string $xml): void
|
||||
public function importXML(User $owner, string $xml): void
|
||||
{
|
||||
$xml = simplexml_load_string($xml);
|
||||
$this->setOwner($owner);
|
||||
|
@ -257,39 +286,69 @@ class Poll extends Attachable
|
|||
$this->setMultipleChoice(($xml["multiple"] ?? "no") == "yes");
|
||||
$this->setAnonymity(($xml["anonymous"] ?? "no") == "yes");
|
||||
$this->setRevotability(($xml["locked"] ?? "no") == "no");
|
||||
if(ctype_digit((string) ($xml["duration"] ?? "")))
|
||||
if (ctype_digit((string) ($xml["duration"] ?? ""))) {
|
||||
$this->setEndDate(time() + ((86400 * (int) $xml["duration"])));
|
||||
}
|
||||
|
||||
$options = [];
|
||||
foreach($xml->options->option as $opt)
|
||||
foreach ($xml->options->option as $opt) {
|
||||
$options[] = (string) $opt;
|
||||
}
|
||||
|
||||
if(empty($options))
|
||||
throw new UnexpectedValueException;
|
||||
if (empty($options)) {
|
||||
throw new UnexpectedValueException();
|
||||
}
|
||||
|
||||
$this->setOptions($options);
|
||||
}
|
||||
|
||||
static function import(User $owner, string $xml): Poll
|
||||
public static function import(User $owner, string $xml): Poll
|
||||
{
|
||||
$poll = new Poll;
|
||||
$poll = new Poll();
|
||||
$poll->importXML($owner, $xml);
|
||||
$poll->save();
|
||||
|
||||
return $poll;
|
||||
}
|
||||
|
||||
function save(): void
|
||||
public function canBeViewedBy(?User $user = null): bool
|
||||
{
|
||||
if(empty($this->choicesToPersist))
|
||||
throw new InvalidStateException;
|
||||
# waiting for #935 :(
|
||||
/*if(!is_null($this->getAttachedPost())) {
|
||||
return $this->getAttachedPost()->canBeViewedBy($user);
|
||||
} else {*/
|
||||
return true;
|
||||
#}
|
||||
|
||||
parent::save();
|
||||
foreach($this->choicesToPersist as $option) {
|
||||
}
|
||||
|
||||
public function save(?bool $log = false): void
|
||||
{
|
||||
if (empty($this->choicesToPersist)) {
|
||||
throw new InvalidStateException();
|
||||
}
|
||||
|
||||
parent::save($log);
|
||||
foreach ($this->choicesToPersist as $option) {
|
||||
DatabaseConnection::i()->getContext()->table("poll_options")->insert([
|
||||
"poll" => $this->getId(),
|
||||
"name" => $option,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function getAttachedPost()
|
||||
{
|
||||
$post = DatabaseConnection::i()->getContext()->table("attachments")
|
||||
->where(
|
||||
["attachable_type" => static::class,
|
||||
"attachable_id" => $this->getId()]
|
||||
)->fetch();
|
||||
|
||||
if (!is_null($post->target_id)) {
|
||||
return (new Posts())->get($post->target_id);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use Chandler\Database\DatabaseConnection as DB;
|
||||
use openvk\Web\Models\Repositories\{Clubs, Users};
|
||||
use openvk\Web\Models\RowModel;
|
||||
|
@ -7,6 +11,7 @@ use openvk\Web\Models\Entities\Notifications\LikeNotification;
|
|||
|
||||
class Post extends Postable
|
||||
{
|
||||
use Traits\TRichText;
|
||||
protected $tableName = "posts";
|
||||
protected $upperNodeReferenceColumnName = "wall";
|
||||
|
||||
|
@ -18,54 +23,60 @@ class Post extends Postable
|
|||
"target" => $this->getRecord()->id,
|
||||
];
|
||||
|
||||
if((sizeof(DB::i()->getContext()->table("likes")->where($searchData)) > 0) !== $liked) {
|
||||
if($this->getOwner(false)->getId() !== $user->getId() && !($this->getOwner() instanceof Club) && !$this instanceof Comment)
|
||||
if ((sizeof(DB::i()->getContext()->table("likes")->where($searchData)) > 0) !== $liked) {
|
||||
if ($this->getOwner(false)->getId() !== $user->getId() && !($this->getOwner() instanceof Club) && !$this instanceof Comment) {
|
||||
(new LikeNotification($this->getOwner(false), $this, $user))->emit();
|
||||
}
|
||||
|
||||
parent::setLike($liked, $user);
|
||||
}
|
||||
|
||||
if($depth < ovkGetQuirk("wall.repost-liking-recursion-limit"))
|
||||
foreach($this->getChildren() as $attachment)
|
||||
if($attachment instanceof Post)
|
||||
if ($depth < ovkGetQuirk("wall.repost-liking-recursion-limit")) {
|
||||
foreach ($this->getChildren() as $attachment) {
|
||||
if ($attachment instanceof Post) {
|
||||
$attachment->setLikeRecursively($liked, $user, $depth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* May return fake owner (group), if flags are [1, (*)]
|
||||
*
|
||||
* @param bool $honourFlags - check flags
|
||||
*/
|
||||
function getOwner(bool $honourFlags = true, bool $real = false): RowModel
|
||||
public function getOwner(bool $honourFlags = true, bool $real = false): RowModel
|
||||
{
|
||||
if($honourFlags && $this->isPostedOnBehalfOfGroup()) {
|
||||
if($this->getRecord()->wall < 0)
|
||||
return (new Clubs)->get(abs($this->getRecord()->wall));
|
||||
if ($honourFlags && $this->isPostedOnBehalfOfGroup()) {
|
||||
if ($this->getRecord()->wall < 0) {
|
||||
return (new Clubs())->get(abs($this->getRecord()->wall));
|
||||
}
|
||||
}
|
||||
|
||||
return parent::getOwner($real);
|
||||
}
|
||||
|
||||
function getPrettyId(): string
|
||||
public function getPrettyId(): string
|
||||
{
|
||||
return $this->getRecord()->wall . "_" . $this->getVirtualId();
|
||||
}
|
||||
|
||||
function getTargetWall(): int
|
||||
public function getTargetWall(): int
|
||||
{
|
||||
return $this->getRecord()->wall;
|
||||
}
|
||||
|
||||
function getWallOwner()
|
||||
public function getWallOwner()
|
||||
{
|
||||
$w = $this->getRecord()->wall;
|
||||
if($w < 0)
|
||||
return (new Clubs)->get(abs($w));
|
||||
|
||||
return (new Users)->get($w);
|
||||
if ($w < 0) {
|
||||
return (new Clubs())->get(abs($w));
|
||||
}
|
||||
|
||||
function getRepostCount(): int
|
||||
return (new Users())->get($w);
|
||||
}
|
||||
|
||||
public function getRepostCount(): int
|
||||
{
|
||||
return sizeof(
|
||||
$this->getRecord()
|
||||
|
@ -74,55 +85,96 @@ class Post extends Postable
|
|||
);
|
||||
}
|
||||
|
||||
function isPinned(): bool
|
||||
public function isPinned(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->pinned;
|
||||
}
|
||||
|
||||
function isAd(): bool
|
||||
public function hasSource(): bool
|
||||
{
|
||||
return $this->getRecord()->source != null;
|
||||
}
|
||||
|
||||
public function getSource(bool $format = false)
|
||||
{
|
||||
$orig_source = $this->getRecord()->source;
|
||||
if (!str_contains($orig_source, "https://") && !str_contains($orig_source, "http://")) {
|
||||
$orig_source = "https://" . $orig_source;
|
||||
}
|
||||
|
||||
if (!$format) {
|
||||
return $orig_source;
|
||||
}
|
||||
|
||||
return $this->formatLinks($orig_source);
|
||||
}
|
||||
|
||||
public function setSource(string $source)
|
||||
{
|
||||
$result = check_copyright_link($source);
|
||||
|
||||
$this->stateChanges("source", $source);
|
||||
}
|
||||
|
||||
public function resetSource()
|
||||
{
|
||||
$this->stateChanges("source", null);
|
||||
}
|
||||
|
||||
public function getVkApiCopyright(): object
|
||||
{
|
||||
return (object) [
|
||||
'id' => 0,
|
||||
'link' => $this->getSource(false),
|
||||
'name' => $this->getSource(false),
|
||||
'type' => 'link',
|
||||
];
|
||||
}
|
||||
|
||||
public function isAd(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->ad;
|
||||
}
|
||||
|
||||
function isPostedOnBehalfOfGroup(): bool
|
||||
public function isPostedOnBehalfOfGroup(): bool
|
||||
{
|
||||
return ($this->getRecord()->flags & 0b10000000) > 0;
|
||||
}
|
||||
|
||||
function isSigned(): bool
|
||||
public function isSigned(): bool
|
||||
{
|
||||
return ($this->getRecord()->flags & 0b01000000) > 0;
|
||||
}
|
||||
|
||||
function isDeactivationMessage(): bool
|
||||
public function isDeactivationMessage(): bool
|
||||
{
|
||||
return (($this->getRecord()->flags & 0b00100000) > 0) && ($this->getRecord()->owner > 0);
|
||||
}
|
||||
|
||||
function isUpdateAvatarMessage(): bool
|
||||
public function isUpdateAvatarMessage(): bool
|
||||
{
|
||||
return (($this->getRecord()->flags & 0b00010000) > 0) && ($this->getRecord()->owner > 0);
|
||||
}
|
||||
|
||||
function isExplicit(): bool
|
||||
public function isExplicit(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->nsfw;
|
||||
}
|
||||
|
||||
function isDeleted(): bool
|
||||
public function isDeleted(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->deleted;
|
||||
}
|
||||
|
||||
function getOwnerPost(): int
|
||||
public function getOwnerPost(): int
|
||||
{
|
||||
return $this->getOwner(false)->getId();
|
||||
}
|
||||
|
||||
function getPlatform(bool $forAPI = false): ?string
|
||||
public function getPlatform(bool $forAPI = false): ?string
|
||||
{
|
||||
$platform = $this->getRecord()->api_source_name;
|
||||
if($forAPI) {
|
||||
if ($forAPI) {
|
||||
switch ($platform) {
|
||||
case 'openvk_refresh_android':
|
||||
case 'openvk_legacy_android':
|
||||
|
@ -134,13 +186,17 @@ class Post extends Postable
|
|||
return 'iphone';
|
||||
break;
|
||||
|
||||
case 'windows_phone':
|
||||
return 'wphone';
|
||||
break;
|
||||
|
||||
case 'vika_touch': // кика хохотач ахахахаххахахахахах
|
||||
case 'vk4me':
|
||||
return 'mobile';
|
||||
break;
|
||||
|
||||
case NULL:
|
||||
return NULL;
|
||||
case null:
|
||||
return null;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -152,17 +208,17 @@ class Post extends Postable
|
|||
}
|
||||
}
|
||||
|
||||
function getPlatformDetails(): array
|
||||
public function getPlatformDetails(): array
|
||||
{
|
||||
$clients = simplexml_load_file(OPENVK_ROOT . "/data/clients.xml");
|
||||
|
||||
foreach($clients as $client) {
|
||||
if($client['tag'] == $this->getPlatform()) {
|
||||
foreach ($clients as $client) {
|
||||
if ($client['tag'] == $this->getPlatform()) {
|
||||
return [
|
||||
"tag" => $client['tag'],
|
||||
"name" => $client['name'],
|
||||
"url" => $client['url'],
|
||||
"img" => $client['img']
|
||||
"img" => $client['img'],
|
||||
];
|
||||
break;
|
||||
}
|
||||
|
@ -170,13 +226,40 @@ class Post extends Postable
|
|||
|
||||
return [
|
||||
"tag" => $this->getPlatform(),
|
||||
"name" => NULL,
|
||||
"url" => NULL,
|
||||
"img" => NULL
|
||||
"name" => null,
|
||||
"url" => null,
|
||||
"img" => null,
|
||||
];
|
||||
}
|
||||
|
||||
function pin(): void
|
||||
public function getPostSourceInfo(): array
|
||||
{
|
||||
$post_source = ["type" => "vk"];
|
||||
if ($this->getPlatform(true) !== null) {
|
||||
$post_source = [
|
||||
"type" => "api",
|
||||
"platform" => $this->getPlatform(true),
|
||||
];
|
||||
}
|
||||
|
||||
if ($this->isUpdateAvatarMessage()) {
|
||||
$post_source['data'] = 'profile_photo';
|
||||
}
|
||||
|
||||
return $post_source;
|
||||
}
|
||||
|
||||
public function getVkApiType(): string
|
||||
{
|
||||
$type = 'post';
|
||||
if ($this->getSuggestionType() != 0) {
|
||||
$type = 'suggest';
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
public function pin(): void
|
||||
{
|
||||
DB::i()
|
||||
->getContext()
|
||||
|
@ -191,60 +274,259 @@ class Post extends Postable
|
|||
$this->save();
|
||||
}
|
||||
|
||||
function unpin(): void
|
||||
public function unpin(): void
|
||||
{
|
||||
$this->stateChanges("pinned", false);
|
||||
$this->save();
|
||||
}
|
||||
|
||||
function canBePinnedBy(User $user): bool
|
||||
public function canBePinnedBy(User $user = null): bool
|
||||
{
|
||||
if($this->getTargetWall() < 0)
|
||||
return (new Clubs)->get(abs($this->getTargetWall()))->canBeModifiedBy($user);
|
||||
if (!$user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->getTargetWall() < 0) {
|
||||
return (new Clubs())->get(abs($this->getTargetWall()))->canBeModifiedBy($user);
|
||||
}
|
||||
|
||||
return $this->getTargetWall() === $user->getId();
|
||||
}
|
||||
|
||||
function canBeDeletedBy(User $user): bool
|
||||
public function canBeDeletedBy(User $user = null): bool
|
||||
{
|
||||
if (!$user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->getTargetWall() < 0 && !$this->getWallOwner()->canBeModifiedBy($user) && $this->getWallOwner()->getWallType() != 1 && $this->getSuggestionType() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->getOwnerPost() === $user->getId() || $this->canBePinnedBy($user);
|
||||
}
|
||||
|
||||
function setContent(string $content): void
|
||||
public function setContent(string $content): void
|
||||
{
|
||||
if(ctype_space($content))
|
||||
if (ctype_space($content)) {
|
||||
throw new \LengthException("Content length must be at least 1 character (not counting whitespaces).");
|
||||
else if(iconv_strlen($content) > OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["postSizes"]["maxSize"])
|
||||
} elseif (iconv_strlen($content) > OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["postSizes"]["maxSize"]) {
|
||||
throw new \LengthException("Content is too large.");
|
||||
}
|
||||
|
||||
$this->stateChanges("content", $content);
|
||||
}
|
||||
|
||||
function toggleLike(User $user): bool
|
||||
public function toggleLike(User $user): bool
|
||||
{
|
||||
$liked = parent::toggleLike($user);
|
||||
|
||||
if($this->getOwner(false)->getId() !== $user->getId() && !($this->getOwner() instanceof Club) && !$this instanceof Comment)
|
||||
if (!$user->isPrivateLikes() && $this->getOwner(false)->getId() !== $user->getId() && !($this->getOwner() instanceof Club) && !$this instanceof Comment) {
|
||||
(new LikeNotification($this->getOwner(false), $this, $user))->emit();
|
||||
}
|
||||
|
||||
foreach($this->getChildren() as $attachment)
|
||||
if($attachment instanceof Post)
|
||||
foreach ($this->getChildren() as $attachment) {
|
||||
if ($attachment instanceof Post) {
|
||||
$attachment->setLikeRecursively($liked, $user, 2);
|
||||
}
|
||||
}
|
||||
|
||||
return $liked;
|
||||
}
|
||||
|
||||
function setLike(bool $liked, User $user): void
|
||||
public function setLike(bool $liked, User $user): void
|
||||
{
|
||||
$this->setLikeRecursively($liked, $user, 1);
|
||||
}
|
||||
|
||||
function deletePost(): void
|
||||
public function deletePost(): void
|
||||
{
|
||||
$this->setDeleted(1);
|
||||
$this->unwire();
|
||||
$this->save();
|
||||
}
|
||||
|
||||
use Traits\TRichText;
|
||||
public function canBeViewedBy(?User $user = null): bool
|
||||
{
|
||||
if ($this->isDeleted()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->getWallOwner()->canBeViewedBy($user);
|
||||
}
|
||||
|
||||
public function getSuggestionType()
|
||||
{
|
||||
return $this->getRecord()->suggested;
|
||||
}
|
||||
|
||||
public function getPageURL(): string
|
||||
{
|
||||
return "/wall" . $this->getPrettyId();
|
||||
}
|
||||
|
||||
public function toNotifApiStruct()
|
||||
{
|
||||
$res = (object) [];
|
||||
|
||||
$res->id = $this->getVirtualId();
|
||||
$res->to_id = $this->getOwner() instanceof Club ? $this->getOwner()->getId() * -1 : $this->getOwner()->getId();
|
||||
$res->from_id = $res->to_id;
|
||||
$res->date = $this->getPublicationTime()->timestamp();
|
||||
$res->text = $this->getText(false);
|
||||
$res->attachments = []; # todo
|
||||
|
||||
$res->copy_owner_id = null; # todo
|
||||
$res->copy_post_id = null; # todo
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function canBeEditedBy(?User $user = null): bool
|
||||
{
|
||||
if (!$user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->isDeactivationMessage() || $this->isUpdateAvatarMessage()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->getTargetWall() > 0) {
|
||||
return $this->getPublicationTime()->timestamp() + WEEK > time() && $user->getId() == $this->getOwner(false)->getId();
|
||||
} else {
|
||||
if ($this->isPostedOnBehalfOfGroup()) {
|
||||
return $this->getWallOwner()->canBeModifiedBy($user);
|
||||
} else {
|
||||
return $user->getId() == $this->getOwner(false)->getId();
|
||||
}
|
||||
}
|
||||
|
||||
return $user->getId() == $this->getOwner(false)->getId();
|
||||
}
|
||||
|
||||
public function toRss(): \Bhaktaraz\RSSGenerator\Item
|
||||
{
|
||||
$domain = ovk_scheme(true) . $_SERVER["HTTP_HOST"];
|
||||
$description = $this->getText(false);
|
||||
$title = str_replace("\n", "", ovk_proc_strtr($description, 79));
|
||||
$description_html = $description;
|
||||
$url = $domain . "/wall" . $this->getPrettyId();
|
||||
|
||||
if ($this->isUpdateAvatarMessage()) {
|
||||
$title = tr('upd_in_general');
|
||||
}
|
||||
if ($this->isDeactivationMessage()) {
|
||||
$title = tr('post_deact_in_general');
|
||||
}
|
||||
|
||||
$author = $this->getOwner();
|
||||
$target_wall = $this->getWallOwner();
|
||||
$author_name = escape_html($author->getCanonicalName());
|
||||
if ($this->isExplicit()) {
|
||||
$title = 'NSFW: ' . $title;
|
||||
}
|
||||
|
||||
foreach ($this->getChildren() as $child) {
|
||||
if ($child instanceof Photo) {
|
||||
$child_page = $domain . $child->getPageURL();
|
||||
$child_url = $child->getURL();
|
||||
$description_html .= "<br /><a href='$child_page'><img src='$child_url'></a><br />";
|
||||
} elseif ($child instanceof Video) {
|
||||
$child_page = $domain . '/video' . $child->getPrettyId();
|
||||
|
||||
if ($child->getType() != 1) {
|
||||
$description_html .= "" .
|
||||
"<br />" .
|
||||
"<video width=\"320\" height=\"240\" controls><source src=\"" . $child->getURL() . "\" type=\"video/mp4\"></video><br />" .
|
||||
"<b>" . escape_html($child->getName()) . "</b><br />";
|
||||
} else {
|
||||
$description_html .= "" .
|
||||
"<br />" .
|
||||
"<a href=\"" . $child->getVideoDriver()->getURL() . "\"><b>" . escape_html($child->getName()) . "</b></a><br />";
|
||||
}
|
||||
} elseif ($child instanceof Audio) {
|
||||
if (!$child->isWithdrawn()) {
|
||||
$description_html .= "<br />"
|
||||
. "<b>" . escape_html($child->getName()) . "</b>:"
|
||||
. "<br />"
|
||||
. "<audio controls>"
|
||||
. "<source src=\"" . $child->getOriginalURL() . "\" type=\"audio/mpeg\"></audio>"
|
||||
. "<br />";
|
||||
}
|
||||
} elseif ($child instanceof Poll) {
|
||||
$description_html .= "<br />" . tr('poll') . ": " . escape_html($child->getTitle());
|
||||
} elseif ($child instanceof Note) {
|
||||
$description_html .= "<br />" . tr('note') . ": " . escape_html($child->getName());
|
||||
}
|
||||
}
|
||||
|
||||
$description_html .= "<br />" . tr('author') . ": <img width='15px' src='" . $author->getAvatarURL() . "'><a href='" . $author->getURL() . "'>" . $author_name . "</a>";
|
||||
|
||||
if ($target_wall->getRealId() != $author->getRealId()) {
|
||||
$description_html .= "<br />" . tr('on_wall') . ": <img width='15px' src='" . $target_wall->getAvatarURL() . "'><a href='" . $target_wall->getURL() . "'>" . escape_html($target_wall->getCanonicalName()) . "</a>";
|
||||
}
|
||||
|
||||
if ($this->isSigned()) {
|
||||
$signer = $this->getOwner(false);
|
||||
$description_html .= "<br />" . tr('sign_short') . ": <img width='15px' src='" . $signer->getAvatarURL() . "'><a href='" . $signer->getURL() . "'>" . escape_html($signer->getCanonicalName()) . "</a>";
|
||||
}
|
||||
|
||||
if ($this->hasSource()) {
|
||||
$description_html .= "<br />" . tr('source') . ": " . escape_html($this->getSource());
|
||||
}
|
||||
|
||||
$item = new \Bhaktaraz\RSSGenerator\Item();
|
||||
$item->title($title)
|
||||
->url($url)
|
||||
->guid($url)
|
||||
->creator($author_name)
|
||||
->pubDate($this->getPublicationTime()->timestamp())
|
||||
->content(str_replace("\n", "<br />", $description_html));
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
public function getGeo(): ?object
|
||||
{
|
||||
if (!$this->getRecord()->geo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (object) json_decode($this->getRecord()->geo, true, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
public function setGeo($encoded_object): void
|
||||
{
|
||||
$final_geo = $encoded_object['name'];
|
||||
$neutral_names = ["Россия", "Russia", "Росія", "Россія", "Украина", "Ukraine", "Україна", "Украіна"];
|
||||
foreach ($neutral_names as $name) {
|
||||
if (str_contains($final_geo, $name . ", ")) {
|
||||
$final_geo = str_replace($name . ", ", "", $final_geo);
|
||||
}
|
||||
}
|
||||
|
||||
$encoded_object['name'] = ovk_proc_strtr($final_geo, 255);
|
||||
$encoded = json_encode($encoded_object);
|
||||
$this->stateChanges("geo", $encoded);
|
||||
}
|
||||
|
||||
public function getLat(): ?float
|
||||
{
|
||||
return (float) $this->getRecord()->geo_lat ?? null;
|
||||
}
|
||||
|
||||
public function getLon(): ?float
|
||||
{
|
||||
return (float) $this->getRecord()->geo_lon ?? null;
|
||||
}
|
||||
|
||||
public function getVkApiGeo(): object
|
||||
{
|
||||
return (object) [
|
||||
'type' => 'point',
|
||||
'coordinates' => $this->getLat() . ',' . $this->getLon(),
|
||||
'name' => $this->getGeo()->name,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use openvk\Web\Util\DateTime;
|
||||
use openvk\Web\Models\RowModel;
|
||||
use openvk\Web\Models\Entities\User;
|
||||
|
@ -12,6 +16,8 @@ use Nette\Database\Table\Selection;
|
|||
|
||||
abstract class Postable extends Attachable
|
||||
{
|
||||
use Traits\TAttachmentHost;
|
||||
use Traits\TOwnable;
|
||||
/**
|
||||
* Column name, that references to an object, that
|
||||
* is hieararchically higher than this Postable.
|
||||
|
@ -29,57 +35,62 @@ abstract class Postable extends Attachable
|
|||
return DB::i()->getContext()->table($this->tableName);
|
||||
}
|
||||
|
||||
function getOwner(bool $real = false): RowModel
|
||||
public function getOwner(bool $real = false): RowModel
|
||||
{
|
||||
$oid = (int) $this->getRecord()->owner;
|
||||
if(!$real && $this->isAnonymous())
|
||||
$oid = OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["anonymousPosting"]["account"];
|
||||
|
||||
if($oid > 0)
|
||||
return (new Users)->get($oid);
|
||||
else
|
||||
return (new Clubs)->get($oid * -1);
|
||||
if (!$real && $this->isAnonymous()) {
|
||||
$oid = (int) OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["anonymousPosting"]["account"];
|
||||
}
|
||||
|
||||
function getVirtualId(): int
|
||||
$oid = abs($oid);
|
||||
if ($oid > 0) {
|
||||
return (new Users())->get($oid);
|
||||
} else {
|
||||
return (new Clubs())->get($oid * -1);
|
||||
}
|
||||
}
|
||||
|
||||
public function getVirtualId(): int
|
||||
{
|
||||
return $this->getRecord()->virtual_id;
|
||||
}
|
||||
|
||||
function getPrettyId(): string
|
||||
public function getPrettyId(): string
|
||||
{
|
||||
return $this->getRecord()->owner . "_" . $this->getVirtualId();
|
||||
}
|
||||
|
||||
function getPublicationTime(): DateTime
|
||||
public function getPublicationTime(): DateTime
|
||||
{
|
||||
return new DateTime($this->getRecord()->created);
|
||||
}
|
||||
|
||||
function getEditTime(): ?DateTime
|
||||
public function getEditTime(): ?DateTime
|
||||
{
|
||||
$edited = $this->getRecord()->edited;
|
||||
if(is_null($edited)) return NULL;
|
||||
if (is_null($edited)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new DateTime($edited);
|
||||
}
|
||||
|
||||
function getComments(int $page, ?int $perPage = NULL): \Traversable
|
||||
public function getComments(int $page, ?int $perPage = null): \Traversable
|
||||
{
|
||||
return (new Comments)->getCommentsByTarget($this, $page, $perPage);
|
||||
return (new Comments())->getCommentsByTarget($this, $page, $perPage);
|
||||
}
|
||||
|
||||
function getCommentsCount(): int
|
||||
public function getCommentsCount(): int
|
||||
{
|
||||
return (new Comments)->getCommentsCountByTarget($this);
|
||||
return (new Comments())->getCommentsCountByTarget($this);
|
||||
}
|
||||
|
||||
function getLastComments(int $count): \Traversable
|
||||
public function getLastComments(int $count): \Traversable
|
||||
{
|
||||
return (new Comments)->getLastCommentsByTarget($this, $count);
|
||||
return (new Comments())->getLastCommentsByTarget($this, $count);
|
||||
}
|
||||
|
||||
function getLikesCount(): int
|
||||
public function getLikesCount(): int
|
||||
{
|
||||
return sizeof(DB::i()->getContext()->table("likes")->where([
|
||||
"model" => static::class,
|
||||
|
@ -87,24 +98,50 @@ abstract class Postable extends Attachable
|
|||
])->group("origin"));
|
||||
}
|
||||
|
||||
# TODO add pagination
|
||||
function getLikers(): \Traversable
|
||||
public function getLikers(int $page = 1, ?int $perPage = null): \Traversable
|
||||
{
|
||||
$perPage ??= OPENVK_DEFAULT_PER_PAGE;
|
||||
|
||||
$sel = DB::i()->getContext()->table("likes")->where([
|
||||
"model" => static::class,
|
||||
"target" => $this->getRecord()->id,
|
||||
]);
|
||||
])->page($page, $perPage);
|
||||
|
||||
foreach($sel as $like)
|
||||
yield (new Users)->get($like->origin);
|
||||
foreach ($sel as $like) {
|
||||
$user = (new Users())->get($like->origin);
|
||||
if ($user->isPrivateLikes() && OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["anonymousPosting"]["enable"]) {
|
||||
$user = (new Users())->get((int) OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["anonymousPosting"]["account"]);
|
||||
}
|
||||
|
||||
function isAnonymous(): bool
|
||||
yield $user;
|
||||
}
|
||||
}
|
||||
|
||||
public function getAccessKey(): string
|
||||
{
|
||||
return $this->getRecord()->access_key;
|
||||
}
|
||||
|
||||
public function checkAccessKey(?string $access_key): bool
|
||||
{
|
||||
if ($this->getAccessKey() === $access_key) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !$this->isPrivate();
|
||||
}
|
||||
|
||||
public function isPrivate(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->unlisted;
|
||||
}
|
||||
|
||||
public function isAnonymous(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->anonymous;
|
||||
}
|
||||
|
||||
function toggleLike(User $user): bool
|
||||
public function toggleLike(User $user): bool
|
||||
{
|
||||
$searchData = [
|
||||
"origin" => $user->getId(),
|
||||
|
@ -112,7 +149,7 @@ abstract class Postable extends Attachable
|
|||
"target" => $this->getRecord()->id,
|
||||
];
|
||||
|
||||
if(sizeof(DB::i()->getContext()->table("likes")->where($searchData)) > 0) {
|
||||
if (sizeof(DB::i()->getContext()->table("likes")->where($searchData)) > 0) {
|
||||
DB::i()->getContext()->table("likes")->where($searchData)->delete();
|
||||
return false;
|
||||
}
|
||||
|
@ -121,7 +158,7 @@ abstract class Postable extends Attachable
|
|||
return true;
|
||||
}
|
||||
|
||||
function setLike(bool $liked, User $user): void
|
||||
public function setLike(bool $liked, User $user): void
|
||||
{
|
||||
$searchData = [
|
||||
"origin" => $user->getId(),
|
||||
|
@ -129,13 +166,18 @@ abstract class Postable extends Attachable
|
|||
"target" => $this->getRecord()->id,
|
||||
];
|
||||
|
||||
if($liked)
|
||||
if ($liked) {
|
||||
if (!$this->hasLikeFrom($user)) {
|
||||
DB::i()->getContext()->table("likes")->insert($searchData);
|
||||
else
|
||||
}
|
||||
} else {
|
||||
if ($this->hasLikeFrom($user)) {
|
||||
DB::i()->getContext()->table("likes")->where($searchData)->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function hasLikeFrom(User $user): bool
|
||||
public function hasLikeFrom(User $user): bool
|
||||
{
|
||||
$searchData = [
|
||||
"origin" => $user->getId(),
|
||||
|
@ -146,33 +188,32 @@ abstract class Postable extends Attachable
|
|||
return sizeof(DB::i()->getContext()->table("likes")->where($searchData)) > 0;
|
||||
}
|
||||
|
||||
function setVirtual_Id(int $id): void
|
||||
public function setVirtual_Id(int $id): void
|
||||
{
|
||||
throw new ISE("Setting virtual id manually is forbidden");
|
||||
}
|
||||
|
||||
function save(): void
|
||||
public function save(?bool $log = false): void
|
||||
{
|
||||
$vref = $this->upperNodeReferenceColumnName;
|
||||
|
||||
$vid = $this->getRecord()->{$vref} ?? $this->changes[$vref];
|
||||
if(!$vid)
|
||||
if (!$vid) {
|
||||
throw new ISE("Can't presist post due to inability to calculate it's $vref post count. Have you set it?");
|
||||
}
|
||||
|
||||
$pCount = sizeof($this->getTable()->where($vref, $vid));
|
||||
if(is_null($this->getRecord())) {
|
||||
if (is_null($this->getRecord())) {
|
||||
# lol allow ppl to taint created value
|
||||
if(!isset($this->changes["created"]))
|
||||
if (!isset($this->changes["created"])) {
|
||||
$this->stateChanges("created", time());
|
||||
}
|
||||
|
||||
$this->stateChanges("virtual_id", $pCount + 1);
|
||||
} else {
|
||||
} /*else {
|
||||
$this->stateChanges("edited", time());
|
||||
}
|
||||
}*/
|
||||
|
||||
parent::save();
|
||||
parent::save($log);
|
||||
}
|
||||
|
||||
use Traits\TAttachmentHost;
|
||||
use Traits\TOwnable;
|
||||
}
|
||||
|
|
177
Web/Models/Entities/Report.php
Normal file
177
Web/Models/Entities/Report.php
Normal file
|
@ -0,0 +1,177 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use openvk\Web\Util\DateTime;
|
||||
use Nette\Database\Table\ActiveRow;
|
||||
use openvk\Web\Models\RowModel;
|
||||
use openvk\Web\Models\Entities\Club;
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
use openvk\Web\Models\Repositories\{Applications, Comments, Notes, Reports, Audios, Documents, Users, Posts, Photos, Videos, Clubs};
|
||||
use Chandler\Database\DatabaseConnection as DB;
|
||||
use Nette\InvalidStateException as ISE;
|
||||
use Nette\Database\Table\Selection;
|
||||
|
||||
class Report extends RowModel
|
||||
{
|
||||
protected $tableName = "reports";
|
||||
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->getRecord()->id;
|
||||
}
|
||||
|
||||
public function getStatus(): int
|
||||
{
|
||||
return $this->getRecord()->status;
|
||||
}
|
||||
|
||||
public function getContentType(): string
|
||||
{
|
||||
return $this->getRecord()->type;
|
||||
}
|
||||
|
||||
public function getReason(): string
|
||||
{
|
||||
return $this->getRecord()->reason;
|
||||
}
|
||||
|
||||
public function getTime(): DateTime
|
||||
{
|
||||
return new DateTime($this->getRecord()->date);
|
||||
}
|
||||
|
||||
public function isDeleted(): bool
|
||||
{
|
||||
if ($this->getRecord()->deleted === 0) {
|
||||
return false;
|
||||
} elseif ($this->getRecord()->deleted === 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function authorId(): int
|
||||
{
|
||||
return $this->getRecord()->user_id;
|
||||
}
|
||||
|
||||
public function getUser(): User
|
||||
{
|
||||
return (new Users())->get((int) $this->getRecord()->user_id);
|
||||
}
|
||||
|
||||
public function getContentId(): int
|
||||
{
|
||||
return (int) $this->getRecord()->target_id;
|
||||
}
|
||||
|
||||
public function getContentObject()
|
||||
{
|
||||
if ($this->getContentType() == "post") {
|
||||
return (new Posts())->get($this->getContentId());
|
||||
} elseif ($this->getContentType() == "photo") {
|
||||
return (new Photos())->get($this->getContentId());
|
||||
} elseif ($this->getContentType() == "video") {
|
||||
return (new Videos())->get($this->getContentId());
|
||||
} elseif ($this->getContentType() == "group") {
|
||||
return (new Clubs())->get($this->getContentId());
|
||||
} elseif ($this->getContentType() == "comment") {
|
||||
return (new Comments())->get($this->getContentId());
|
||||
} elseif ($this->getContentType() == "note") {
|
||||
return (new Notes())->get($this->getContentId());
|
||||
} elseif ($this->getContentType() == "app") {
|
||||
return (new Applications())->get($this->getContentId());
|
||||
} elseif ($this->getContentType() == "user") {
|
||||
return (new Users())->get($this->getContentId());
|
||||
} elseif ($this->getContentType() == "audio") {
|
||||
return (new Audios())->get($this->getContentId());
|
||||
} elseif ($this->getContentType() == "doc") {
|
||||
return (new Documents())->get($this->getContentId());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function getAuthor(): RowModel
|
||||
{
|
||||
return $this->getContentObject()->getOwner();
|
||||
}
|
||||
|
||||
public function getReportAuthor(): User
|
||||
{
|
||||
return (new Users())->get($this->getRecord()->user_id);
|
||||
}
|
||||
|
||||
public function banUser($initiator)
|
||||
{
|
||||
$reason = $this->getContentType() !== "user" ? ("**content-" . $this->getContentType() . "-" . $this->getContentId() . "**") : ("Подозрительная активность");
|
||||
$this->getAuthor()->ban($reason, false, time() + $this->getAuthor()->getNewBanTime(), $initiator);
|
||||
}
|
||||
|
||||
public function deleteContent()
|
||||
{
|
||||
if ($this->getContentType() !== "user") {
|
||||
$pubTime = $this->getContentObject()->getPublicationTime();
|
||||
if (method_exists($this->getContentObject(), "getName")) {
|
||||
$name = $this->getContentObject()->getName();
|
||||
$placeholder = "$pubTime ($name)";
|
||||
} else {
|
||||
$placeholder = "$pubTime";
|
||||
}
|
||||
|
||||
if ($this->getAuthor() instanceof Club) {
|
||||
$name = $this->getAuthor()->getName();
|
||||
$this->getAuthor()->getOwner()->adminNotify("Ваш контент, который опубликовали $placeholder в созданной вами группе \"$name\" был удалён модераторами инстанса. За повторные или серьёзные нарушения группу могут заблокировать.");
|
||||
} else {
|
||||
$this->getAuthor()->adminNotify("Ваш контент, который вы опубликовали $placeholder был удалён модераторами инстанса. За повторные или серьёзные нарушения вас могут заблокировать.");
|
||||
}
|
||||
$this->getContentObject()->delete($this->getContentType() !== "app");
|
||||
}
|
||||
|
||||
$this->delete();
|
||||
}
|
||||
|
||||
public function getDuplicates(): \Traversable
|
||||
{
|
||||
return (new Reports())->getDuplicates($this->getContentType(), $this->getContentId(), $this->getId());
|
||||
}
|
||||
|
||||
public function getDuplicatesCount(): int
|
||||
{
|
||||
return count(iterator_to_array($this->getDuplicates()));
|
||||
}
|
||||
|
||||
public function hasDuplicates(): bool
|
||||
{
|
||||
return $this->getDuplicatesCount() > 0;
|
||||
}
|
||||
|
||||
public function getContentName(): string
|
||||
{
|
||||
$content_object = $this->getContentObject();
|
||||
if (!$content_object) {
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
if (method_exists($content_object, "getCanonicalName")) {
|
||||
return $content_object->getCanonicalName();
|
||||
}
|
||||
|
||||
return $this->getContentType() . " #" . $this->getContentId();
|
||||
}
|
||||
|
||||
public function delete(bool $softly = true): void
|
||||
{
|
||||
if ($this->hasDuplicates()) {
|
||||
foreach ($this->getDuplicates() as $duplicate) {
|
||||
$duplicate->setDeleted(1);
|
||||
$duplicate->save();
|
||||
}
|
||||
}
|
||||
|
||||
$this->setDeleted(1);
|
||||
$this->save();
|
||||
}
|
||||
}
|
|
@ -1,5 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Models\Entities;
|
||||
|
||||
use openvk\Web\Models\Repositories\Users;
|
||||
use openvk\Web\Models\RowModel;
|
||||
|
||||
|
@ -7,33 +11,33 @@ class SupportAgent extends RowModel
|
|||
{
|
||||
protected $tableName = "support_names";
|
||||
|
||||
function getAgentId(): int
|
||||
public function getAgentId(): int
|
||||
{
|
||||
return $this->getRecord()->agent;
|
||||
}
|
||||
|
||||
function getName(): ?string
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->getRecord()->name;
|
||||
}
|
||||
|
||||
function getCanonicalName(): string
|
||||
public function getCanonicalName(): string
|
||||
{
|
||||
return $this->getName();
|
||||
}
|
||||
|
||||
function getAvatarURL(): ?string
|
||||
public function getAvatarURL(): ?string
|
||||
{
|
||||
return $this->getRecord()->icon;
|
||||
}
|
||||
|
||||
function isShowNumber(): int
|
||||
public function isShowNumber(): int
|
||||
{
|
||||
return $this->getRecord()->numerate;
|
||||
}
|
||||
|
||||
function getRealName(): string
|
||||
public function getRealName(): string
|
||||
{
|
||||
return (new Users)->get($this->getAgentId())->getCanonicalName();
|
||||
return (new Users())->get($this->getAgentId())->getCanonicalName();
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue