mirror of
https://github.com/openvk/openvk
synced 2025-04-23 08:33:02 +03:00
Merge branch 'master' into disco
This commit is contained in:
commit
3e119ccbc6
254 changed files with 9305 additions and 3330 deletions
|
@ -1,11 +1,8 @@
|
||||||
<?xml encoding="UTF-8"?>
|
<?xml encoding="UTF-8"?>
|
||||||
|
|
||||||
<!ELEMENT latte (tags,filters,variables,functions)>
|
<!ELEMENT latte (tags,filters,variables,functions)>
|
||||||
<!ATTLIST latte vendor #REQUIRED>
|
<!ATTLIST latte vendor #REQUIRED>
|
||||||
<!ATTLIST latte version #REQUIRED>
|
<!ATTLIST latte version #REQUIRED>
|
||||||
|
|
||||||
<!ELEMENT tags (tag)+>
|
<!ELEMENT tags (tag)+>
|
||||||
|
|
||||||
<!ELEMENT tag (arguments)?>
|
<!ELEMENT tag (arguments)?>
|
||||||
<!ATTLIST tag name CDATA #REQUIRED>
|
<!ATTLIST tag name CDATA #REQUIRED>
|
||||||
<!ATTLIST tag type (PAIR|UNPAIRED|UNPAIRED_ATTR|ATTR_ONLY|AUTO_EMPTY) #REQUIRED>
|
<!ATTLIST tag type (PAIR|UNPAIRED|UNPAIRED_ATTR|ATTR_ONLY|AUTO_EMPTY) #REQUIRED>
|
||||||
|
@ -13,32 +10,24 @@
|
||||||
<!ATTLIST tag arguments CDATA #IMPLIED>
|
<!ATTLIST tag arguments CDATA #IMPLIED>
|
||||||
<!ATTLIST tag deprecatedMessage CDATA #IMPLIED>
|
<!ATTLIST tag deprecatedMessage CDATA #IMPLIED>
|
||||||
<!ATTLIST tag multiLine (true|false) #IMPLIED>
|
<!ATTLIST tag multiLine (true|false) #IMPLIED>
|
||||||
|
|
||||||
<!ELEMENT arguments (argument)+>
|
<!ELEMENT arguments (argument)+>
|
||||||
|
|
||||||
<!ELEMENT argument EMPTY>
|
<!ELEMENT argument EMPTY>
|
||||||
<!ATTLIST argument name #REQUIRED>
|
<!ATTLIST argument name #REQUIRED>
|
||||||
<!ATTLIST argument types CDATA #REQUIRED>
|
<!ATTLIST argument types CDATA #REQUIRED>
|
||||||
<!ATTLIST argument repeatable (true|false) #IMPLIED>
|
<!ATTLIST argument repeatable (true|false) #IMPLIED>
|
||||||
<!ATTLIST argument required (true|false) #IMPLIED>
|
<!ATTLIST argument required (true|false) #IMPLIED>
|
||||||
<!ATTLIST argument validType #IMPLIED>
|
<!ATTLIST argument validType #IMPLIED>
|
||||||
|
|
||||||
<!ELEMENT filters (filter)+>
|
<!ELEMENT filters (filter)+>
|
||||||
|
|
||||||
<!ELEMENT filter EMPTY>
|
<!ELEMENT filter EMPTY>
|
||||||
<!ATTLIST filter name #REQUIRED>
|
<!ATTLIST filter name #REQUIRED>
|
||||||
<!ATTLIST filter description CDATA #IMPLIED>
|
<!ATTLIST filter description CDATA #IMPLIED>
|
||||||
<!ATTLIST filter arguments CDATA #IMPLIED>
|
<!ATTLIST filter arguments CDATA #IMPLIED>
|
||||||
<!ATTLIST filter insertColons #IMPLIED>
|
<!ATTLIST filter insertColons #IMPLIED>
|
||||||
|
|
||||||
<!ELEMENT variables (variable)+>
|
<!ELEMENT variables (variable)+>
|
||||||
|
|
||||||
<!ELEMENT variable EMPTY>
|
<!ELEMENT variable EMPTY>
|
||||||
<!ATTLIST variable name #REQUIRED>
|
<!ATTLIST variable name #REQUIRED>
|
||||||
<!ATTLIST variable type CDATA #REQUIRED>
|
<!ATTLIST variable type CDATA #REQUIRED>
|
||||||
|
|
||||||
<!ELEMENT functions (function)+>
|
<!ELEMENT functions (function)+>
|
||||||
|
|
||||||
<!ELEMENT function EMPTY>
|
<!ELEMENT function EMPTY>
|
||||||
<!ATTLIST function name #REQUIRED>
|
<!ATTLIST function name #REQUIRED>
|
||||||
<!ATTLIST function arguments CDATA #REQUIRED>
|
<!ATTLIST function arguments CDATA #REQUIRED>
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/console" />
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/console" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php80" />
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php80" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/service-contracts" />
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/service-contracts" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/wapmorgan/morphos" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/console" />
|
<path value="$PROJECT_DIR$/vendor/symfony/console" />
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php80" />
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php80" />
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/service-contracts" />
|
<path value="$PROJECT_DIR$/vendor/symfony/service-contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/wapmorgan/morphos" />
|
||||||
</include_path>
|
</include_path>
|
||||||
</component>
|
</component>
|
||||||
<component name="PhpProjectSharedConfiguration" php_language_level="7.4">
|
<component name="PhpProjectSharedConfiguration" php_language_level="7.4">
|
||||||
|
|
103
CLI/FetchToncoinTransactions.php
Executable file
103
CLI/FetchToncoinTransactions.php
Executable file
|
@ -0,0 +1,103 @@
|
||||||
|
<?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;
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Nette\Utils\ImageException;
|
||||||
|
|
||||||
|
define("NANOTON", 1000000000);
|
||||||
|
|
||||||
|
class FetchToncoinTransactions extends Command
|
||||||
|
{
|
||||||
|
private $images;
|
||||||
|
|
||||||
|
protected static $defaultName = "fetch-ton";
|
||||||
|
|
||||||
|
function __construct()
|
||||||
|
{
|
||||||
|
$this->transactions = DatabaseConnection::i()->getContext()->table("cryptotransactions");
|
||||||
|
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function configure(): void
|
||||||
|
{
|
||||||
|
$this->setDescription("Fetches TON transactions to top up the users' balance")
|
||||||
|
->setHelp("This command checks for new transactions on TON Wallet and then top up the balance of specified users");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
|
{
|
||||||
|
$header = $output->section();
|
||||||
|
|
||||||
|
$header->writeln([
|
||||||
|
"TONCOIN Fetcher",
|
||||||
|
"=====================",
|
||||||
|
"",
|
||||||
|
]);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
$testnetSubdomain = OPENVK_ROOT_CONF["openvk"]["preferences"]["ton"]["testnet"] ? "testnet." : "";
|
||||||
|
$url = "https://" . $testnetSubdomain . "toncenter.com/api/v2/getTransactions?";
|
||||||
|
|
||||||
|
$opts = [
|
||||||
|
"http" => [
|
||||||
|
"method" => "GET",
|
||||||
|
"header" => "Accept: application/json"
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$selection = $this->transactions->select('hash, lt')->order("id DESC")->limit(1)->fetch();
|
||||||
|
$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
|
||||||
|
]);
|
||||||
|
|
||||||
|
$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) {
|
||||||
|
$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)) {
|
||||||
|
$header->writeln("Well, that's a donation. Thanks! XD");
|
||||||
|
} else {
|
||||||
|
$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();
|
||||||
|
$header->writeln($value . " coins are added to " . $user->getId() . " user id");
|
||||||
|
$this->transactions->insert([
|
||||||
|
"id" => NULL,
|
||||||
|
"hash" => $transfer["transaction_id"]["hash"],
|
||||||
|
"lt" => $transfer["transaction_id"]["lt"]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$header->writeln("Processing finished :3");
|
||||||
|
|
||||||
|
return Command::SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
11
CODE_OF_CONFLICT.md
Normal file
11
CODE_OF_CONFLICT.md
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
The OpenVK development effort is a very personal process compared to "traditional" ways of developing software.
|
||||||
|
Your code and ideas behind it will be carefully reviewed, often resulting in critique and criticism.
|
||||||
|
The review will almost always require improvements to the code before it can be included in the repo.
|
||||||
|
Know that this happens because everyone involved wants to see the best possible solution for the overall success of OpenVK.
|
||||||
|
|
||||||
|
If however, anyone feels personally abused, threatened, or otherwise uncomfortable due to this process, that is not acceptable.
|
||||||
|
If so, please contact the community manager @WerySkok and report the issue.
|
||||||
|
|
||||||
|
As a reviewer of code, please strive to keep things civil and focused on the technical issues involved. We are all humans,
|
||||||
|
and frustrations can be high on both sides of the process.
|
||||||
|
Try to keep in mind the immortal words of Bill and Ted, "Be excellent to each other."
|
277
CODE_STYLE.md
Normal file
277
CODE_STYLE.md
Normal file
|
@ -0,0 +1,277 @@
|
||||||
|
# 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:
|
||||||
|

|
||||||
|
|
||||||
|
+ 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";
|
||||||
|
}
|
||||||
|
```
|
204
Email/change-email.eml.latte
Normal file
204
Email/change-email.eml.latte
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<title>Подтверждение изменения Email</title>
|
||||||
|
<link rel="stylesheet" href="foundation.css" />
|
||||||
|
<style>
|
||||||
|
.container {
|
||||||
|
border-top: 5px solid pink;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<table class="body" data-made-with-foundation="">
|
||||||
|
<tr>
|
||||||
|
<td class="float-center" align="center" valign="top">
|
||||||
|
<center>
|
||||||
|
<table class="spacer">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<table class="container">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<table class="row header">
|
||||||
|
<tr>
|
||||||
|
<th class="small-12 large-12 columns first last">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<table class="spacer">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<h4 class="text-center">Подтверждение изменения Email</h4>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table class="row">
|
||||||
|
<tr>
|
||||||
|
<th class="small-12 large-12 columns first last">
|
||||||
|
<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>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
<table class="spacer">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p class="text-left">
|
||||||
|
Здравствуйте, {$name}! Вы вероятно изменили свой адрес электронной почты в OpenVK. Чтобы изменение вступило в силу, необходимо подтвердить ваш новый Email.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<table class="spacer">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table class="button large expand success">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<center>
|
||||||
|
<a href="http://{$_SERVER['HTTP_HOST']}/settings/change_email?key={rawurlencode($key)}" align="center" class="float-center">Подтвердить Email!</a>
|
||||||
|
</center>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table class="spacer">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p class="text-left">
|
||||||
|
Если кнопка не работает, вы можете попробовать скопировать и вставить эту ссылку в адресную строку вашего веб-обозревателя:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p class="text-left">
|
||||||
|
Обратите внимание на то, что эту ссылку нельзя:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Передавать другим людям (даже друзьям, питомцам, соседам, любимым девушкам)</li>
|
||||||
|
<li>Использовать, если прошло более двух дней с её генерации</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<table class="callout">
|
||||||
|
<tr>
|
||||||
|
<th class="callout-inner alert">
|
||||||
|
<p>
|
||||||
|
Ещё раз <b>обратите внимание</b> на то, что данную ссылку или письмо <b>ни в коем случае нельзя</b> передавать другим людям! Даже если они представляются службой поддержки.<br/>
|
||||||
|
Это письмо предназначено исключительно для одноразового, <b>непосредственного</b> использования владельцем аккаунта.
|
||||||
|
</p>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table class="spacer">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p class="text-right">
|
||||||
|
С уважением, овк-тян.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<table class="spacer">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
<table class="spacer">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p class="text-left">
|
||||||
|
<small>
|
||||||
|
Вы получили это письмо так как кто-то или вы изменили адрес электронной почты. Это не рассылка и от неё нельзя отписаться. Если вы всё равно хотите перестать получать подобные письма, деактивируйте ваш аккаунт.
|
||||||
|
</small>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<table class="spacer">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</center>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
32
README.md
32
README.md
|
@ -12,13 +12,15 @@ To be honest, we don't know whether it even works. However, this version is main
|
||||||
|
|
||||||
We will release OpenVK as soon as it's ready. As for now you can:
|
We will release OpenVK as soon as it's ready. As for now you can:
|
||||||
* `git clone` this repo's master branch (use `git pull` to update)
|
* `git clone` this repo's master branch (use `git pull` to update)
|
||||||
* Grab a prebuilt OpenVK distro from [GitHub artifacts](https://github.com/openvk/archive/actions/workflows/nightly.yml)
|
* Grab a prebuilt OpenVK distro from [GitHub artifacts](https://nightly.link/openvk/archive/workflows/nightly/master/OpenVK%20Archive.zip)
|
||||||
|
|
||||||
## Instances
|
## Instances
|
||||||
|
|
||||||
* **[openvk.su](https://openvk.su/)**
|
* **[openvk.su](https://openvk.su/)**
|
||||||
* **[openvk.uk](https://openvk.uk)** - official mirror of openvk.su (<https://t.me/openvkch/1609>)
|
* **[openvk.uk](https://openvk.uk)** - official mirror of openvk.su (<https://t.me/openvk/1609>)
|
||||||
|
* **[openvk.co](http://openvk.co)** - yet another official mirror of openvk.su without TLS (<https://t.me/openvk/1654>)
|
||||||
* [social.fetbuk.ru](http://social.fetbuk.ru/)
|
* [social.fetbuk.ru](http://social.fetbuk.ru/)
|
||||||
|
* [vepurovk.xyz](http://vepurovk.xyz/)
|
||||||
|
|
||||||
## Can I create my own OpenVK instance?
|
## Can I create my own OpenVK instance?
|
||||||
|
|
||||||
|
@ -32,29 +34,35 @@ If you want, you can add your instance to the list above so that people can regi
|
||||||
|
|
||||||
1. Install PHP 7.4, web-server, Composer, Node.js, Yarn and [Chandler](https://github.com/openvk/chandler)
|
1. Install PHP 7.4, web-server, Composer, Node.js, Yarn and [Chandler](https://github.com/openvk/chandler)
|
||||||
|
|
||||||
* PHP 8 has **not** yet been tested, so you should not expect it to work. (edit: it does not work).
|
* PHP 8.1 is supported, but it was not tested carefully, be aware of that.
|
||||||
|
|
||||||
2. Install [commitcaptcha](https://github.com/openvk/commitcaptcha) and OpenVK as Chandler extensions like this:
|
2. Install MySQL-compatible database.
|
||||||
|
|
||||||
|
* We recommend using Percona Server, but any MySQL-compatible server should work
|
||||||
|
* Server should be compatible with at least MySQL 5.6, MySQL 8.0+ recommended.
|
||||||
|
* Support for MySQL 4.1+ is WIP, replace `utf8mb4` and `utf8mb4_unicode_520_ci` with `utf8` and `utf8_unicode_ci` in SQLs.
|
||||||
|
|
||||||
|
3. Install [commitcaptcha](https://github.com/openvk/commitcaptcha) and OpenVK as Chandler extensions like this:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/openvk/openvk /path/to/chandler/extensions/available/openvk
|
git clone https://github.com/openvk/openvk /path/to/chandler/extensions/available/openvk
|
||||||
git clone https://github.com/openvk/commitcaptcha /path/to/chandler/extensions/available/commitcaptcha
|
git clone https://github.com/openvk/commitcaptcha /path/to/chandler/extensions/available/commitcaptcha
|
||||||
```
|
```
|
||||||
|
|
||||||
3. And enable them:
|
4. And enable them:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ln -s /path/to/chandler/extensions/available/commitcaptcha /path/to/chandler/extensions/enabled/
|
ln -s /path/to/chandler/extensions/available/commitcaptcha /path/to/chandler/extensions/enabled/
|
||||||
ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions/enabled/
|
ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions/enabled/
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Import `install/init-static-db.sql` to the **same database** you installed Chandler to and import all sqls from `install/sqls` to the **same database**
|
5. Import `install/init-static-db.sql` to the **same database** you installed Chandler to and import all sqls from `install/sqls` to the **same database**
|
||||||
5. Import `install/init-event-db.sql` to a **separate database** (Yandex.Clickhouse can also be used, higly recommended)
|
6. Import `install/init-event-db.sql` to a **separate database** (Yandex.Clickhouse can also be used, highly recommended)
|
||||||
6. Copy `openvk-example.yml` to `openvk.yml` and change options to your liking
|
7. Copy `openvk-example.yml` to `openvk.yml` and change options to your liking
|
||||||
7. Run `composer install` in OpenVK directory
|
8. Run `composer install` in OpenVK directory
|
||||||
8. Run `composer install` in commitcaptcha directory
|
9. Run `composer install` in commitcaptcha directory
|
||||||
9. Move to `Web/static/js` and execute `yarn install`
|
10. Move to `Web/static/js` and execute `yarn install`
|
||||||
10. Set `openvk` as your root app in `chandler.yml`
|
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):
|
Once you are done, you can login as a system administrator on the network itself (no registration required):
|
||||||
|
|
||||||
|
|
44
README_RU.md
44
README_RU.md
|
@ -2,23 +2,25 @@
|
||||||
|
|
||||||
_[English](README.md)_
|
_[English](README.md)_
|
||||||
|
|
||||||
**OpenVK** это попытка создать простую CMS, которая ~~косплеит~~ имитирует старый ВКонтакте. Представленный здесь код пока не стабилен.
|
**OpenVK** - это попытка создать простую CMS, которая ~~косплеит~~ имитирует старый ВКонтакте. На данный момент представленный здесь исходный код проекта пока не является стабильным.
|
||||||
|
|
||||||
ВКонтакте принадлежит Павлу Дурову и VK Group.
|
ВКонтакте принадлежит Павлу Дурову и VK Group.
|
||||||
|
|
||||||
Честно говоря, мы даже не знаем, работает ли она вообще. Однако, эта версия поддерживается, и мы будем рады принять ваши сообщения об ошибках [в нашем баг-трекере](https://github.com/openvk/openvk/projects/1). Вы также можете отправлять их через [вкладку "Помощь"](https://openvk.su/support?act=new) (для этого вам понадобится учетная запись OVK).
|
Честно говоря, мы даже не знаем, работает ли она вообще. Однако, эта версия поддерживается, и мы будем рады принять ваши сообщения об ошибках [в нашем баг-трекере](https://github.com/openvk/openvk/projects/1). Вы также можете отправлять их через [вкладку "Помощь"](https://openvk.su/support?act=new) (для этого вам понадобится учетная запись OVK).
|
||||||
|
|
||||||
## Когда релиз?
|
## Когда выйдет релизная версия?
|
||||||
|
|
||||||
Мы выпустим OpenVK, как только он будет готов. На данный момент Вы можете:
|
Мы выпустим OpenVK, как только он будет готов. На данный момент Вы можете:
|
||||||
* Сделать `git clone` master ветки этой репозитории (используйте `git pull` для обновления)
|
* Склонировать master ветку репозитория командой `git clone` (используйте `git pull` для обновления)
|
||||||
* Взять готовую сборку OpenVK из [GitHub Actions](https://github.com/openvk/archive/actions/workflows/nightly.yml)
|
* Взять готовую сборку OpenVK из [GitHub Actions](https://nightly.link/openvk/archive/workflows/nightly/master/OpenVK%20Archive.zip)
|
||||||
|
|
||||||
## Инстанции
|
## Инстанции
|
||||||
|
|
||||||
* **[openvk.su](https://openvk.su/)**
|
* **[openvk.su](https://openvk.su/)**
|
||||||
* **[openvk.uk](https://openvk.uk)** - официальное зеркало openvk.su (<https://t.me/openvkch/1609>)
|
* **[openvk.uk](https://openvk.uk)** - официальное зеркало openvk.su (<https://t.me/openvk/1609>)
|
||||||
|
* **[openvk.co](http://openvk.co)** - ещё одно официальное зеркало openvk.su без TLS (<https://t.me/openvk/1654>)
|
||||||
* [social.fetbuk.ru](http://social.fetbuk.ru/)
|
* [social.fetbuk.ru](http://social.fetbuk.ru/)
|
||||||
|
* [vepurovk.xyz](http://vepurovk.xyz/)
|
||||||
|
|
||||||
## Могу ли я создать свою собственную инстанцию OpenVK?
|
## Могу ли я создать свою собственную инстанцию OpenVK?
|
||||||
|
|
||||||
|
@ -32,35 +34,41 @@ _[English](README.md)_
|
||||||
|
|
||||||
1. Установите PHP 7.4, веб-сервер, Composer, Node.js, Yarn и [Chandler](https://github.com/openvk/chandler)
|
1. Установите PHP 7.4, веб-сервер, Composer, Node.js, Yarn и [Chandler](https://github.com/openvk/chandler)
|
||||||
|
|
||||||
* PHP 8 еще **не** тестировался, поэтому не стоит ожидать, что он будет работать (обновление: он не работает).
|
* PHP 8 еще **не** тестировался, поэтому не стоит ожидать, что он будет работать (UPD: он не работает).
|
||||||
|
|
||||||
2. Установите [commitcaptcha](https://github.com/openvk/commitcaptcha) и OpenVK в качестве расширений Chandler следующим образом:
|
2. Установите MySQL-совместимую базу данных.
|
||||||
|
|
||||||
|
* Мы рекомендуем использовать Persona Server, но любая MySQL-совместимая база данных должна работать
|
||||||
|
* Сервер должен поддерживать хотя бы MySQL 5.6, рекомендуется использовать MySQL 8.0+.
|
||||||
|
* Поддержка для MySQL 4.1+ находится в процессе, а пока замените `utf8mb4` и `utf8mb4_unicode_520_ci` на `utf8` и `utf8_unicode_ci` в SQL-файлах, соответственно.
|
||||||
|
|
||||||
|
3. Установите [commitcaptcha](https://github.com/openvk/commitcaptcha) и OpenVK в качестве расширений Chandler:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/openvk/openvk /path/to/chandler/extensions/available/openvk
|
git clone https://github.com/openvk/openvk /path/to/chandler/extensions/available/openvk
|
||||||
git clone https://github.com/openvk/commitcaptcha /path/to/chandler/extensions/available/commitcaptcha
|
git clone https://github.com/openvk/commitcaptcha /path/to/chandler/extensions/available/commitcaptcha
|
||||||
```
|
```
|
||||||
|
|
||||||
3. И включите их:
|
4. И включите их:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ln -s /path/to/chandler/extensions/available/commitcaptcha /path/to/chandler/extensions/enabled/
|
ln -s /path/to/chandler/extensions/available/commitcaptcha /path/to/chandler/extensions/enabled/
|
||||||
ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions/enabled/
|
ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions/enabled/
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Импортируйте `install/init-static-db.sql` в **ту же базу данных**, в которую вы установили Chandler, и импортируйте все SQL файлы из папки `install/sqls` в **ту же базу данных**
|
5. Импортируйте `install/init-static-db.sql` в **ту же базу данных**, в которую вы установили Chandler, и импортируйте все SQL файлы из папки `install/sqls` в **ту же базу данных**
|
||||||
5. Импортируйте `install/init-event-db.sql` в **отдельную базу данных** (Яндекс.Clickhouse также может быть использован, настоятельно рекомендуется)
|
6. Импортируйте `install/init-event-db.sql` в **отдельную базу данных** (Яндекс.Clickhouse также может быть использован, настоятельно рекомендуется)
|
||||||
6. Скопируйте `openvk-example.yml` в `openvk.yml` и измените параметры
|
7. Скопируйте `openvk-example.yml` в `openvk.yml` и измените параметры под свои нужды
|
||||||
7. Запустите `composer install` в директории OpenVK
|
8. Запустите `composer install` в директории OpenVK
|
||||||
8. Запустите `composer install` в директории commitcaptcha
|
9. Запустите `composer install` в директории commitcaptcha
|
||||||
9. Перейдите в `Web/static/js` и выполните `yarn install`
|
10. Перейдите в `Web/static/js` и выполните `yarn install`
|
||||||
10. Установите `openvk` в качестве корневого приложения в файле `chandler.yml`
|
11. Установите `openvk` в качестве корневого приложения в файле `chandler.yml`
|
||||||
|
|
||||||
После этого вы можете войти как системный администратор в саму сеть (регистрация не требуется):
|
После этого вы можете войти как системный администратор в саму сеть (регистрация не требуется):
|
||||||
|
|
||||||
* **Логин**: `admin@localhost.localdomain6`
|
* **Логин**: `admin@localhost.localdomain6`
|
||||||
* **Пароль**: `admin`
|
* **Пароль**: `admin`
|
||||||
* Перед использованием встроенной учетной записи рекомендуется сменить пароль.
|
* Перед использованием встроенной учетной записи рекомендуется сменить пароль или отключить её.
|
||||||
|
|
||||||
💡Запутались? Полное руководство по установке доступно [здесь](https://docs.openvk.su/openvk_engine/centos8_installation/) (CentOS 8 [и](https://almalinux.org/ru/) [семейство](https://yum.oracle.com/oracle-linux-isos.html)).
|
💡Запутались? Полное руководство по установке доступно [здесь](https://docs.openvk.su/openvk_engine/centos8_installation/) (CentOS 8 [и](https://almalinux.org/ru/) [семейство](https://yum.oracle.com/oracle-linux-isos.html)).
|
||||||
|
|
||||||
|
@ -74,7 +82,7 @@ ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions
|
||||||
|
|
||||||
* [Баг-трекер](https://github.com/openvk/openvk/projects/1)
|
* [Баг-трекер](https://github.com/openvk/openvk/projects/1)
|
||||||
* [Помощь в OVK](https://openvk.su/support?act=new)
|
* [Помощь в OVK](https://openvk.su/support?act=new)
|
||||||
* Telegram-чат: Перейдите на [наш канал](https://t.me/openvkch) и откройте обсуждение в меню нашего канала.
|
* Telegram-чат: Перейдите на [наш канал](https://t.me/openvk) и откройте обсуждение в меню нашего канала.
|
||||||
* [Reddit](https://www.reddit.com/r/openvk/)
|
* [Reddit](https://www.reddit.com/r/openvk/)
|
||||||
* [Обсуждения](https://github.com/openvk/openvk/discussions)
|
* [Обсуждения](https://github.com/openvk/openvk/discussions)
|
||||||
* Чат в Matrix: #ovk:matrix.org
|
* Чат в Matrix: #ovk:matrix.org
|
||||||
|
@ -82,5 +90,5 @@ ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions
|
||||||
**Внимание**: баг-трекер, форум, телеграм- и matrix-чат являются публичными местами, и жалобы в OVK обслуживается волонтерами. Если вам нужно сообщить о чем-то, что не должно быть раскрыто широкой публике (например, сообщение об уязвимости), пожалуйста, свяжитесь с нами напрямую по этому адресу: **openvk [собака] tutanota [точка] com**.
|
**Внимание**: баг-трекер, форум, телеграм- и matrix-чат являются публичными местами, и жалобы в OVK обслуживается волонтерами. Если вам нужно сообщить о чем-то, что не должно быть раскрыто широкой публике (например, сообщение об уязвимости), пожалуйста, свяжитесь с нами напрямую по этому адресу: **openvk [собака] tutanota [точка] com**.
|
||||||
|
|
||||||
<a href="https://codeberg.org/OpenVK/openvk">
|
<a href="https://codeberg.org/OpenVK/openvk">
|
||||||
<img alt="Получить на Codeberg" src="https://codeberg.org/Codeberg/GetItOnCodeberg/media/branch/main/get-it-on-blue-on-white.png" height="60">
|
<img alt="Get it on Codeberg" src="https://codeberg.org/Codeberg/GetItOnCodeberg/media/branch/main/get-it-on-blue-on-white.png" height="60">
|
||||||
</a>
|
</a>
|
||||||
|
|
87
ServiceAPI/Apps.php
Normal file
87
ServiceAPI/Apps.php
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\ServiceAPI;
|
||||||
|
|
||||||
|
use openvk\Web\Models\Entities\User;
|
||||||
|
use openvk\Web\Models\Repositories\Applications;
|
||||||
|
|
||||||
|
class Apps implements Handler
|
||||||
|
{
|
||||||
|
private $user;
|
||||||
|
private $apps;
|
||||||
|
|
||||||
|
public function __construct(?User $user)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
$this->apps = new Applications;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUserInfo(callable $resolve, callable $reject): void
|
||||||
|
{
|
||||||
|
$hexId = dechex($this->user->getId());
|
||||||
|
$sign = hash_hmac("sha512/224", $hexId, CHANDLER_ROOT_CONF["security"]["secret"], true);
|
||||||
|
$marketingId = $hexId . "_" . base64_encode($sign);
|
||||||
|
|
||||||
|
$resolve([
|
||||||
|
"id" => $this->user->getId(),
|
||||||
|
"marketing_id" => $marketingId,
|
||||||
|
"name" => [
|
||||||
|
"first" => $this->user->getFirstName(),
|
||||||
|
"last" => $this->user->getLastName(),
|
||||||
|
"full" => $this->user->getFullName(),
|
||||||
|
],
|
||||||
|
"ava" => $this->user->getAvatarUrl(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePermission(int $app, string $perm, string $state, callable $resolve, callable $reject): void
|
||||||
|
{
|
||||||
|
$app = $this->apps->get($app);
|
||||||
|
if(!$app || !$app->isEnabled()) {
|
||||||
|
$reject("No application with this id found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
$app = $this->apps->get($appId);
|
||||||
|
if(!$app || !$app->isEnabled()) {
|
||||||
|
$reject("No application with this id found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$coinsLeft = $this->user->getCoins() - $amount;
|
||||||
|
if($coinsLeft < 0) {
|
||||||
|
$reject(41, "Not enough money");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->user->setCoins($coinsLeft);
|
||||||
|
$this->user->save();
|
||||||
|
$app->addCoins($amount);
|
||||||
|
|
||||||
|
$t = time();
|
||||||
|
$resolve($t . "," . hash_hmac("whirlpool", "$appId:$amount:$t", CHANDLER_ROOT_CONF["security"]["secret"]));
|
||||||
|
}
|
||||||
|
|
||||||
|
function withdrawFunds(int $appId, callable $resolve, callable $reject): void
|
||||||
|
{
|
||||||
|
$app = $this->apps->get($appId);
|
||||||
|
if(!$app) {
|
||||||
|
$reject("No application with this id found");
|
||||||
|
return;
|
||||||
|
} else if($app->getOwner()->getId() != $this->user->getId()) {
|
||||||
|
$reject("You don't have rights to edit this app");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$coins = $app->getBalance();
|
||||||
|
$app->withdrawCoins();
|
||||||
|
$resolve($coins);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\ServiceAPI;
|
namespace openvk\ServiceAPI;
|
||||||
|
use openvk\Web\Models\Entities\Post;
|
||||||
use openvk\Web\Models\Entities\User;
|
use openvk\Web\Models\Entities\User;
|
||||||
use openvk\Web\Models\Repositories\Posts;
|
use openvk\Web\Models\Repositories\Posts;
|
||||||
|
|
||||||
|
@ -55,4 +56,19 @@ class Wall implements Handler
|
||||||
|
|
||||||
$resolve((array) $res);
|
$resolve((array) $res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function newStatus(string $text, callable $resolve, callable $reject): void
|
||||||
|
{
|
||||||
|
$post = new Post;
|
||||||
|
$post->setOwner($this->user->getId());
|
||||||
|
$post->setWall($this->user->getId());
|
||||||
|
$post->setCreated(time());
|
||||||
|
$post->setContent($text);
|
||||||
|
$post->setAnonymous(false);
|
||||||
|
$post->setFlags(0);
|
||||||
|
$post->setNsfw(false);
|
||||||
|
$post->save();
|
||||||
|
|
||||||
|
$resolve($post->getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,9 @@ final class Account extends VKAPIRequestHandler
|
||||||
"last_name" => $this->getUser()->getLastName(),
|
"last_name" => $this->getUser()->getLastName(),
|
||||||
"home_town" => $this->getUser()->getHometown(),
|
"home_town" => $this->getUser()->getHometown(),
|
||||||
"status" => $this->getUser()->getStatus(),
|
"status" => $this->getUser()->getStatus(),
|
||||||
"bdate" => "1.1.1970", // TODO
|
"bdate" => $this->getUser()->getBirthday()->format('%e.%m.%Y'),
|
||||||
"bdate_visibility" => 0, // TODO
|
"bdate_visibility" => $this->getUser()->getBirthdayPrivacy(),
|
||||||
"phone" => "+420 ** *** 228", // TODO
|
"phone" => "+420 ** *** 228", # TODO
|
||||||
"relation" => $this->getUser()->getMaritalStatus(),
|
"relation" => $this->getUser()->getMaritalStatus(),
|
||||||
"sex" => $this->getUser()->isFemale() ? 1 : 2
|
"sex" => $this->getUser()->isFemale() ? 1 : 2
|
||||||
];
|
];
|
||||||
|
@ -25,12 +25,10 @@ final class Account extends VKAPIRequestHandler
|
||||||
{
|
{
|
||||||
$this->requireUser();
|
$this->requireUser();
|
||||||
|
|
||||||
// Цiй метод є заглушка
|
|
||||||
|
|
||||||
return (object) [
|
return (object) [
|
||||||
"2fa_required" => 0,
|
"2fa_required" => $this->getUser()->is2faEnabled() ? 1 : 0,
|
||||||
"country" => "CZ", // TODO
|
"country" => "CZ", # TODO
|
||||||
"eu_user" => false, // TODO
|
"eu_user" => false, # TODO
|
||||||
"https_required" => 1,
|
"https_required" => 1,
|
||||||
"intro" => 0,
|
"intro" => 0,
|
||||||
"community_comments" => false,
|
"community_comments" => false,
|
||||||
|
@ -47,6 +45,7 @@ final class Account extends VKAPIRequestHandler
|
||||||
$this->requireUser();
|
$this->requireUser();
|
||||||
|
|
||||||
$this->getUser()->setOnline(time());
|
$this->getUser()->setOnline(time());
|
||||||
|
$this->getUser()->save();
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -55,7 +54,7 @@ final class Account extends VKAPIRequestHandler
|
||||||
{
|
{
|
||||||
$this->requireUser();
|
$this->requireUser();
|
||||||
|
|
||||||
// Цiй метод є заглушка
|
# Цiй метод є заглушка
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -73,6 +72,6 @@ final class Account extends VKAPIRequestHandler
|
||||||
"messages" => $this->getUser()->getUnreadMessagesCount()
|
"messages" => $this->getUser()->getUnreadMessagesCount()
|
||||||
];
|
];
|
||||||
|
|
||||||
// TODO: Filter
|
# TODO: Filter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -316,6 +316,20 @@ final class Audio extends VKAPIRequestHandler
|
||||||
"count" => sizeof($items),
|
"count" => sizeof($items),
|
||||||
"items" => $items,
|
"items" => $items,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
$serverUrl = ovk_scheme(true) . $_SERVER["SERVER_NAME"];
|
||||||
|
|
||||||
|
return (object) [
|
||||||
|
"count" => 1,
|
||||||
|
"items" => [(object) [
|
||||||
|
"id" => 1,
|
||||||
|
"owner_id" => 1,
|
||||||
|
"artist" => "В ОВК ПОКА НЕТ МУЗЫКИ",
|
||||||
|
"title" => "ЖДИТЕ :)))",
|
||||||
|
"duration" => 22,
|
||||||
|
"url" => $serverUrl . "/assets/packages/static/openvk/audio/nomusic.mp3"
|
||||||
|
]]
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLyrics(int $lyrics_id): object
|
function getLyrics(int $lyrics_id): object
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\VKAPI\Handlers;
|
namespace openvk\VKAPI\Handlers;
|
||||||
use openvk\Web\Models\Entities\User;
|
|
||||||
use openvk\Web\Models\Repositories\Users as UsersRepo;
|
use openvk\Web\Models\Repositories\Users as UsersRepo;
|
||||||
|
|
||||||
final class Friends extends VKAPIRequestHandler
|
final class Friends extends VKAPIRequestHandler
|
||||||
|
@ -24,9 +23,8 @@ final class Friends extends VKAPIRequestHandler
|
||||||
|
|
||||||
$usersApi = new Users($this->getUser());
|
$usersApi = new Users($this->getUser());
|
||||||
|
|
||||||
if (!is_null($fields)) {
|
if(!is_null($fields))
|
||||||
$response = $usersApi->get(implode(',', $friends), $fields, 0, $count); // FIXME
|
$response = $usersApi->get(implode(',', $friends), $fields, 0, $count); # FIXME
|
||||||
}
|
|
||||||
|
|
||||||
return (object) [
|
return (object) [
|
||||||
"count" => $users->get($user_id)->getFriendsCount(),
|
"count" => $users->get($user_id)->getFriendsCount(),
|
||||||
|
@ -70,7 +68,6 @@ final class Friends extends VKAPIRequestHandler
|
||||||
$this->requireUser();
|
$this->requireUser();
|
||||||
|
|
||||||
$users = new UsersRepo;
|
$users = new UsersRepo;
|
||||||
|
|
||||||
$user = $users->get(intval($user_id));
|
$user = $users->get(intval($user_id));
|
||||||
|
|
||||||
if(is_null($user)) {
|
if(is_null($user)) {
|
||||||
|
@ -83,20 +80,16 @@ final class Friends extends VKAPIRequestHandler
|
||||||
case 0:
|
case 0:
|
||||||
$user->toggleSubscription($this->getUser());
|
$user->toggleSubscription($this->getUser());
|
||||||
return 1;
|
return 1;
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
$user->toggleSubscription($this->getUser());
|
$user->toggleSubscription($this->getUser());
|
||||||
return 2;
|
return 2;
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
return 2;
|
return 2;
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 1;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,11 +105,9 @@ final class Friends extends VKAPIRequestHandler
|
||||||
case 3:
|
case 3:
|
||||||
$user->toggleSubscription($this->getUser());
|
$user->toggleSubscription($this->getUser());
|
||||||
return 1;
|
return 1;
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fail(15, "Access denied: No friend or friend request found.");
|
fail(15, "Access denied: No friend or friend request found.");
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,22 +124,6 @@ final class Friends extends VKAPIRequestHandler
|
||||||
for($i=0; $i < sizeof($friends); $i++) {
|
for($i=0; $i < sizeof($friends); $i++) {
|
||||||
$friend = $users->get(intval($friends[$i]));
|
$friend = $users->get(intval($friends[$i]));
|
||||||
|
|
||||||
$status = 0;
|
|
||||||
switch ($friend->getSubscriptionStatus($this->getUser())) {
|
|
||||||
case 3:
|
|
||||||
case 0:
|
|
||||||
$status = $friend->getSubscriptionStatus($this->getUser());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
$status = 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
$status = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$response[] = (object)[
|
$response[] = (object)[
|
||||||
"friend_status" => $friend->getSubscriptionStatus($this->getUser()),
|
"friend_status" => $friend->getSubscriptionStatus($this->getUser()),
|
||||||
"user_id" => $friend->getId()
|
"user_id" => $friend->getId()
|
||||||
|
@ -157,4 +132,32 @@ final class Friends extends VKAPIRequestHandler
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRequests(string $fields = "", int $offset = 0, int $count = 100): object
|
||||||
|
{
|
||||||
|
$this->requireUser();
|
||||||
|
|
||||||
|
$i = 0;
|
||||||
|
$offset++;
|
||||||
|
$followers = [];
|
||||||
|
|
||||||
|
foreach($this->getUser()->getFollowers() as $follower) {
|
||||||
|
$followers[$i] = $follower->getId();
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $followers;
|
||||||
|
$usersApi = new Users($this->getUser());
|
||||||
|
|
||||||
|
if(!is_null($fields))
|
||||||
|
$response = $usersApi->get(implode(',', $followers), $fields, 0, $count); # FIXME
|
||||||
|
|
||||||
|
foreach($response as $user)
|
||||||
|
$user->user_id = $user->id;
|
||||||
|
|
||||||
|
return (object) [
|
||||||
|
"count" => $this->getUser()->getFollowersCount(),
|
||||||
|
"items" => $response
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,12 +1,7 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\VKAPI\Handlers;
|
namespace openvk\VKAPI\Handlers;
|
||||||
use openvk\Web\Models\Entities\User;
|
|
||||||
use openvk\Web\Models\Entities\Clubs;
|
|
||||||
use openvk\Web\Models\Repositories\Clubs as ClubsRepo;
|
use openvk\Web\Models\Repositories\Clubs as ClubsRepo;
|
||||||
use openvk\Web\Models\Repositories\Users as UsersRepo;
|
use openvk\Web\Models\Repositories\Users as UsersRepo;
|
||||||
use openvk\Web\Models\Entities\Post;
|
|
||||||
use openvk\Web\Models\Entities\Postable;
|
|
||||||
use openvk\Web\Models\Repositories\Posts as PostsRepo;
|
|
||||||
|
|
||||||
final class Groups extends VKAPIRequestHandler
|
final class Groups extends VKAPIRequestHandler
|
||||||
{
|
{
|
||||||
|
@ -15,40 +10,40 @@ final class Groups extends VKAPIRequestHandler
|
||||||
$this->requireUser();
|
$this->requireUser();
|
||||||
|
|
||||||
if($user_id == 0) {
|
if($user_id == 0) {
|
||||||
foreach($this->getUser()->getClubs($offset+1) as $club) {
|
foreach($this->getUser()->getClubs($offset+1) as $club)
|
||||||
$clbs[] = $club;
|
$clbs[] = $club;
|
||||||
}
|
|
||||||
$clbsCount = $this->getUser()->getClubCount();
|
$clbsCount = $this->getUser()->getClubCount();
|
||||||
} else {
|
} else {
|
||||||
$users = new UsersRepo;
|
$users = new UsersRepo;
|
||||||
$user = $users->get($user_id);
|
$user = $users->get($user_id);
|
||||||
if (is_null($user)) {
|
|
||||||
|
if(is_null($user))
|
||||||
$this->fail(15, "Access denied");
|
$this->fail(15, "Access denied");
|
||||||
}
|
|
||||||
foreach($user->getClubs($offset+1) as $club) {
|
foreach($user->getClubs($offset+1) as $club)
|
||||||
$clbs[] = $club;
|
$clbs[] = $club;
|
||||||
}
|
|
||||||
$clbsCount = $user->getClubCount();
|
$clbsCount = $user->getClubCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
$rClubs;
|
$rClubs;
|
||||||
|
|
||||||
$ic = sizeof($clbs);
|
$ic = sizeof($clbs);
|
||||||
|
if(sizeof($clbs) > $count)
|
||||||
|
$ic = $count;
|
||||||
|
|
||||||
if(sizeof($clbs) > $count) $ic = $count;
|
if(!empty($clbs)) {
|
||||||
|
|
||||||
$clbs = array_slice($clbs, $offset * $count);
|
$clbs = array_slice($clbs, $offset * $count);
|
||||||
|
|
||||||
for($i=0; $i < $ic; $i++) {
|
for($i=0; $i < $ic; $i++) {
|
||||||
$usr = $clbs[$i];
|
$usr = $clbs[$i];
|
||||||
if(is_null($usr))
|
if(is_null($usr)) {
|
||||||
{
|
|
||||||
$rClubs[$i] = (object)[
|
$rClubs[$i] = (object)[
|
||||||
"id" => $clbs[$i],
|
"id" => $clbs[$i],
|
||||||
"name" => "DELETED",
|
"name" => "DELETED",
|
||||||
"deactivated" => "deleted"
|
"deactivated" => "deleted"
|
||||||
];
|
];
|
||||||
}else if($clbs[$i] == null){
|
} else if($clbs[$i] == NULL) {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$rClubs[$i] = (object) [
|
$rClubs[$i] = (object) [
|
||||||
|
@ -63,25 +58,43 @@ final class Groups extends VKAPIRequestHandler
|
||||||
|
|
||||||
foreach($flds as $field) {
|
foreach($flds as $field) {
|
||||||
switch($field) {
|
switch($field) {
|
||||||
case 'verified':
|
case "verified":
|
||||||
$rClubs[$i]->verified = intval($usr->isVerified());
|
$rClubs[$i]->verified = intval($usr->isVerified());
|
||||||
break;
|
break;
|
||||||
case 'has_photo':
|
case "has_photo":
|
||||||
$rClubs[$i]->has_photo = is_null($usr->getAvatarPhoto()) ? 0 : 1;
|
$rClubs[$i]->has_photo = is_null($usr->getAvatarPhoto()) ? 0 : 1;
|
||||||
break;
|
break;
|
||||||
case 'photo_max_orig':
|
case "photo_max_orig":
|
||||||
$rClubs[$i]->photo_max_orig = $usr->getAvatarURL();
|
$rClubs[$i]->photo_max_orig = $usr->getAvatarURL();
|
||||||
break;
|
break;
|
||||||
case 'photo_max':
|
case "photo_max":
|
||||||
$rClubs[$i]->photo_max = $usr->getAvatarURL();
|
$rClubs[$i]->photo_max = $usr->getAvatarURL("original"); // ORIGINAL ANDREI CHINITEL 🥵🥵🥵🥵
|
||||||
break;
|
break;
|
||||||
case 'members_count':
|
case "photo_50":
|
||||||
|
$rClubs[$i]->photo_50 = $usr->getAvatarURL();
|
||||||
|
break;
|
||||||
|
case "photo_100":
|
||||||
|
$rClubs[$i]->photo_100 = $usr->getAvatarURL("tiny");
|
||||||
|
break;
|
||||||
|
case "photo_200":
|
||||||
|
$rClubs[$i]->photo_200 = $usr->getAvatarURL("normal");
|
||||||
|
break;
|
||||||
|
case "photo_200_orig":
|
||||||
|
$rClubs[$i]->photo_200_orig = $usr->getAvatarURL("normal");
|
||||||
|
break;
|
||||||
|
case "photo_400_orig":
|
||||||
|
$rClubs[$i]->photo_400_orig = $usr->getAvatarURL("normal");
|
||||||
|
break;
|
||||||
|
case "members_count":
|
||||||
$rClubs[$i]->members_count = $usr->getFollowersCount();
|
$rClubs[$i]->members_count = $usr->getFollowersCount();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
$rClubs = [];
|
||||||
|
}
|
||||||
|
|
||||||
return (object) [
|
return (object) [
|
||||||
"count" => $clbsCount,
|
"count" => $clbsCount,
|
||||||
|
@ -91,14 +104,12 @@ final class Groups extends VKAPIRequestHandler
|
||||||
|
|
||||||
function getById(string $group_ids = "", string $group_id = "", string $fields = ""): ?array
|
function getById(string $group_ids = "", string $group_id = "", string $fields = ""): ?array
|
||||||
{
|
{
|
||||||
$this->requireUser();
|
|
||||||
|
|
||||||
$clubs = new ClubsRepo;
|
$clubs = new ClubsRepo;
|
||||||
|
|
||||||
if ($group_ids == null && $group_id != null)
|
if($group_ids == NULL && $group_id != NULL)
|
||||||
$group_ids = $group_id;
|
$group_ids = $group_id;
|
||||||
|
|
||||||
if ($group_ids == null && $group_id == null)
|
if($group_ids == NULL && $group_id == NULL)
|
||||||
$this->fail(100, "One of the parameters specified was missing or invalid: group_ids is undefined");
|
$this->fail(100, "One of the parameters specified was missing or invalid: group_ids is undefined");
|
||||||
|
|
||||||
$clbs = explode(',', $group_ids);
|
$clbs = explode(',', $group_ids);
|
||||||
|
@ -114,8 +125,7 @@ final class Groups extends VKAPIRequestHandler
|
||||||
$this->fail(100, "ты ошибся чутка, у айди группы убери минус");
|
$this->fail(100, "ты ошибся чутка, у айди группы убери минус");
|
||||||
|
|
||||||
$clb = $clubs->get((int) $clbs[$i]);
|
$clb = $clubs->get((int) $clbs[$i]);
|
||||||
if(is_null($clb))
|
if(is_null($clb)) {
|
||||||
{
|
|
||||||
$response[$i] = (object)[
|
$response[$i] = (object)[
|
||||||
"id" => intval($clbs[$i]),
|
"id" => intval($clbs[$i]),
|
||||||
"name" => "DELETED",
|
"name" => "DELETED",
|
||||||
|
@ -123,7 +133,7 @@ final class Groups extends VKAPIRequestHandler
|
||||||
"type" => "group",
|
"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){
|
} else if($clbs[$i] == NULL) {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$response[$i] = (object)[
|
$response[$i] = (object)[
|
||||||
|
@ -139,44 +149,65 @@ final class Groups extends VKAPIRequestHandler
|
||||||
|
|
||||||
foreach($flds as $field) {
|
foreach($flds as $field) {
|
||||||
switch($field) {
|
switch($field) {
|
||||||
case 'verified':
|
case "verified":
|
||||||
$response[$i]->verified = intval($clb->isVerified());
|
$response[$i]->verified = intval($clb->isVerified());
|
||||||
break;
|
break;
|
||||||
case 'has_photo':
|
case "has_photo":
|
||||||
$response[$i]->has_photo = is_null($clb->getAvatarPhoto()) ? 0 : 1;
|
$response[$i]->has_photo = is_null($clb->getAvatarPhoto()) ? 0 : 1;
|
||||||
break;
|
break;
|
||||||
case 'photo_max_orig':
|
case "photo_max_orig":
|
||||||
$response[$i]->photo_max_orig = $clb->getAvatarURL();
|
$response[$i]->photo_max_orig = $clb->getAvatarURL();
|
||||||
break;
|
break;
|
||||||
case 'photo_max':
|
case "photo_max":
|
||||||
$response[$i]->photo_max = $clb->getAvatarURL();
|
$response[$i]->photo_max = $clb->getAvatarURL();
|
||||||
break;
|
break;
|
||||||
case 'members_count':
|
case "photo_50":
|
||||||
|
$response[$i]->photo_50 = $clb->getAvatarURL();
|
||||||
|
break;
|
||||||
|
case "photo_100":
|
||||||
|
$response[$i]->photo_100 = $clb->getAvatarURL("tiny");
|
||||||
|
break;
|
||||||
|
case "photo_200":
|
||||||
|
$response[$i]->photo_200 = $clb->getAvatarURL("normal");
|
||||||
|
break;
|
||||||
|
case "photo_200_orig":
|
||||||
|
$response[$i]->photo_200_orig = $clb->getAvatarURL("normal");
|
||||||
|
break;
|
||||||
|
case "photo_400_orig":
|
||||||
|
$response[$i]->photo_400_orig = $clb->getAvatarURL("normal");
|
||||||
|
break;
|
||||||
|
case "members_count":
|
||||||
$response[$i]->members_count = $clb->getFollowersCount();
|
$response[$i]->members_count = $clb->getFollowersCount();
|
||||||
break;
|
break;
|
||||||
case 'site':
|
case "site":
|
||||||
$response[$i]->site = $clb->getWebsite();
|
$response[$i]->site = $clb->getWebsite();
|
||||||
break;
|
break;
|
||||||
case 'description':
|
case "description":
|
||||||
$response[$i]->desctiption = $clb->getDescription();
|
$response[$i]->desctiption = $clb->getDescription();
|
||||||
break;
|
break;
|
||||||
case 'contacts':
|
case "contacts":
|
||||||
$contacts;
|
$contacts;
|
||||||
$contactTmp = $clb->getManagers(1, true);
|
$contactTmp = $clb->getManagers(1, true);
|
||||||
foreach($contactTmp as $contact) {
|
|
||||||
|
foreach($contactTmp as $contact)
|
||||||
$contacts[] = array(
|
$contacts[] = array(
|
||||||
'user_id' => $contact->getUser()->getId(),
|
"user_id" => $contact->getUser()->getId(),
|
||||||
'desc' => $contact->getComment()
|
"desc" => $contact->getComment()
|
||||||
);
|
);
|
||||||
}
|
|
||||||
$response[$i]->contacts = $contacts;
|
$response[$i]->contacts = $contacts;
|
||||||
break;
|
break;
|
||||||
case 'can_post':
|
case "can_post":
|
||||||
|
if(!is_null($this->getUser()))
|
||||||
if($clb->canBeModifiedBy($this->getUser()))
|
if($clb->canBeModifiedBy($this->getUser()))
|
||||||
$response[$i]->can_post = true;
|
$response[$i]->can_post = true;
|
||||||
else
|
else
|
||||||
$response[$i]->can_post = $clb->canPost();
|
$response[$i]->can_post = $clb->canPost();
|
||||||
break;
|
break;
|
||||||
|
case "is_member":
|
||||||
|
if(!is_null($this->getUser()))
|
||||||
|
$response[$i]->is_member = (int) $clb->getSubscriptionStatus($this->getUser());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,38 +10,37 @@ final class Likes extends VKAPIRequestHandler
|
||||||
$this->requireUser();
|
$this->requireUser();
|
||||||
|
|
||||||
switch($type) {
|
switch($type) {
|
||||||
case 'post':
|
case "post":
|
||||||
$post = (new PostsRepo)->getPostById($owner_id, $item_id);
|
$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(is_null($post))
|
||||||
|
$this->fail(100, "One of the parameters specified was missing or invalid: object not found");
|
||||||
|
|
||||||
$post->setLike(true, $this->getUser());
|
$post->setLike(true, $this->getUser());
|
||||||
|
|
||||||
return (object) [
|
return (object) [
|
||||||
"likes" => $post->getLikesCount()
|
"likes" => $post->getLikesCount()
|
||||||
];
|
];
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
$this->fail(100, 'One of the parameters specified was missing or invalid: incorrect type');
|
$this->fail(100, "One of the parameters specified was missing or invalid: incorrect type");
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function remove(string $type, int $owner_id, int $item_id): object
|
function delete(string $type, int $owner_id, int $item_id): object
|
||||||
{
|
{
|
||||||
$this->requireUser();
|
$this->requireUser();
|
||||||
|
|
||||||
switch($type) {
|
switch($type) {
|
||||||
case 'post':
|
case "post":
|
||||||
$post = (new PostsRepo)->getPostById($owner_id, $item_id);
|
$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 (is_null($post))
|
||||||
|
$this->fail(100, "One of the parameters specified was missing or invalid: object not found");
|
||||||
|
|
||||||
$post->setLike(false, $this->getUser());
|
$post->setLike(false, $this->getUser());
|
||||||
return (object) [
|
return (object) [
|
||||||
"likes" => $post->getLikesCount()
|
"likes" => $post->getLikesCount()
|
||||||
];
|
];
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
$this->fail(100, 'One of the parameters specified was missing or invalid: incorrect type');
|
$this->fail(100, "One of the parameters specified was missing or invalid: incorrect type");
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,25 +49,25 @@ final class Likes extends VKAPIRequestHandler
|
||||||
$this->requireUser();
|
$this->requireUser();
|
||||||
|
|
||||||
switch($type) {
|
switch($type) {
|
||||||
case 'post':
|
case "post":
|
||||||
$user = (new UsersRepo)->get($user_id);
|
$user = (new UsersRepo)->get($user_id);
|
||||||
if (is_null($user)) return (object)[
|
if (is_null($user))
|
||||||
|
return (object) [
|
||||||
"liked" => 0,
|
"liked" => 0,
|
||||||
"copied" => 0,
|
"copied" => 0,
|
||||||
"sex" => 0
|
"sex" => 0
|
||||||
];
|
];
|
||||||
|
|
||||||
$post = (new PostsRepo)->getPostById($owner_id, $item_id);
|
$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 (is_null($post))
|
||||||
|
$this->fail(100, "One of the parameters specified was missing or invalid: object not found");
|
||||||
|
|
||||||
return (object) [
|
return (object) [
|
||||||
"liked" => (int) $post->hasLikeFrom($user),
|
"liked" => (int) $post->hasLikeFrom($user),
|
||||||
"copied" => 0 // TODO: handle this
|
"copied" => 0 # TODO: handle this
|
||||||
];
|
];
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
$this->fail(100, 'One of the parameters specified was missing or invalid: incorrect type');
|
$this->fail(100, "One of the parameters specified was missing or invalid: incorrect type");
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ final class Messages extends VKAPIRequestHandler
|
||||||
if(!$peer)
|
if(!$peer)
|
||||||
$this->fail(936, "There is no peer with this id");
|
$this->fail(936, "There is no peer with this id");
|
||||||
|
|
||||||
if($this->getUser()->getId() !== $peer->getId() && $peer->getSubscriptionStatus($this->getUser()) !== 3)
|
if($this->getUser()->getId() !== $peer->getId() && !$peer->getPrivacyPermission('messages.write', $this->getUser()))
|
||||||
$this->fail(945, "This chat is disabled because of privacy settings");
|
$this->fail(945, "This chat is disabled because of privacy settings");
|
||||||
|
|
||||||
# Finally we get to send a message!
|
# Finally we get to send a message!
|
||||||
|
@ -123,9 +123,8 @@ final class Messages extends VKAPIRequestHandler
|
||||||
$items = [];
|
$items = [];
|
||||||
foreach($ids as $id) {
|
foreach($ids as $id) {
|
||||||
$message = $msgs->get((int) $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;
|
$items[$id] = 0;
|
||||||
}
|
|
||||||
|
|
||||||
$message->delete();
|
$message->delete();
|
||||||
$items[$id] = 1;
|
$items[$id] = 1;
|
||||||
|
@ -153,6 +152,7 @@ final class Messages extends VKAPIRequestHandler
|
||||||
$this->requireUser();
|
$this->requireUser();
|
||||||
|
|
||||||
$convos = (new MSGRepo)->getCorrespondencies($this->getUser(), -1, $count, $offset);
|
$convos = (new MSGRepo)->getCorrespondencies($this->getUser(), -1, $count, $offset);
|
||||||
|
$convosCount = (new MSGRepo)->getCorrespondenciesCount($this->getUser());
|
||||||
$list = [];
|
$list = [];
|
||||||
|
|
||||||
$users = [];
|
$users = [];
|
||||||
|
@ -198,7 +198,6 @@ final class Messages extends VKAPIRequestHandler
|
||||||
$lastMessagePreview->emoji = true;
|
$lastMessagePreview->emoji = true;
|
||||||
|
|
||||||
if($extended == 1) {
|
if($extended == 1) {
|
||||||
$users[] = $lastMessage->getSender()->getId();
|
|
||||||
$users[] = $author;
|
$users[] = $author;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,21 +210,81 @@ final class Messages extends VKAPIRequestHandler
|
||||||
|
|
||||||
if($extended == 0){
|
if($extended == 0){
|
||||||
return (object) [
|
return (object) [
|
||||||
"count" => sizeof($list),
|
"count" => $convosCount,
|
||||||
"items" => $list,
|
"items" => $list,
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
|
$users[] = $this->getUser()->getId();
|
||||||
$users = array_unique($users);
|
$users = array_unique($users);
|
||||||
|
|
||||||
return (object) [
|
return (object) [
|
||||||
"count" => sizeof($list),
|
"count" => $convosCount,
|
||||||
"items" => $list,
|
"items" => $list,
|
||||||
"profiles" => (new APIUsers)->get(implode(',', $users), $fields, $offset, $count)
|
"profiles" => (!empty($users) ? (new APIUsers)->get(implode(',', $users), $fields, 0, $count+1) : [])
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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): object
|
function getConversationsById(string $peer_ids, int $extended = 0, string $fields = "")
|
||||||
|
{
|
||||||
|
$this->requireUser();
|
||||||
|
|
||||||
|
$peers = explode(',', $peer_ids);
|
||||||
|
|
||||||
|
$output = [
|
||||||
|
"count" => 0,
|
||||||
|
"items" => []
|
||||||
|
];
|
||||||
|
|
||||||
|
$userslist = [];
|
||||||
|
|
||||||
|
foreach($peers as $peer) {
|
||||||
|
if(key($peers) > 100)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(is_null($user_id = $this->resolvePeer((int) $peer)))
|
||||||
|
$this->fail(-151, "Chats are not implemented");
|
||||||
|
|
||||||
|
$user = (new USRRepo)->get((int) $peer);
|
||||||
|
|
||||||
|
$dialogue = new Correspondence($this->getUser(), $user);
|
||||||
|
$iterator = $dialogue->getMessages(Correspondence::CAP_BEHAVIOUR_START_MESSAGE_ID, 0, 1, 0, false);
|
||||||
|
$msg = $iterator[0]->unwrap(); // шоб удобнее было
|
||||||
|
$output['items'][] = [
|
||||||
|
"peer" => [
|
||||||
|
"id" => $user->getId(),
|
||||||
|
"type" => "user",
|
||||||
|
"local_id" => $user->getId()
|
||||||
|
],
|
||||||
|
"last_message_id" => $msg->id,
|
||||||
|
"in_read" => $msg->id,
|
||||||
|
"out_read" => $msg->id,
|
||||||
|
"sort_id" => [
|
||||||
|
"major_id" => 0,
|
||||||
|
"minor_id" => $msg->id, // КОНЕЧНО ЖЕ
|
||||||
|
],
|
||||||
|
"last_conversation_message_id" => $user->getId(),
|
||||||
|
"in_read_cmid" => $user->getId(),
|
||||||
|
"out_read_cmid" => $user->getId(),
|
||||||
|
"is_marked_unread" => $iterator[0]->isUnread(),
|
||||||
|
"important" => false, // целестора когда релиз
|
||||||
|
"can_write" => [
|
||||||
|
"allowed" => ($user->getId() === $this->getUser()->getId() || $user->getPrivacyPermission('messages.write', $this->getUser()) === true)
|
||||||
|
]
|
||||||
|
];
|
||||||
|
$userslist[] = $user->getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
if($extended == 1) {
|
||||||
|
$userslist = array_unique($userslist);
|
||||||
|
$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
|
||||||
{
|
{
|
||||||
$this->requireUser();
|
$this->requireUser();
|
||||||
|
|
||||||
|
@ -257,10 +316,18 @@ final class Messages extends VKAPIRequestHandler
|
||||||
$results[] = $rMsg;
|
$results[] = $rMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (object) [
|
$output = [
|
||||||
"count" => sizeof($results),
|
"count" => sizeof($results),
|
||||||
"items" => $results,
|
"items" => $results,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if ($extended == 1) {
|
||||||
|
$users[] = $this->getUser()->getId();
|
||||||
|
$users[] = $user_id;
|
||||||
|
$output["profiles"] = (!empty($users) ? (new APIUsers($this->getUser()))->get(implode(',', $users), $fields) : []);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (object) $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLongPollHistory(int $ts = -1, int $preview_length = 0, int $events_limit = 1000, int $msgs_limit = 1000): object
|
function getLongPollHistory(int $ts = -1, int $preview_length = 0, int $events_limit = 1000, int $msgs_limit = 1000): object
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\VKAPI\Handlers;
|
namespace openvk\VKAPI\Handlers;
|
||||||
use openvk\Web\Models\Entities\User;
|
|
||||||
use openvk\Web\Models\Entities\Post;
|
|
||||||
use openvk\Web\Models\Entities\Postable;
|
|
||||||
use Chandler\Database\DatabaseConnection;
|
use Chandler\Database\DatabaseConnection;
|
||||||
use openvk\Web\Models\Repositories\Posts as PostsRepo;
|
use openvk\Web\Models\Repositories\Posts as PostsRepo;
|
||||||
use openvk\VKAPI\Handlers\Wall;
|
use openvk\VKAPI\Handlers\Wall;
|
||||||
|
@ -13,8 +10,6 @@ final class Newsfeed extends VKAPIRequestHandler
|
||||||
{
|
{
|
||||||
$this->requireUser();
|
$this->requireUser();
|
||||||
|
|
||||||
if($offset != 0) $start_from = $offset;
|
|
||||||
|
|
||||||
$id = $this->getUser()->getId();
|
$id = $this->getUser()->getId();
|
||||||
$subs = DatabaseConnection::i()
|
$subs = DatabaseConnection::i()
|
||||||
->getContext()
|
->getContext()
|
||||||
|
@ -31,12 +26,15 @@ final class Newsfeed extends VKAPIRequestHandler
|
||||||
->select("id")
|
->select("id")
|
||||||
->where("wall IN (?)", $ids)
|
->where("wall IN (?)", $ids)
|
||||||
->where("deleted", 0)
|
->where("deleted", 0)
|
||||||
|
->where("id < (?)", empty($start_from) ? time()+1 : $start_from)
|
||||||
->order("created DESC");
|
->order("created DESC");
|
||||||
|
|
||||||
$rposts = [];
|
$rposts = [];
|
||||||
foreach($posts->page((int) ($offset + 1), $count) as $post)
|
foreach($posts->page((int) ($offset + 1), $count) as $post)
|
||||||
$rposts[] = (new PostsRepo)->get($post->id)->getPrettyId();
|
$rposts[] = (new PostsRepo)->get($post->id)->getPrettyId();
|
||||||
|
|
||||||
return (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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\VKAPI\Handlers;
|
namespace openvk\VKAPI\Handlers;
|
||||||
|
use openvk\Web\Models\Repositories\{Users as UsersRepo, Clubs as ClubsRepo, Posts as PostsRepo};
|
||||||
|
|
||||||
final class Ovk extends VKAPIRequestHandler
|
final class Ovk extends VKAPIRequestHandler
|
||||||
{
|
{
|
||||||
|
@ -21,4 +22,54 @@ final class Ovk extends VKAPIRequestHandler
|
||||||
{
|
{
|
||||||
return "крылышки";
|
return "крылышки";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
$response->statistics = (object) [
|
||||||
|
"users_count" => $usersStats->all,
|
||||||
|
"online_users_count" => $usersStats->online,
|
||||||
|
"active_users_count" => $usersStats->active,
|
||||||
|
"groups_count" => $clubsCount,
|
||||||
|
"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) {
|
||||||
|
return $admin->getId();
|
||||||
|
}, $admins)), $admin_fields, 0, sizeof($admins));
|
||||||
|
$response->administrators = (object) [
|
||||||
|
"count" => sizeof($admins),
|
||||||
|
"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) {
|
||||||
|
return $entry->club->getId();
|
||||||
|
}, $popularClubs)), "", "members_count, " . $group_fields);
|
||||||
|
|
||||||
|
$response->popular_groups = (object) [
|
||||||
|
"count" => sizeof($popularClubs),
|
||||||
|
"items" => $clubsResponse
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
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']
|
||||||
|
];
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
42
VKAPI/Handlers/Pay.php
Normal file
42
VKAPI/Handlers/Pay.php
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<?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
|
||||||
|
{
|
||||||
|
[$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)
|
||||||
|
$this->fail(4, "Invalid marketing id");
|
||||||
|
} catch (\SodiumException $e) {
|
||||||
|
$this->fail(4, "Invalid marketing id");
|
||||||
|
}
|
||||||
|
|
||||||
|
return hexdec($hexId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function verifyOrder(int $app_id, float $amount, string $signature): bool
|
||||||
|
{
|
||||||
|
$this->requireUser();
|
||||||
|
|
||||||
|
$app = (new Applications())->get($app_id);
|
||||||
|
if(!$app)
|
||||||
|
$this->fail(26, "No app found with this id");
|
||||||
|
else if($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)
|
||||||
|
$this->fail(4, "Invalid order");
|
||||||
|
} catch (\SodiumException $e) {
|
||||||
|
$this->fail(4, "Invalid order");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,34 +7,33 @@ final class Users extends VKAPIRequestHandler
|
||||||
{
|
{
|
||||||
function get(string $user_ids = "0", string $fields = "", int $offset = 0, int $count = 100, User $authuser = null /* костыль(( */): array
|
function get(string $user_ids = "0", string $fields = "", int $offset = 0, int $count = 100, User $authuser = null /* костыль(( */): array
|
||||||
{
|
{
|
||||||
// $this->requireUser();
|
if($authuser == NULL) $authuser = $this->getUser();
|
||||||
|
|
||||||
if($authuser == null) $authuser = $this->getUser();
|
|
||||||
|
|
||||||
$users = new UsersRepo;
|
$users = new UsersRepo;
|
||||||
if($user_ids == "0")
|
if($user_ids == "0")
|
||||||
$user_ids = (string) $authuser->getId();
|
$user_ids = (string) $authuser->getId();
|
||||||
|
|
||||||
$usrs = explode(',', $user_ids);
|
$usrs = explode(',', $user_ids);
|
||||||
$response;
|
$response = array();
|
||||||
|
|
||||||
$ic = sizeof($usrs);
|
$ic = sizeof($usrs);
|
||||||
|
|
||||||
if(sizeof($usrs) > $count) $ic = $count;
|
if(sizeof($usrs) > $count)
|
||||||
|
$ic = $count;
|
||||||
|
|
||||||
$usrs = array_slice($usrs, $offset * $count);
|
$usrs = array_slice($usrs, $offset * $count);
|
||||||
|
|
||||||
for($i=0; $i < $ic; $i++) {
|
for($i=0; $i < $ic; $i++) {
|
||||||
|
if($usrs[$i] != 0) {
|
||||||
$usr = $users->get((int) $usrs[$i]);
|
$usr = $users->get((int) $usrs[$i]);
|
||||||
if(is_null($usr))
|
if(is_null($usr) || $usr->isDeleted()) {
|
||||||
{
|
|
||||||
$response[$i] = (object)[
|
$response[$i] = (object)[
|
||||||
"id" => $usrs[$i],
|
"id" => (int) $usrs[$i],
|
||||||
"first_name" => "DELETED",
|
"first_name" => "DELETED",
|
||||||
"last_name" => "",
|
"last_name" => "",
|
||||||
"deactivated" => "deleted"
|
"deactivated" => "deleted"
|
||||||
];
|
];
|
||||||
}else if($usrs[$i] == null){
|
} else if($usrs[$i] == NULL) {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$response[$i] = (object)[
|
$response[$i] = (object)[
|
||||||
|
@ -49,32 +48,54 @@ final class Users extends VKAPIRequestHandler
|
||||||
|
|
||||||
foreach($flds as $field) {
|
foreach($flds as $field) {
|
||||||
switch($field) {
|
switch($field) {
|
||||||
case 'verified':
|
case "verified":
|
||||||
$response[$i]->verified = intval($usr->isVerified());
|
$response[$i]->verified = intval($usr->isVerified());
|
||||||
break;
|
break;
|
||||||
case 'sex':
|
case "sex":
|
||||||
$response[$i]->sex = $usr->isFemale() ? 1 : 2;
|
$response[$i]->sex = $usr->isFemale() ? 1 : 2;
|
||||||
break;
|
break;
|
||||||
case 'has_photo':
|
case "has_photo":
|
||||||
$response[$i]->has_photo = is_null($usr->getAvatarPhoto()) ? 0 : 1;
|
$response[$i]->has_photo = is_null($usr->getAvatarPhoto()) ? 0 : 1;
|
||||||
break;
|
break;
|
||||||
case 'photo_max_orig':
|
case "photo_max_orig":
|
||||||
$response[$i]->photo_max_orig = $usr->getAvatarURL();
|
$response[$i]->photo_max_orig = $usr->getAvatarURL();
|
||||||
break;
|
break;
|
||||||
case 'photo_max':
|
case "photo_max":
|
||||||
$response[$i]->photo_max = $usr->getAvatarURL();
|
$response[$i]->photo_max = $usr->getAvatarURL("original");
|
||||||
break;
|
break;
|
||||||
case 'status':
|
case "photo_50":
|
||||||
if($usr->getStatus() != null)
|
$response[$i]->photo_50 = $usr->getAvatarURL();
|
||||||
|
break;
|
||||||
|
case "photo_100":
|
||||||
|
$response[$i]->photo_100 = $usr->getAvatarURL("tiny");
|
||||||
|
break;
|
||||||
|
case "photo_200":
|
||||||
|
$response[$i]->photo_200 = $usr->getAvatarURL("normal");
|
||||||
|
break;
|
||||||
|
case "photo_200_orig": # вообще не ебу к чему эта строка ну пусть будет кек
|
||||||
|
$response[$i]->photo_200_orig = $usr->getAvatarURL("normal");
|
||||||
|
break;
|
||||||
|
case "photo_400_orig":
|
||||||
|
$response[$i]->photo_400_orig = $usr->getAvatarURL("normal");
|
||||||
|
break;
|
||||||
|
|
||||||
|
# Она хочет быть выебанной видя матан
|
||||||
|
# Покайфу когда ты Виет а вокруг лишь дискриминант
|
||||||
|
|
||||||
|
# ору а когда я это успел написать
|
||||||
|
# вова кстати не матерись в коде мамка же спалит азщазаззазщазазаззазазазх
|
||||||
|
case "status":
|
||||||
|
if($usr->getStatus() != NULL)
|
||||||
$response[$i]->status = $usr->getStatus();
|
$response[$i]->status = $usr->getStatus();
|
||||||
break;
|
break;
|
||||||
case 'screen_name':
|
case "screen_name":
|
||||||
if($usr->getShortCode() != null)
|
if($usr->getShortCode() != NULL)
|
||||||
$response[$i]->screen_name = $usr->getShortCode();
|
$response[$i]->screen_name = $usr->getShortCode();
|
||||||
break;
|
break;
|
||||||
case 'friend_status':
|
case "friend_status":
|
||||||
switch($usr->getSubscriptionStatus($authuser)) {
|
switch($usr->getSubscriptionStatus($authuser)) {
|
||||||
case 3:
|
case 3:
|
||||||
|
# NOTICE falling through
|
||||||
case 0:
|
case 0:
|
||||||
$response[$i]->friend_status = $usr->getSubscriptionStatus($authuser);
|
$response[$i]->friend_status = $usr->getSubscriptionStatus($authuser);
|
||||||
break;
|
break;
|
||||||
|
@ -86,50 +107,44 @@ final class Users extends VKAPIRequestHandler
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'last_seen':
|
case "last_seen":
|
||||||
if ($usr->onlineStatus() == 0) {
|
if ($usr->onlineStatus() == 0)
|
||||||
$response[$i]->last_seen = (object) [
|
$response[$i]->last_seen = (object) [
|
||||||
"platform" => 1,
|
"platform" => 1,
|
||||||
"time" => $usr->getOnline()->timestamp()
|
"time" => $usr->getOnline()->timestamp()
|
||||||
];
|
];
|
||||||
}
|
case "music":
|
||||||
case 'music':
|
|
||||||
$response[$i]->music = $usr->getFavoriteMusic();
|
$response[$i]->music = $usr->getFavoriteMusic();
|
||||||
break;
|
break;
|
||||||
case 'movies':
|
case "movies":
|
||||||
$response[$i]->movies = $usr->getFavoriteFilms();
|
$response[$i]->movies = $usr->getFavoriteFilms();
|
||||||
break;
|
break;
|
||||||
case 'tv':
|
case "tv":
|
||||||
$response[$i]->tv = $usr->getFavoriteShows();
|
$response[$i]->tv = $usr->getFavoriteShows();
|
||||||
break;
|
break;
|
||||||
case 'books':
|
case "books":
|
||||||
$response[$i]->books = $usr->getFavoriteBooks();
|
$response[$i]->books = $usr->getFavoriteBooks();
|
||||||
break;
|
break;
|
||||||
case 'city':
|
case "city":
|
||||||
$response[$i]->city = $usr->getCity();
|
$response[$i]->city = $usr->getCity();
|
||||||
break;
|
break;
|
||||||
case 'interests':
|
case "interests":
|
||||||
$response[$i]->interests = $usr->getInterests();
|
$response[$i]->interests = $usr->getInterests();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($usr->getOnline()->timestamp() + 300 > time()) {
|
if($usr->getOnline()->timestamp() + 300 > time())
|
||||||
$response[$i]->online = 1;
|
$response[$i]->online = 1;
|
||||||
}else{
|
else
|
||||||
$response[$i]->online = 0;
|
$response[$i]->online = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* private function getUsersById(string $user_ids, string $fields = "", int $offset = 0, int $count = PHP_INT_MAX){
|
|
||||||
|
|
||||||
} */
|
|
||||||
|
|
||||||
function getFollowers(int $user_id, string $fields = "", int $offset = 0, int $count = 100): object
|
function getFollowers(int $user_id, string $fields = "", int $offset = 0, int $count = 100): object
|
||||||
{
|
{
|
||||||
$offset++;
|
$offset++;
|
||||||
|
@ -139,15 +154,13 @@ final class Users extends VKAPIRequestHandler
|
||||||
|
|
||||||
$this->requireUser();
|
$this->requireUser();
|
||||||
|
|
||||||
foreach ($users->get($user_id)->getFollowers($offset, $count) as $follower) {
|
foreach($users->get($user_id)->getFollowers($offset, $count) as $follower)
|
||||||
$followers[] = $follower->getId();
|
$followers[] = $follower->getId();
|
||||||
}
|
|
||||||
|
|
||||||
$response = $followers;
|
$response = $followers;
|
||||||
|
|
||||||
if (!is_null($fields)) {
|
if(!is_null($fields))
|
||||||
$response = $this->get(implode(',', $followers), $fields, 0, $count);
|
$response = $this->get(implode(',', $followers), $fields, 0, $count);
|
||||||
}
|
|
||||||
|
|
||||||
return (object) [
|
return (object) [
|
||||||
"count" => $users->get($user_id)->getFollowersCount(),
|
"count" => $users->get($user_id)->getFollowersCount(),
|
||||||
|
@ -155,16 +168,15 @@ final class Users extends VKAPIRequestHandler
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function search(string $q, string $fields = '', int $offset = 0, int $count = 100)
|
function search(string $q, string $fields = "", int $offset = 0, int $count = 100)
|
||||||
{
|
{
|
||||||
$users = new UsersRepo;
|
$users = new UsersRepo;
|
||||||
|
|
||||||
$array = [];
|
$array = [];
|
||||||
$find = $users->find($q);
|
$find = $users->find($q);
|
||||||
|
|
||||||
foreach ($find as $user) {
|
foreach ($find as $user)
|
||||||
$array[] = $user->getId();
|
$array[] = $user->getId();
|
||||||
}
|
|
||||||
|
|
||||||
return (object) [
|
return (object) [
|
||||||
"count" => $find->size(),
|
"count" => $find->size(),
|
||||||
|
|
|
@ -1,49 +1,66 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\VKAPI\Handlers;
|
namespace openvk\VKAPI\Handlers;
|
||||||
use openvk\Web\Models\Entities\User;
|
use openvk\Web\Models\Entities\User;
|
||||||
use openvk\Web\Models\Entities\Notifications\{WallPostNotification};
|
use openvk\Web\Models\Entities\Notifications\{WallPostNotification, RepostNotification, CommentNotification};
|
||||||
use openvk\Web\Models\Repositories\Users as UsersRepo;
|
use openvk\Web\Models\Repositories\Users as UsersRepo;
|
||||||
use openvk\Web\Models\Entities\Club;
|
use openvk\Web\Models\Entities\Club;
|
||||||
use openvk\Web\Models\Repositories\Clubs as ClubsRepo;
|
use openvk\Web\Models\Repositories\Clubs as ClubsRepo;
|
||||||
use openvk\Web\Models\Entities\Post;
|
use openvk\Web\Models\Entities\Post;
|
||||||
use openvk\Web\Models\Entities\Postable;
|
|
||||||
use openvk\Web\Models\Repositories\Posts as PostsRepo;
|
use openvk\Web\Models\Repositories\Posts as PostsRepo;
|
||||||
|
use openvk\Web\Models\Entities\Comment;
|
||||||
|
use openvk\Web\Models\Repositories\Comments as CommentsRepo;
|
||||||
|
|
||||||
final class Wall extends VKAPIRequestHandler
|
final class Wall extends VKAPIRequestHandler
|
||||||
{
|
{
|
||||||
function get(string $owner_id, string $domain = "", int $offset = 0, int $count = 30, int $extended = 0): object
|
function get(int $owner_id, string $domain = "", int $offset = 0, int $count = 30, int $extended = 0): object
|
||||||
{
|
{
|
||||||
$posts = new PostsRepo;
|
$posts = new PostsRepo;
|
||||||
|
|
||||||
$items = [];
|
$items = [];
|
||||||
$profiles = [];
|
$profiles = [];
|
||||||
$groups = [];
|
$groups = [];
|
||||||
$count = $posts->getPostCountOnUserWall((int) $owner_id);
|
$cnt = $posts->getPostCountOnUserWall($owner_id);
|
||||||
|
|
||||||
foreach ($posts->getPostsFromUsersWall((int)$owner_id, 1, $count, $offset) as $post) {
|
$wallOnwer = (new UsersRepo)->get($owner_id);
|
||||||
|
|
||||||
|
if(!$wallOnwer || $wallOnwer->isDeleted() || $wallOnwer->isDeleted())
|
||||||
|
$this->fail(18, "User was deleted or banned");
|
||||||
|
|
||||||
|
foreach($posts->getPostsFromUsersWall($owner_id, 1, $count, $offset) as $post) {
|
||||||
$from_id = get_class($post->getOwner()) == "openvk\Web\Models\Entities\Club" ? $post->getOwner()->getId() * (-1) : $post->getOwner()->getId();
|
$from_id = get_class($post->getOwner()) == "openvk\Web\Models\Entities\Club" ? $post->getOwner()->getId() * (-1) : $post->getOwner()->getId();
|
||||||
|
|
||||||
$attachments;
|
$attachments = [];
|
||||||
foreach($post->getChildren() as $attachment)
|
$repost = [];
|
||||||
{
|
foreach($post->getChildren() as $attachment) {
|
||||||
if($attachment instanceof \openvk\Web\Models\Entities\Photo)
|
if($attachment instanceof \openvk\Web\Models\Entities\Photo) {
|
||||||
{
|
if($attachment->isDeleted())
|
||||||
$attachments[] = [
|
continue;
|
||||||
"type" => "photo",
|
|
||||||
"photo" => [
|
$attachments[] = $this->getApiPhoto($attachment);
|
||||||
"album_id" => $attachment->getAlbum() ? $attachment->getAlbum()->getId() : null,
|
} else if ($attachment instanceof \openvk\Web\Models\Entities\Post) {
|
||||||
"date" => $attachment->getPublicationTime()->timestamp(),
|
$repostAttachments = [];
|
||||||
|
|
||||||
|
foreach($attachment->getChildren() as $repostAttachment) {
|
||||||
|
if($repostAttachment instanceof \openvk\Web\Models\Entities\Photo) {
|
||||||
|
if($attachment->isDeleted())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$repostAttachments[] = $this->getApiPhoto($repostAttachment);
|
||||||
|
/* Рекурсии, сука! Заказывали? */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$repost[] = [
|
||||||
"id" => $attachment->getVirtualId(),
|
"id" => $attachment->getVirtualId(),
|
||||||
"owner_id" => $attachment->getOwner()->getId(),
|
"owner_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(),
|
||||||
"sizes" => array([
|
"from_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(),
|
||||||
"height" => 500, // Для временного компросима оставляю статическое число. Если каждый раз обращаться к файлу за количеством пикселов, то наступает пuпuська полная с производительностью, так что пока так
|
"date" => $attachment->getPublicationTime()->timestamp(),
|
||||||
"url" => $attachment->getURL(),
|
"post_type" => "post",
|
||||||
"type" => "m",
|
"text" => $attachment->getText(false),
|
||||||
"width" => 500,
|
"attachments" => $repostAttachments,
|
||||||
]),
|
"post_source" => [
|
||||||
"text" => "",
|
"type" => "vk"
|
||||||
"has_tags" => false
|
],
|
||||||
]
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,11 +71,12 @@ final class Wall extends VKAPIRequestHandler
|
||||||
"owner_id" => $post->getTargetWall(),
|
"owner_id" => $post->getTargetWall(),
|
||||||
"date" => $post->getPublicationTime()->timestamp(),
|
"date" => $post->getPublicationTime()->timestamp(),
|
||||||
"post_type" => "post",
|
"post_type" => "post",
|
||||||
"text" => $post->getText(),
|
"text" => $post->getText(false),
|
||||||
"can_edit" => 0, // TODO
|
"copy_history" => $repost,
|
||||||
|
"can_edit" => 0, # TODO
|
||||||
"can_delete" => $post->canBeDeletedBy($this->getUser()),
|
"can_delete" => $post->canBeDeletedBy($this->getUser()),
|
||||||
"can_pin" => $post->canBePinnedBy($this->getUser()),
|
"can_pin" => $post->canBePinnedBy($this->getUser()),
|
||||||
"can_archive" => false, // TODO MAYBE
|
"can_archive" => false, # TODO MAYBE
|
||||||
"is_archived" => false,
|
"is_archived" => false,
|
||||||
"is_pinned" => $post->isPinned(),
|
"is_pinned" => $post->isPinned(),
|
||||||
"attachments" => $attachments,
|
"attachments" => $attachments,
|
||||||
|
@ -84,11 +102,10 @@ final class Wall extends VKAPIRequestHandler
|
||||||
else
|
else
|
||||||
$groups[] = $from_id * -1;
|
$groups[] = $from_id * -1;
|
||||||
|
|
||||||
$attachments = null; // free attachments so it will not clone everythingg
|
$attachments = NULL; # free attachments so it will not clone everythingg
|
||||||
}
|
}
|
||||||
|
|
||||||
if($extended == 1)
|
if($extended == 1) {
|
||||||
{
|
|
||||||
$profiles = array_unique($profiles);
|
$profiles = array_unique($profiles);
|
||||||
$groups = array_unique($groups);
|
$groups = array_unique($groups);
|
||||||
|
|
||||||
|
@ -126,57 +143,65 @@ final class Wall extends VKAPIRequestHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
return (object) [
|
return (object) [
|
||||||
"count" => $count,
|
"count" => $cnt,
|
||||||
"items" => (array)$items,
|
"items" => $items,
|
||||||
"profiles" => (array)$profilesFormatted,
|
"profiles" => $profilesFormatted,
|
||||||
"groups" => (array)$groupsFormatted
|
"groups" => $groupsFormatted
|
||||||
];
|
];
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
return (object) [
|
return (object) [
|
||||||
"count" => $count,
|
"count" => $cnt,
|
||||||
"items" => (array)$items
|
"items" => $items
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getById(string $posts, int $extended = 0, string $fields = "", User $user = null)
|
function getById(string $posts, int $extended = 0, string $fields = "", User $user = NULL)
|
||||||
{
|
{
|
||||||
if($user == null) $user = $this->getUser(); // костыли костыли крылышки
|
if($user == NULL) {
|
||||||
|
$this->requireUser();
|
||||||
|
$user = $this->getUser(); # костыли костыли крылышки
|
||||||
|
}
|
||||||
|
|
||||||
$items = [];
|
$items = [];
|
||||||
$profiles = [];
|
$profiles = [];
|
||||||
$groups = [];
|
$groups = [];
|
||||||
# $count = $posts->getPostCountOnUserWall((int) $owner_id);
|
|
||||||
|
|
||||||
$psts = explode(",", $posts);
|
$psts = explode(',', $posts);
|
||||||
|
|
||||||
foreach($psts as $pst)
|
foreach($psts as $pst) {
|
||||||
{
|
|
||||||
$id = explode("_", $pst);
|
$id = explode("_", $pst);
|
||||||
$post = (new PostsRepo)->getPostById(intval($id[0]), intval($id[1]));
|
$post = (new PostsRepo)->getPostById(intval($id[0]), intval($id[1]));
|
||||||
if($post) {
|
if($post) {
|
||||||
$from_id = get_class($post->getOwner()) == "openvk\Web\Models\Entities\Club" ? $post->getOwner()->getId() * (-1) : $post->getOwner()->getId();
|
$from_id = get_class($post->getOwner()) == "openvk\Web\Models\Entities\Club" ? $post->getOwner()->getId() * (-1) : $post->getOwner()->getId();
|
||||||
$attachments;
|
$attachments = [];
|
||||||
foreach($post->getChildren() as $attachment)
|
$repost = []; // чел высрал семь сигарет 😳 помянем 🕯
|
||||||
{
|
foreach($post->getChildren() as $attachment) {
|
||||||
if($attachment instanceof \openvk\Web\Models\Entities\Photo)
|
if($attachment instanceof \openvk\Web\Models\Entities\Photo) {
|
||||||
{
|
$attachments[] = $this->getApiPhoto($attachment);
|
||||||
$attachments[] = [
|
} else if ($attachment instanceof \openvk\Web\Models\Entities\Post) {
|
||||||
"type" => "photo",
|
$repostAttachments = [];
|
||||||
"photo" => [
|
|
||||||
"album_id" => $attachment->getAlbum() ? $attachment->getAlbum()->getId() : null,
|
foreach($attachment->getChildren() as $repostAttachment) {
|
||||||
"date" => $attachment->getPublicationTime()->timestamp(),
|
if($repostAttachment instanceof \openvk\Web\Models\Entities\Photo) {
|
||||||
|
if($attachment->isDeleted())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$repostAttachments[] = $this->getApiPhoto($repostAttachment);
|
||||||
|
/* Рекурсии, сука! Заказывали? */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$repost[] = [
|
||||||
"id" => $attachment->getVirtualId(),
|
"id" => $attachment->getVirtualId(),
|
||||||
"owner_id" => $attachment->getOwner()->getId(),
|
"owner_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(),
|
||||||
"sizes" => array([
|
"from_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(),
|
||||||
"height" => 500, // я ещё я заебался вставлять одинаковый код в два разных места
|
"date" => $attachment->getPublicationTime()->timestamp(),
|
||||||
"url" => $attachment->getURL(),
|
"post_type" => "post",
|
||||||
"type" => "m",
|
"text" => $attachment->getText(false),
|
||||||
"width" => 500,
|
"attachments" => $repostAttachments,
|
||||||
]),
|
"post_source" => [
|
||||||
"text" => "",
|
"type" => "vk"
|
||||||
"has_tags" => false
|
],
|
||||||
]
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,11 +212,12 @@ final class Wall extends VKAPIRequestHandler
|
||||||
"owner_id" => $post->getTargetWall(),
|
"owner_id" => $post->getTargetWall(),
|
||||||
"date" => $post->getPublicationTime()->timestamp(),
|
"date" => $post->getPublicationTime()->timestamp(),
|
||||||
"post_type" => "post",
|
"post_type" => "post",
|
||||||
"text" => $post->getText(),
|
"text" => $post->getText(false),
|
||||||
"can_edit" => 0, // TODO
|
"copy_history" => $repost,
|
||||||
|
"can_edit" => 0, # TODO
|
||||||
"can_delete" => $post->canBeDeletedBy($user),
|
"can_delete" => $post->canBeDeletedBy($user),
|
||||||
"can_pin" => $post->canBePinnedBy($user),
|
"can_pin" => $post->canBePinnedBy($user),
|
||||||
"can_archive" => false, // TODO MAYBE
|
"can_archive" => false, # TODO MAYBE
|
||||||
"is_archived" => false,
|
"is_archived" => false,
|
||||||
"is_pinned" => $post->isPinned(),
|
"is_pinned" => $post->isPinned(),
|
||||||
"post_source" => (object)["type" => "vk"],
|
"post_source" => (object)["type" => "vk"],
|
||||||
|
@ -217,12 +243,12 @@ final class Wall extends VKAPIRequestHandler
|
||||||
else
|
else
|
||||||
$groups[] = $from_id * -1;
|
$groups[] = $from_id * -1;
|
||||||
|
|
||||||
$attachments = null; // free attachments so it will not clone everythingg
|
$attachments = NULL; # free attachments so it will not clone everything
|
||||||
|
$repost = NULL; # same
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($extended == 1)
|
if($extended == 1) {
|
||||||
{
|
|
||||||
$profiles = array_unique($profiles);
|
$profiles = array_unique($profiles);
|
||||||
$groups = array_unique($groups);
|
$groups = array_unique($groups);
|
||||||
|
|
||||||
|
@ -264,8 +290,7 @@ final class Wall extends VKAPIRequestHandler
|
||||||
"profiles" => (array)$profilesFormatted,
|
"profiles" => (array)$profilesFormatted,
|
||||||
"groups" => (array)$groupsFormatted
|
"groups" => (array)$groupsFormatted
|
||||||
];
|
];
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
return (object) [
|
return (object) [
|
||||||
"items" => (array)$items
|
"items" => (array)$items
|
||||||
];
|
];
|
||||||
|
@ -308,12 +333,12 @@ final class Wall extends VKAPIRequestHandler
|
||||||
if($signed == 1)
|
if($signed == 1)
|
||||||
$flags |= 0b01000000;
|
$flags |= 0b01000000;
|
||||||
|
|
||||||
// TODO: Compatible implementation of this
|
# TODO: Compatible implementation of this
|
||||||
try {
|
try {
|
||||||
$photo = null;
|
$photo = NULL;
|
||||||
$video = null;
|
$video = NULL;
|
||||||
if($_FILES["photo"]["error"] === UPLOAD_ERR_OK) {
|
if($_FILES["photo"]["error"] === UPLOAD_ERR_OK) {
|
||||||
$album = null;
|
$album = NULL;
|
||||||
if(!$anon && $owner_id > 0 && $owner_id === $this->getUser()->getId())
|
if(!$anon && $owner_id > 0 && $owner_id === $this->getUser()->getId())
|
||||||
$album = (new AlbumsRepo)->getUserWallAlbum($wallOwner);
|
$album = (new AlbumsRepo)->getUserWallAlbum($wallOwner);
|
||||||
|
|
||||||
|
@ -354,4 +379,201 @@ final class Wall extends VKAPIRequestHandler
|
||||||
|
|
||||||
return (object)["post_id" => $post->getVirtualId()];
|
return (object)["post_id" => $post->getVirtualId()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function repost(string $object, string $message = "") {
|
||||||
|
$this->requireUser();
|
||||||
|
|
||||||
|
$postArray;
|
||||||
|
if(preg_match('/wall((?:-?)[0-9]+)_([0-9]+)/', $object, $postArray) == 0)
|
||||||
|
$this->fail(100, "One of the parameters specified was missing or invalid: object is incorrect");
|
||||||
|
|
||||||
|
$post = (new PostsRepo)->getPostById((int) $postArray[1], (int) $postArray[2]);
|
||||||
|
if(!$post || $post->isDeleted()) $this->fail(100, "One of the parameters specified was missing or invalid");
|
||||||
|
|
||||||
|
$nPost = new Post;
|
||||||
|
$nPost->setOwner($this->user->getId());
|
||||||
|
$nPost->setWall($this->user->getId());
|
||||||
|
$nPost->setContent($message);
|
||||||
|
$nPost->save();
|
||||||
|
$nPost->attach($post);
|
||||||
|
|
||||||
|
if($post->getOwner(false)->getId() !== $this->user->getId() && !($post->getOwner() instanceof Club))
|
||||||
|
(new RepostNotification($post->getOwner(false), $post, $this->user->identity))->emit();
|
||||||
|
|
||||||
|
return (object) [
|
||||||
|
"success" => 1, // 👍
|
||||||
|
"post_id" => $nPost->getVirtualId(),
|
||||||
|
"reposts_count" => $post->getRepostCount(),
|
||||||
|
"likes_count" => $post->getLikesCount()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getComments(int $owner_id, int $post_id, bool $need_likes = true, int $offset = 0, int $count = 10, string $fields = "sex,screen_name,photo_50,photo_100,online_info,online", string $sort = "asc", bool $extended = false) {
|
||||||
|
$this->requireUser();
|
||||||
|
|
||||||
|
$post = (new PostsRepo)->getPostById($owner_id, $post_id);
|
||||||
|
if(!$post || $post->isDeleted()) $this->fail(100, "One of the parameters specified was missing or invalid");
|
||||||
|
|
||||||
|
$comments = (new CommentsRepo)->getCommentsByTarget($post, $offset+1, $count, $sort == "desc" ? "DESC" : "ASC");
|
||||||
|
|
||||||
|
$items = [];
|
||||||
|
$profiles = [];
|
||||||
|
|
||||||
|
foreach($comments as $comment) {
|
||||||
|
$item = [
|
||||||
|
"id" => $comment->getId(),
|
||||||
|
"from_id" => $comment->getOwner()->getId(),
|
||||||
|
"date" => $comment->getPublicationTime()->timestamp(),
|
||||||
|
"text" => $comment->getText(false),
|
||||||
|
"post_id" => $post->getVirtualId(),
|
||||||
|
"owner_id" => $post->isPostedOnBehalfOfGroup() ? $post->getOwner()->getId() * -1 : $post->getOwner()->getId(),
|
||||||
|
"parents_stack" => [],
|
||||||
|
"thread" => [
|
||||||
|
"count" => 0,
|
||||||
|
"items" => [],
|
||||||
|
"can_post" => false,
|
||||||
|
"show_reply_button" => true,
|
||||||
|
"groups_can_post" => false,
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
if($need_likes == true)
|
||||||
|
$item['likes'] = [
|
||||||
|
"can_like" => 1,
|
||||||
|
"count" => $comment->getLikesCount(),
|
||||||
|
"user_likes" => (int) $comment->hasLikeFrom($this->getUser()),
|
||||||
|
"can_publish" => 1
|
||||||
|
];
|
||||||
|
|
||||||
|
$items[] = $item;
|
||||||
|
if($extended == true)
|
||||||
|
$profiles[] = $comment->getOwner()->getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = [
|
||||||
|
"count" => (new CommentsRepo)->getCommentsCountByTarget($post),
|
||||||
|
"items" => $items,
|
||||||
|
"current_level_count" => (new CommentsRepo)->getCommentsCountByTarget($post),
|
||||||
|
"can_post" => true,
|
||||||
|
"show_reply_button" => true,
|
||||||
|
"groups_can_post" => false
|
||||||
|
];
|
||||||
|
|
||||||
|
if($extended == true) {
|
||||||
|
$profiles = array_unique($profiles);
|
||||||
|
$response['profiles'] = (!empty($profiles) ? (new Users)->get(implode(',', $profiles), $fields) : []);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (object) $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getComment(int $owner_id, int $comment_id, bool $extended = false, string $fields = "sex,screen_name,photo_50,photo_100,online_info,online") {
|
||||||
|
$this->requireUser();
|
||||||
|
|
||||||
|
$comment = (new CommentsRepo)->get($comment_id); // один хуй айди всех комментов общий
|
||||||
|
|
||||||
|
$profiles = [];
|
||||||
|
|
||||||
|
$item = [
|
||||||
|
"id" => $comment->getId(),
|
||||||
|
"from_id" => $comment->getOwner()->getId(),
|
||||||
|
"date" => $comment->getPublicationTime()->timestamp(),
|
||||||
|
"text" => $comment->getText(false),
|
||||||
|
"post_id" => $comment->getTarget()->getVirtualId(),
|
||||||
|
"owner_id" => $comment->getTarget()->isPostedOnBehalfOfGroup() ? $comment->getTarget()->getOwner()->getId() * -1 : $comment->getTarget()->getOwner()->getId(),
|
||||||
|
"parents_stack" => [],
|
||||||
|
"likes" => [
|
||||||
|
"can_like" => 1,
|
||||||
|
"count" => $comment->getLikesCount(),
|
||||||
|
"user_likes" => (int) $comment->hasLikeFrom($this->getUser()),
|
||||||
|
"can_publish" => 1
|
||||||
|
],
|
||||||
|
"thread" => [
|
||||||
|
"count" => 0,
|
||||||
|
"items" => [],
|
||||||
|
"can_post" => false,
|
||||||
|
"show_reply_button" => true,
|
||||||
|
"groups_can_post" => false,
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
if($extended == true)
|
||||||
|
$profiles[] = $comment->getOwner()->getId();
|
||||||
|
|
||||||
|
$response = [
|
||||||
|
"items" => [$item],
|
||||||
|
"can_post" => true,
|
||||||
|
"show_reply_button" => true,
|
||||||
|
"groups_can_post" => false
|
||||||
|
];
|
||||||
|
|
||||||
|
if($extended == true) {
|
||||||
|
$profiles = array_unique($profiles);
|
||||||
|
$response['profiles'] = (!empty($profiles) ? (new Users)->get(implode(',', $profiles), $fields) : []);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createComment(int $owner_id, int $post_id, string $message, int $from_group = 0) {
|
||||||
|
$post = (new PostsRepo)->getPostById($owner_id, $post_id);
|
||||||
|
if(!$post || $post->isDeleted()) $this->fail(100, "One of the parameters specified was missing or invalid");
|
||||||
|
|
||||||
|
if($post->getTargetWall() < 0)
|
||||||
|
$club = (new ClubsRepo)->get(abs($post->getTargetWall()));
|
||||||
|
|
||||||
|
$flags = 0;
|
||||||
|
if($from_group != 0 && !is_null($club) && $club->canBeModifiedBy($this->user))
|
||||||
|
$flags |= 0b10000000;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$comment = new Comment;
|
||||||
|
$comment->setOwner($this->user->getId());
|
||||||
|
$comment->setModel(get_class($post));
|
||||||
|
$comment->setTarget($post->getId());
|
||||||
|
$comment->setContent($message);
|
||||||
|
$comment->setCreated(time());
|
||||||
|
$comment->setFlags($flags);
|
||||||
|
$comment->save();
|
||||||
|
} catch (\LengthException $ex) {
|
||||||
|
$this->fail(1, "ошибка про то что коммент большой слишком");
|
||||||
|
}
|
||||||
|
|
||||||
|
if($post->getOwner()->getId() !== $this->user->getId())
|
||||||
|
if(($owner = $post->getOwner()) instanceof User)
|
||||||
|
(new CommentNotification($owner, $comment, $post, $this->user))->emit();
|
||||||
|
|
||||||
|
return (object) [
|
||||||
|
"comment_id" => $comment->getId(),
|
||||||
|
"parents_stack" => []
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteComment(int $comment_id) {
|
||||||
|
$this->requireUser();
|
||||||
|
|
||||||
|
$comment = (new CommentsRepo)->get($comment_id);
|
||||||
|
if(!$comment) $this->fail(100, "One of the parameters specified was missing or invalid");;
|
||||||
|
if(!$comment->canBeDeletedBy($this->user))
|
||||||
|
$this->fail(7, "Access denied");
|
||||||
|
|
||||||
|
$comment->delete();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getApiPhoto($attachment) {
|
||||||
|
return [
|
||||||
|
"type" => "photo",
|
||||||
|
"photo" => [
|
||||||
|
"album_id" => $attachment->getAlbum() ? $attachment->getAlbum()->getId() : NULL,
|
||||||
|
"date" => $attachment->getPublicationTime()->timestamp(),
|
||||||
|
"id" => $attachment->getVirtualId(),
|
||||||
|
"owner_id" => $attachment->getOwner()->getId(),
|
||||||
|
"sizes" => array_values($attachment->getVkApiSizes()),
|
||||||
|
"text" => "",
|
||||||
|
"has_tags" => false
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
16
Vagrantfile
vendored
16
Vagrantfile
vendored
|
@ -1,16 +1,22 @@
|
||||||
# -*- mode: ruby -*-
|
# -*- mode: ruby -*-
|
||||||
# vi: set ft=ruby :
|
# vi: set ft=ruby :
|
||||||
Vagrant.configure("2") do |config|
|
Vagrant.configure("2") do |config|
|
||||||
config.vm.box = "freebsd/FreeBSD-12.1-STABLE"
|
config.vm.box = "freebsd/FreeBSD-13.1-RC2"
|
||||||
|
config.vm.box_version = "2022.04.07"
|
||||||
|
|
||||||
config.vm.network "forwarded_port", guest: 80, host: 4000
|
config.vm.network "forwarded_port", guest: 80, host: 4000
|
||||||
|
|
||||||
config.vm.synced_folder ".", "/.ovk_release"
|
|
||||||
|
|
||||||
config.vm.provider "virtualbox" do |vb|
|
config.vm.provider "virtualbox" do |vb|
|
||||||
vb.gui = true
|
vb.gui = true
|
||||||
vb.memory = "1024"
|
vb.cpus = 4
|
||||||
|
vb.memory = "1568"
|
||||||
end
|
end
|
||||||
|
|
||||||
config.vm.provision "shell", inline: "/bin/tcsh /.ovk_release/install/automated/freebsd-12/install"
|
config.vm.provider "vmware_workstation" do |vwx|
|
||||||
|
vwx.gui = true
|
||||||
|
vwx.vmx["memsize"] = "1568"
|
||||||
|
vwx.vmx["numvcpus"] = "4"
|
||||||
|
end
|
||||||
|
|
||||||
|
config.vm.provision "shell", inline: "/bin/tcsh /.ovk_release/install/automated/freebsd-13/install"
|
||||||
end
|
end
|
||||||
|
|
316
Web/Models/Entities/Application.php
Normal file
316
Web/Models/Entities/Application.php
Normal file
|
@ -0,0 +1,316 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Models\Entities;
|
||||||
|
use Chandler\Database\DatabaseConnection;
|
||||||
|
use Nette\Utils\Image;
|
||||||
|
use Nette\Utils\UnknownImageFileException;
|
||||||
|
use openvk\Web\Models\Repositories\Notes;
|
||||||
|
use openvk\Web\Models\Repositories\Users;
|
||||||
|
use openvk\Web\Models\RowModel;
|
||||||
|
|
||||||
|
class Application extends RowModel
|
||||||
|
{
|
||||||
|
protected $tableName = "apps";
|
||||||
|
|
||||||
|
const PERMS = [
|
||||||
|
"notify",
|
||||||
|
"friends",
|
||||||
|
"photos",
|
||||||
|
"audio",
|
||||||
|
"video",
|
||||||
|
"stories",
|
||||||
|
"pages",
|
||||||
|
"status",
|
||||||
|
"notes",
|
||||||
|
"messages",
|
||||||
|
"wall",
|
||||||
|
"ads",
|
||||||
|
"docs",
|
||||||
|
"groups",
|
||||||
|
"notifications",
|
||||||
|
"stats",
|
||||||
|
"email",
|
||||||
|
"market",
|
||||||
|
];
|
||||||
|
|
||||||
|
private function getAvatarsDir(): string
|
||||||
|
{
|
||||||
|
$uploadSettings = OPENVK_ROOT_CONF["openvk"]["preferences"]["uploads"];
|
||||||
|
if($uploadSettings["mode"] === "server" && $uploadSettings["server"]["kind"] === "cdn")
|
||||||
|
return $uploadSettings["server"]["directory"];
|
||||||
|
else
|
||||||
|
return OPENVK_ROOT . "/storage/";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getId(): int
|
||||||
|
{
|
||||||
|
return $this->getRecord()->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOwner(): User
|
||||||
|
{
|
||||||
|
return (new Users)->get($this->getRecord()->owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getName(): string
|
||||||
|
{
|
||||||
|
return $this->getRecord()->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDescription(): string
|
||||||
|
{
|
||||||
|
return $this->getRecord()->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAvatarUrl(): string
|
||||||
|
{
|
||||||
|
$serverUrl = ovk_scheme(true) . $_SERVER["HTTP_HOST"];
|
||||||
|
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"]) {
|
||||||
|
default:
|
||||||
|
case "default":
|
||||||
|
case "basic":
|
||||||
|
return "$serverUrl/blob_" . substr($hash, 0, 2) . "/$hash" . "_app_avatar.png";
|
||||||
|
case "accelerated":
|
||||||
|
return "$serverUrl/openvk-datastore/$hash" . "_app_avatar.png";
|
||||||
|
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" . "_app_avatar.png"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNote(): ?Note
|
||||||
|
{
|
||||||
|
if(!$this->getRecord()->news)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return (new Notes)->get($this->getRecord()->news);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNoteLink(): string
|
||||||
|
{
|
||||||
|
$note = $this->getNote();
|
||||||
|
if(!$note)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
return ovk_scheme(true) . $_SERVER["HTTP_HOST"] . "/note" . $note->getPrettyId();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBalance(): float
|
||||||
|
{
|
||||||
|
return $this->getRecord()->coins;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getURL(): string
|
||||||
|
{
|
||||||
|
return $this->getRecord()->address;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOrigin(): string
|
||||||
|
{
|
||||||
|
$parsed = parse_url($this->getURL());
|
||||||
|
|
||||||
|
return (
|
||||||
|
($parsed["scheme"] ?? "https") . "://"
|
||||||
|
. ($parsed["host"] ?? "127.0.0.1") . ":"
|
||||||
|
. ($parsed["port"] ?? "443")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUsersCount(): int
|
||||||
|
{
|
||||||
|
$cx = DatabaseConnection::i()->getContext();
|
||||||
|
return sizeof($cx->table("app_users")->where("app", $this->getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getInstallationEntry(User $user): ?array
|
||||||
|
{
|
||||||
|
$cx = DatabaseConnection::i()->getContext();
|
||||||
|
$entry = $cx->table("app_users")->where([
|
||||||
|
"app" => $this->getId(),
|
||||||
|
"user" => $user->getId(),
|
||||||
|
])->fetch();
|
||||||
|
|
||||||
|
if(!$entry)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return $entry->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPermissions(User $user): array
|
||||||
|
{
|
||||||
|
$permMask = 0;
|
||||||
|
$installInfo = $this->getInstallationEntry($user);
|
||||||
|
if(!$installInfo)
|
||||||
|
$this->install($user);
|
||||||
|
else
|
||||||
|
$permMask = $installInfo["access"];
|
||||||
|
|
||||||
|
$res = [];
|
||||||
|
for($i = 0; $i < sizeof(self::PERMS); $i++) {
|
||||||
|
$checkVal = 1 << $i;
|
||||||
|
if(($permMask & $checkVal) > 0)
|
||||||
|
$res[] = self::PERMS[$i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isInstalledBy(User $user): bool
|
||||||
|
{
|
||||||
|
return !is_null($this->getInstallationEntry($user));
|
||||||
|
}
|
||||||
|
|
||||||
|
function setNoteLink(?string $link): bool
|
||||||
|
{
|
||||||
|
if(!$link) {
|
||||||
|
$this->stateChanges("news", NULL);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
preg_match("%note([0-9]+)_([0-9]+)$%", $link, $matches);
|
||||||
|
if(sizeof($matches) != 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
$owner = is_null($this->getRecord()) ? $this->changes["owner"] : $this->getRecord()->owner;
|
||||||
|
[, $ownerId, $vid] = $matches;
|
||||||
|
if($ownerId != $owner)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
$note = (new Notes)->getNoteById((int) $ownerId, (int) $vid);
|
||||||
|
if(!$note)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
$this->stateChanges("news", $note->getId());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setAvatar(array $file): int
|
||||||
|
{
|
||||||
|
if($file["error"] !== UPLOAD_ERR_OK)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$image = Image::fromFile($file["tmp_name"]);
|
||||||
|
} catch (UnknownImageFileException $e) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
$hash = hash_file("adler32", $file["tmp_name"]);
|
||||||
|
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");
|
||||||
|
|
||||||
|
$this->stateChanges("avatar_hash", $hash);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setPermission(User $user, string $perm, bool $enabled): bool
|
||||||
|
{
|
||||||
|
$permMask = 0;
|
||||||
|
$installInfo = $this->getInstallationEntry($user);
|
||||||
|
if(!$installInfo)
|
||||||
|
$this->install($user);
|
||||||
|
else
|
||||||
|
$permMask = $installInfo["access"];
|
||||||
|
|
||||||
|
$index = array_search($perm, self::PERMS);
|
||||||
|
if($index === false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
$permVal = 1 << $index;
|
||||||
|
$permMask = $enabled ? ($permMask | $permVal) : ($permMask ^ $permVal);
|
||||||
|
|
||||||
|
$cx = DatabaseConnection::i()->getContext();
|
||||||
|
$cx->table("app_users")->where([
|
||||||
|
"app" => $this->getId(),
|
||||||
|
"user" => $user->getId(),
|
||||||
|
])->update([
|
||||||
|
"access" => $permMask,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isEnabled(): bool
|
||||||
|
{
|
||||||
|
return (bool) $this->getRecord()->enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
function enable(): void
|
||||||
|
{
|
||||||
|
$this->stateChanges("enabled", 1);
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
function disable(): void
|
||||||
|
{
|
||||||
|
$this->stateChanges("enabled", 0);
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
function install(User $user): void
|
||||||
|
{
|
||||||
|
if(!$this->getInstallationEntry($user)) {
|
||||||
|
$cx = DatabaseConnection::i()->getContext();
|
||||||
|
$cx->table("app_users")->insert([
|
||||||
|
"app" => $this->getId(),
|
||||||
|
"user" => $user->getId(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function uninstall(User $user): void
|
||||||
|
{
|
||||||
|
$cx = DatabaseConnection::i()->getContext();
|
||||||
|
$cx->table("app_users")->where([
|
||||||
|
"app" => $this->getId(),
|
||||||
|
"user" => $user->getId(),
|
||||||
|
])->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
function addCoins(float $coins): float
|
||||||
|
{
|
||||||
|
$res = $this->getBalance() + $coins;
|
||||||
|
$this->stateChanges("coins", $res);
|
||||||
|
$this->save();
|
||||||
|
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
|
function withdrawCoins(): void
|
||||||
|
{
|
||||||
|
$balance = $this->getBalance();
|
||||||
|
$tax = ($balance / 100) * OPENVK_ROOT_CONF["openvk"]["preferences"]["apps"]["withdrawTax"];
|
||||||
|
|
||||||
|
$owner = $this->getOwner();
|
||||||
|
$owner->setCoins($owner->getCoins() + ($balance - $tax));
|
||||||
|
$this->setCoins(0.0);
|
||||||
|
$this->save();
|
||||||
|
$owner->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
function delete(bool $softly = true): void
|
||||||
|
{
|
||||||
|
if($softly)
|
||||||
|
throw new \UnexpectedValueException("Can't delete apps softly.");
|
||||||
|
|
||||||
|
$cx = DatabaseConnection::i()->getContext();
|
||||||
|
$cx->table("app_users")->where("app", $this->getId())->delete();
|
||||||
|
|
||||||
|
parent::delete(false);
|
||||||
|
}
|
||||||
|
}
|
49
Web/Models/Entities/BannedLink.php
Normal file
49
Web/Models/Entities/BannedLink.php
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<?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};
|
||||||
|
use Nette\Database\Table\ActiveRow;
|
||||||
|
|
||||||
|
class BannedLink extends RowModel
|
||||||
|
{
|
||||||
|
protected $tableName = "links_banned";
|
||||||
|
private $overrideContentColumn = "reason";
|
||||||
|
|
||||||
|
function getId(): int
|
||||||
|
{
|
||||||
|
return $this->getRecord()->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDomain(): string
|
||||||
|
{
|
||||||
|
return $this->getRecord()->domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getReason(): string
|
||||||
|
{
|
||||||
|
return $this->getRecord()->reason ?? tr("url_is_banned_default_reason");
|
||||||
|
}
|
||||||
|
|
||||||
|
function getInitiator(): ?User
|
||||||
|
{
|
||||||
|
return (new Users)->get($this->getRecord()->initiator);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
return addslashes("/" . $this->getDomain() . $this->getRawRegexp() . "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRawRegexp(): string
|
||||||
|
{
|
||||||
|
return $this->getRecord()->regexp_rule;
|
||||||
|
}
|
||||||
|
}
|
|
@ -67,7 +67,7 @@ class Club extends RowModel
|
||||||
|
|
||||||
function getName(): string
|
function getName(): string
|
||||||
{
|
{
|
||||||
return ovk_proc_strtr($this->getRecord()->name, 32);
|
return $this->getRecord()->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCanonicalName(): string
|
function getCanonicalName(): string
|
||||||
|
@ -100,6 +100,14 @@ class Club extends RowModel
|
||||||
return $this->getRecord()->about;
|
return $this->getRecord()->about;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getDescriptionHtml(): ?string
|
||||||
|
{
|
||||||
|
if(!is_null($this->getDescription()))
|
||||||
|
return nl2br(htmlspecialchars($this->getDescription(), ENT_DISALLOWED | ENT_XHTML));
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
function getShortCode(): ?string
|
function getShortCode(): ?string
|
||||||
{
|
{
|
||||||
return $this->getRecord()->shortcode;
|
return $this->getRecord()->shortcode;
|
||||||
|
@ -302,8 +310,8 @@ class Club extends RowModel
|
||||||
{
|
{
|
||||||
$manager = (new Managers)->getByUserAndClub($user->getId(), $this->getId());
|
$manager = (new Managers)->getByUserAndClub($user->getId(), $this->getId());
|
||||||
|
|
||||||
if ($ignoreHidden && $manager !== null && $manager->isHidden())
|
if ($ignoreHidden && $manager !== NULL && $manager->isHidden())
|
||||||
return null;
|
return NULL;
|
||||||
|
|
||||||
return $manager;
|
return $manager;
|
||||||
}
|
}
|
||||||
|
@ -347,5 +355,10 @@ class Club extends RowModel
|
||||||
return $this->getRecord()->website;
|
return $this->getRecord()->website;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getAlert(): ?string
|
||||||
|
{
|
||||||
|
return $this->getRecord()->alert;
|
||||||
|
}
|
||||||
|
|
||||||
use Traits\TSubscribable;
|
use Traits\TSubscribable;
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,7 +131,7 @@ class Correspondence
|
||||||
*/
|
*/
|
||||||
function getPreviewMessage(): ?Message
|
function getPreviewMessage(): ?Message
|
||||||
{
|
{
|
||||||
$messages = $this->getMessages(1, null, 1);
|
$messages = $this->getMessages(1, NULL, 1);
|
||||||
return $messages[0] ?? NULL;
|
return $messages[0] ?? NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
15
Web/Models/Entities/EmailChangeVerification.php
Normal file
15
Web/Models/Entities/EmailChangeVerification.php
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?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;
|
||||||
|
|
||||||
|
class EmailChangeVerification extends PasswordReset
|
||||||
|
{
|
||||||
|
protected $tableName = "email_change_verifications";
|
||||||
|
|
||||||
|
function getNewEmail(): string
|
||||||
|
{
|
||||||
|
return $this->getRecord()->new_email;
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,8 @@ abstract class Media extends Postable
|
||||||
{
|
{
|
||||||
protected $fileExtension = "oct"; #octet stream xddd
|
protected $fileExtension = "oct"; #octet stream xddd
|
||||||
protected $upperNodeReferenceColumnName = "owner";
|
protected $upperNodeReferenceColumnName = "owner";
|
||||||
|
protected $processingPlaceholder = NULL;
|
||||||
|
protected $processingTime = 30;
|
||||||
|
|
||||||
function __destruct()
|
function __destruct()
|
||||||
{
|
{
|
||||||
|
@ -23,6 +25,11 @@ abstract class Media extends Postable
|
||||||
return OPENVK_ROOT . "/storage/";
|
return OPENVK_ROOT . "/storage/";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function checkIfFileIsProcessed(): bool
|
||||||
|
{
|
||||||
|
throw new \LogicException("checkIfFileIsProcessed is not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
abstract protected function saveFile(string $filename, string $hash): bool;
|
abstract protected function saveFile(string $filename, string $hash): bool;
|
||||||
|
|
||||||
protected function pathFromHash(string $hash): string
|
protected function pathFromHash(string $hash): string
|
||||||
|
@ -41,6 +48,10 @@ abstract class Media extends Postable
|
||||||
|
|
||||||
function getURL(): string
|
function getURL(): string
|
||||||
{
|
{
|
||||||
|
if(!is_null($this->processingPlaceholder))
|
||||||
|
if(!$this->isProcessed())
|
||||||
|
return "/assets/packages/static/openvk/$this->processingPlaceholder.$this->fileExtension";
|
||||||
|
|
||||||
$hash = $this->getRecord()->hash;
|
$hash = $this->getRecord()->hash;
|
||||||
|
|
||||||
switch(OPENVK_ROOT_CONF["openvk"]["preferences"]["uploads"]["mode"]) {
|
switch(OPENVK_ROOT_CONF["openvk"]["preferences"]["uploads"]["mode"]) {
|
||||||
|
@ -55,7 +66,7 @@ abstract class Media extends Postable
|
||||||
case "server":
|
case "server":
|
||||||
$settings = (object) OPENVK_ROOT_CONF["openvk"]["preferences"]["uploads"]["server"];
|
$settings = (object) OPENVK_ROOT_CONF["openvk"]["preferences"]["uploads"]["server"];
|
||||||
return (
|
return (
|
||||||
$settings->protocol .
|
$settings->protocol ?? ovk_scheme() .
|
||||||
"://" . $settings->host .
|
"://" . $settings->host .
|
||||||
$settings->path .
|
$settings->path .
|
||||||
substr($hash, 0, 2) . "/$hash.$this->fileExtension"
|
substr($hash, 0, 2) . "/$hash.$this->fileExtension"
|
||||||
|
@ -69,6 +80,26 @@ abstract class Media extends Postable
|
||||||
return $this->getRecord()->description;
|
return $this->getRecord()->description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function isProcessed(): bool
|
||||||
|
{
|
||||||
|
if(is_null($this->processingPlaceholder))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if($this->getRecord()->processed)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
$timeDiff = time() - $this->getRecord()->last_checked;
|
||||||
|
if($timeDiff < $this->processingTime)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
$res = $this->checkIfFileIsProcessed();
|
||||||
|
$this->stateChanges("last_checked", time());
|
||||||
|
$this->stateChanges("processed", $res);
|
||||||
|
$this->save();
|
||||||
|
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
function isDeleted(): bool
|
function isDeleted(): bool
|
||||||
{
|
{
|
||||||
return (bool) $this->getRecord()->deleted;
|
return (bool) $this->getRecord()->deleted;
|
||||||
|
@ -90,6 +121,16 @@ abstract class Media extends Postable
|
||||||
$this->stateChanges("hash", $hash);
|
$this->stateChanges("hash", $hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function save(): void
|
||||||
|
{
|
||||||
|
if(!is_null($this->processingPlaceholder) && is_null($this->getRecord())) {
|
||||||
|
$this->stateChanges("processed", 0);
|
||||||
|
$this->stateChanges("last_checked", time());
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::save();
|
||||||
|
}
|
||||||
|
|
||||||
function delete(bool $softly = true): void
|
function delete(bool $softly = true): void
|
||||||
{
|
{
|
||||||
$deleteQuirk = ovkGetQuirk("blobs.erase-upon-deletion");
|
$deleteQuirk = ovkGetQuirk("blobs.erase-upon-deletion");
|
||||||
|
|
|
@ -61,6 +61,17 @@ class Message extends RowModel
|
||||||
return new DateTime($this->getRecord()->created);
|
return new DateTime($this->getRecord()->created);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
} else {
|
||||||
|
return $dateTime->format("%d.%m.%y");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get date of last edit, if any edits were made, otherwise null.
|
* Get date of last edit, if any edits were made, otherwise null.
|
||||||
*
|
*
|
||||||
|
@ -125,8 +136,8 @@ class Message extends RowModel
|
||||||
"name" => $author->getFirstName().$unreadmsg,
|
"name" => $author->getFirstName().$unreadmsg,
|
||||||
],
|
],
|
||||||
"timing" => [
|
"timing" => [
|
||||||
"sent" => (string) $this->getSendTime()->format("%e %B %G" . tr("time_at_sp") . "%X"),
|
"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(),
|
"text" => $this->getText(),
|
||||||
"read" => !$this->isUnread(),
|
"read" => !$this->isUnread(),
|
||||||
|
|
|
@ -75,8 +75,18 @@ class Note extends Postable
|
||||||
"underline",
|
"underline",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$source = NULL;
|
||||||
|
if(is_null($this->getRecord())) {
|
||||||
|
if(isset($this->changes["source"]))
|
||||||
|
$source = $this->changes["source"];
|
||||||
|
else
|
||||||
|
throw new \LogicException("Can't render note without content set.");
|
||||||
|
} else {
|
||||||
|
$source = $this->getRecord()->source;
|
||||||
|
}
|
||||||
|
|
||||||
$purifier = new HTMLPurifier($config);
|
$purifier = new HTMLPurifier($config);
|
||||||
return $purifier->purify($this->getRecord()->source);
|
return $purifier->purify($source);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getName(): string
|
function getName(): string
|
||||||
|
@ -91,6 +101,9 @@ class Note extends Postable
|
||||||
|
|
||||||
function getText(): string
|
function getText(): string
|
||||||
{
|
{
|
||||||
|
if(is_null($this->getRecord()))
|
||||||
|
return $this->renderHTML();
|
||||||
|
|
||||||
$cached = $this->getRecord()->cached_content;
|
$cached = $this->getRecord()->cached_content;
|
||||||
if(!$cached) {
|
if(!$cached) {
|
||||||
$cached = $this->renderHTML();
|
$cached = $this->renderHTML();
|
||||||
|
|
|
@ -165,8 +165,11 @@ class Photo extends Media
|
||||||
foreach($manifest->Size as $size)
|
foreach($manifest->Size as $size)
|
||||||
$mappings[(string) $size["id"]] = (string) $size["vkId"];
|
$mappings[(string) $size["id"]] = (string) $size["vkId"];
|
||||||
|
|
||||||
foreach($sizes as $id => $meta)
|
foreach($sizes as $id => $meta) {
|
||||||
$res[$mappings[$id] ?? $id] = $meta;
|
$type = $mappings[$id] ?? $id;
|
||||||
|
$meta->type = $type;
|
||||||
|
$res[$type] = $meta;
|
||||||
|
}
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
@ -240,8 +243,11 @@ class Photo extends Media
|
||||||
$photo->setFile($file);
|
$photo->setFile($file);
|
||||||
$photo->save();
|
$photo->save();
|
||||||
|
|
||||||
if(!is_null($album))
|
if(!is_null($album)) {
|
||||||
$album->addPhoto($photo);
|
$album->addPhoto($photo);
|
||||||
|
$album->setEdited(time());
|
||||||
|
$album->save();
|
||||||
|
}
|
||||||
|
|
||||||
return $photo;
|
return $photo;
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,11 @@ class Post extends Postable
|
||||||
return ($this->getRecord()->flags & 0b01000000) > 0;
|
return ($this->getRecord()->flags & 0b01000000) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isDeactivationMessage(): bool
|
||||||
|
{
|
||||||
|
return ($this->getRecord()->flags & 0b00100000) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
function isExplicit(): bool
|
function isExplicit(): bool
|
||||||
{
|
{
|
||||||
return (bool) $this->getRecord()->nsfw;
|
return (bool) $this->getRecord()->nsfw;
|
||||||
|
|
|
@ -87,7 +87,7 @@ abstract class Postable extends Attachable
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO add pagination
|
# TODO add pagination
|
||||||
function getLikers(): \Traversable
|
function getLikers(): \Traversable
|
||||||
{
|
{
|
||||||
$sel = DB::i()->getContext()->table("likes")->where([
|
$sel = DB::i()->getContext()->table("likes")->where([
|
||||||
|
|
|
@ -35,12 +35,12 @@ trait TRichText
|
||||||
"%(([A-z]++):\/\/(\S*?\.\S*?))([\s)\[\]{},\"\'<]|\.\s|$)%",
|
"%(([A-z]++):\/\/(\S*?\.\S*?))([\s)\[\]{},\"\'<]|\.\s|$)%",
|
||||||
(function (array $matches): string {
|
(function (array $matches): string {
|
||||||
$href = str_replace("#", "#", $matches[1]);
|
$href = str_replace("#", "#", $matches[1]);
|
||||||
$href = str_replace(";", ";", $matches[1]);
|
$href = rawurlencode(str_replace(";", ";", $matches[1]));
|
||||||
$link = str_replace("#", "#", $matches[3]);
|
$link = str_replace("#", "#", $matches[3]);
|
||||||
$link = str_replace(";", ";", $matches[3]);
|
$link = str_replace(";", ";", $matches[3]);
|
||||||
$rel = $this->isAd() ? "sponsored" : "ugc";
|
$rel = $this->isAd() ? "sponsored" : "ugc";
|
||||||
|
|
||||||
return "<a href='$href' rel='$rel' target='_blank'>$link</a>" . htmlentities($matches[4]);
|
return "<a href='/away.php?to=$href' rel='$rel' target='_blank'>$link</a>" . htmlentities($matches[4]);
|
||||||
}),
|
}),
|
||||||
$text
|
$text
|
||||||
);
|
);
|
||||||
|
@ -55,21 +55,28 @@ trait TRichText
|
||||||
{
|
{
|
||||||
$contentColumn = property_exists($this, "overrideContentColumn") ? $this->overrideContentColumn : "content";
|
$contentColumn = property_exists($this, "overrideContentColumn") ? $this->overrideContentColumn : "content";
|
||||||
|
|
||||||
$text = htmlentities($this->getRecord()->{$contentColumn}, ENT_DISALLOWED | ENT_XHTML);
|
$text = htmlspecialchars($this->getRecord()->{$contentColumn}, ENT_DISALLOWED | ENT_XHTML);
|
||||||
$proc = iconv_strlen($this->getRecord()->{$contentColumn}) <= OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["postSizes"]["processingLimit"];
|
$proc = iconv_strlen($this->getRecord()->{$contentColumn}) <= OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["postSizes"]["processingLimit"];
|
||||||
if($html) {
|
if($html) {
|
||||||
if($proc) {
|
if($proc) {
|
||||||
$rel = $this->isAd() ? "sponsored" : "ugc";
|
$rel = $this->isAd() ? "sponsored" : "ugc";
|
||||||
$text = $this->formatLinks($text);
|
$text = $this->formatLinks($text);
|
||||||
$text = preg_replace("%@([A-Za-z0-9]++) \(([\p{L} 0-9]+)\)%Xu", "[$1|$2]", $text);
|
$text = preg_replace("%@([A-Za-z0-9]++) \(((?:[\p{L&}\p{Lo} 0-9]\p{Mn}?)++)\)%Xu", "[$1|$2]", $text);
|
||||||
$text = preg_replace("%([\n\r\s]|^)(@([A-Za-z0-9]++))%Xu", "$1[$3|@$3]", $text);
|
$text = preg_replace("%([\n\r\s]|^)(@([A-Za-z0-9]++))%Xu", "$1[$3|@$3]", $text);
|
||||||
$text = preg_replace("%\[([A-Za-z0-9]++)\|([\p{L} 0-9@]+)\]%Xu", "<a href='/$1'>$2</a>", $text);
|
$text = preg_replace("%\[([A-Za-z0-9]++)\|((?:[\p{L&}\p{Lo} 0-9@]\p{Mn}?)++)\]%Xu", "<a href='/$1'>$2</a>", $text);
|
||||||
$text = preg_replace("%([\n\r\s]|^)(#([\p{L}_-]++[0-9]*[\p{L}_-]*))%Xu", "$1<a href='/feed/hashtag/$3'>$2</a>", $text);
|
$text = preg_replace_callback("%([\n\r\s]|^)(\#([\p{L}_0-9][\p{L}_0-9\(\)\-\']+[\p{L}_0-9\(\)]|[\p{L}_0-9]{1,2}))%Xu", function($m) {
|
||||||
|
$slug = rawurlencode($m[3]);
|
||||||
|
|
||||||
|
return "$m[1]<a href='/feed/hashtag/$slug'>$m[2]</a>";
|
||||||
|
}, $text);
|
||||||
|
|
||||||
$text = $this->formatEmojis($text);
|
$text = $this->formatEmojis($text);
|
||||||
}
|
}
|
||||||
|
|
||||||
$text = $this->removeZalgo($text);
|
$text = $this->removeZalgo($text);
|
||||||
$text = nl2br($text);
|
$text = nl2br($text);
|
||||||
|
} else {
|
||||||
|
$text = str_replace("\r\n","\n", $text);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["christian"])
|
if(OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["christian"])
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Models\Entities;
|
namespace openvk\Web\Models\Entities;
|
||||||
|
use morphos\Gender;
|
||||||
use openvk\Web\Themes\{Themepack, Themepacks};
|
use openvk\Web\Themes\{Themepack, Themepacks};
|
||||||
use openvk\Web\Util\DateTime;
|
use openvk\Web\Util\DateTime;
|
||||||
use openvk\Web\Models\RowModel;
|
use openvk\Web\Models\RowModel;
|
||||||
|
@ -9,6 +10,7 @@ use openvk\Web\Models\Exceptions\InvalidUserNameException;
|
||||||
use Nette\Database\Table\ActiveRow;
|
use Nette\Database\Table\ActiveRow;
|
||||||
use Chandler\Database\DatabaseConnection;
|
use Chandler\Database\DatabaseConnection;
|
||||||
use Chandler\Security\User as ChandlerUser;
|
use Chandler\Security\User as ChandlerUser;
|
||||||
|
use function morphos\Russian\inflectName;
|
||||||
|
|
||||||
class User extends RowModel
|
class User extends RowModel
|
||||||
{
|
{
|
||||||
|
@ -84,6 +86,11 @@ class User extends RowModel
|
||||||
return (bool) $this->getRecord()->microblog;
|
return (bool) $this->getRecord()->microblog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getMainPage(): int
|
||||||
|
{
|
||||||
|
return $this->getRecord()->main_page;
|
||||||
|
}
|
||||||
|
|
||||||
function getChandlerGUID(): string
|
function getChandlerGUID(): string
|
||||||
{
|
{
|
||||||
return $this->getRecord()->user;
|
return $this->getRecord()->user;
|
||||||
|
@ -138,24 +145,32 @@ class User extends RowModel
|
||||||
return iterator_to_array($avPhotos)[0] ?? NULL;
|
return iterator_to_array($avPhotos)[0] ?? NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFirstName(): string
|
function getFirstName(bool $pristine = false): string
|
||||||
{
|
{
|
||||||
return $this->getRecord()->deleted ? "DELETED" : mb_convert_case($this->getRecord()->first_name, MB_CASE_TITLE);
|
$name = ($this->isDeleted() && !$this->isDeactivated() ? "DELETED" : mb_convert_case($this->getRecord()->first_name, MB_CASE_TITLE));
|
||||||
|
if((($ts = tr("__transNames")) !== "@__transNames") && !$pristine)
|
||||||
|
return mb_convert_case(transliterator_transliterate($ts, $name), MB_CASE_TITLE);
|
||||||
|
else
|
||||||
|
return $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLastName(): string
|
function getLastName(bool $pristine = false): string
|
||||||
{
|
{
|
||||||
return $this->getRecord()->deleted ? "DELETED" : mb_convert_case($this->getRecord()->last_name, MB_CASE_TITLE);
|
$name = ($this->isDeleted() && !$this->isDeactivated() ? "DELETED" : mb_convert_case($this->getRecord()->last_name, MB_CASE_TITLE));
|
||||||
|
if((($ts = tr("__transNames")) !== "@__transNames") && !$pristine)
|
||||||
|
return mb_convert_case(transliterator_transliterate($ts, $name), MB_CASE_TITLE);
|
||||||
|
else
|
||||||
|
return $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPseudo(): ?string
|
function getPseudo(): ?string
|
||||||
{
|
{
|
||||||
return $this->getRecord()->deleted ? "DELETED" : $this->getRecord()->pseudo;
|
return ($this->isDeleted() && !$this->isDeactivated() ? "DELETED" : $this->getRecord()->pseudo);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFullName(): string
|
function getFullName(): string
|
||||||
{
|
{
|
||||||
if($this->getRecord()->deleted)
|
if($this->isDeleted() && !$this->isDeactivated())
|
||||||
return "DELETED";
|
return "DELETED";
|
||||||
|
|
||||||
$pseudo = $this->getPseudo();
|
$pseudo = $this->getPseudo();
|
||||||
|
@ -167,12 +182,23 @@ class User extends RowModel
|
||||||
return $this->getFirstName() . $pseudo . $this->getLastName();
|
return $this->getFirstName() . $pseudo . $this->getLastName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getMorphedName(string $case = "genitive", bool $fullName = true): string
|
||||||
|
{
|
||||||
|
$name = $fullName ? ($this->getLastName() . " " . $this->getFirstName()) : $this->getFirstName();
|
||||||
|
if(!preg_match("%^[А-яё\-]+$%", $name))
|
||||||
|
return $name; # name is probably not russian
|
||||||
|
|
||||||
|
$inflected = inflectName($name, $case, $this->isFemale() ? Gender::FEMALE : Gender::MALE);
|
||||||
|
|
||||||
|
return $inflected ?: $name;
|
||||||
|
}
|
||||||
|
|
||||||
function getCanonicalName(): string
|
function getCanonicalName(): string
|
||||||
{
|
{
|
||||||
if($this->getRecord()->deleted)
|
if($this->isDeleted() && !$this->isDeactivated())
|
||||||
return "DELETED";
|
return "DELETED";
|
||||||
else
|
else
|
||||||
return $this->getFirstName() . ' ' . $this->getLastName();
|
return $this->getFirstName() . " " . $this->getLastName();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPhone(): ?string
|
function getPhone(): ?string
|
||||||
|
@ -268,6 +294,19 @@ class User extends RowModel
|
||||||
return $this->getRecord()->marital_status;
|
return $this->getRecord()->marital_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getLocalizedMaritalStatus(): string
|
||||||
|
{
|
||||||
|
$status = $this->getMaritalStatus();
|
||||||
|
$string = "relationship_$status";
|
||||||
|
if($this->isFemale()) {
|
||||||
|
$res = tr($string . "_fem");
|
||||||
|
if($res != ("@" . $string . "_fem"))
|
||||||
|
return $res; # If fem version exists, return
|
||||||
|
}
|
||||||
|
|
||||||
|
return tr($string);
|
||||||
|
}
|
||||||
|
|
||||||
function getContactEmail(): ?string
|
function getContactEmail(): ?string
|
||||||
{
|
{
|
||||||
return $this->getRecord()->email_contact;
|
return $this->getRecord()->email_contact;
|
||||||
|
@ -325,9 +364,17 @@ class User extends RowModel
|
||||||
|
|
||||||
function getBirthday(): ?DateTime
|
function getBirthday(): ?DateTime
|
||||||
{
|
{
|
||||||
|
if(is_null($this->getRecord()->birthday))
|
||||||
|
return NULL;
|
||||||
|
else
|
||||||
return new DateTime($this->getRecord()->birthday);
|
return new DateTime($this->getRecord()->birthday);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getBirthdayPrivacy(): int
|
||||||
|
{
|
||||||
|
return $this->getRecord()->birthday_privacy;
|
||||||
|
}
|
||||||
|
|
||||||
function getAge(): ?int
|
function getAge(): ?int
|
||||||
{
|
{
|
||||||
return (int)floor((time() - $this->getBirthday()->timestamp()) / YEAR);
|
return (int)floor((time() - $this->getBirthday()->timestamp()) / YEAR);
|
||||||
|
@ -453,6 +500,16 @@ class User extends RowModel
|
||||||
return $this->_abstractRelationCount("get-friends");
|
return $this->_abstractRelationCount("get-friends");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getFriendsOnline(int $page = 1, int $limit = 6): \Traversable
|
||||||
|
{
|
||||||
|
return $this->_abstractRelationGenerator("get-online-friends", $page, $limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFriendsOnlineCount(): int
|
||||||
|
{
|
||||||
|
return $this->_abstractRelationCount("get-online-friends");
|
||||||
|
}
|
||||||
|
|
||||||
function getFollowers(int $page = 1, int $limit = 6): \Traversable
|
function getFollowers(int $page = 1, int $limit = 6): \Traversable
|
||||||
{
|
{
|
||||||
return $this->_abstractRelationGenerator("get-followers", $page, $limit);
|
return $this->_abstractRelationGenerator("get-followers", $page, $limit);
|
||||||
|
@ -711,7 +768,7 @@ class User extends RowModel
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ban(string $reason, bool $deleteSubscriptions = true): void
|
function ban(string $reason, bool $deleteSubscriptions = true, ?int $unban_time = NULL): void
|
||||||
{
|
{
|
||||||
if($deleteSubscriptions) {
|
if($deleteSubscriptions) {
|
||||||
$subs = DatabaseConnection::i()->getContext()->table("subscriptions");
|
$subs = DatabaseConnection::i()->getContext()->table("subscriptions");
|
||||||
|
@ -725,9 +782,31 @@ class User extends RowModel
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->setBlock_Reason($reason);
|
$this->setBlock_Reason($reason);
|
||||||
|
$this->setUnblock_time($unban_time);
|
||||||
$this->save();
|
$this->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function deactivate(?string $reason): void
|
||||||
|
{
|
||||||
|
$this->setDeleted(1);
|
||||||
|
$this->setDeact_Date(time() + (MONTH * 7));
|
||||||
|
$this->setDeact_Reason($reason);
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
function reactivate(): void
|
||||||
|
{
|
||||||
|
$this->setDeleted(0);
|
||||||
|
$this->setDeact_Date(0);
|
||||||
|
$this->setDeact_Reason("");
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDeactivationDate(): DateTime
|
||||||
|
{
|
||||||
|
return new DateTime($this->getRecord()->deact_date);
|
||||||
|
}
|
||||||
|
|
||||||
function verifyNumber(string $code): bool
|
function verifyNumber(string $code): bool
|
||||||
{
|
{
|
||||||
$ver = $this->getPendingPhoneVerification();
|
$ver = $this->getPendingPhoneVerification();
|
||||||
|
@ -864,6 +943,17 @@ class User extends RowModel
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changeEmail(string $email): void
|
||||||
|
{
|
||||||
|
DatabaseConnection::i()->getContext()->table("ChandlerUsers")
|
||||||
|
->where("id", $this->getChandlerUser()->getId())->update([
|
||||||
|
"login" => $email
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->stateChanges("email", $email);
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
|
||||||
function adminNotify(string $message): bool
|
function adminNotify(string $message): bool
|
||||||
{
|
{
|
||||||
$admId = OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["adminAccount"];
|
$admId = OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["adminAccount"];
|
||||||
|
@ -888,6 +978,14 @@ class User extends RowModel
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isDeactivated(): bool
|
||||||
|
{
|
||||||
|
if($this->getDeactivationDate()->timestamp() > time())
|
||||||
|
return TRUE;
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 0 - Default status
|
* 0 - Default status
|
||||||
* 1 - Incognito online status
|
* 1 - Incognito online status
|
||||||
|
@ -915,11 +1013,27 @@ class User extends RowModel
|
||||||
return $this->getRecord()->website;
|
return $this->getRecord()->website;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ты устрица
|
# ты устрица
|
||||||
function isActivated(): bool
|
function isActivated(): bool
|
||||||
{
|
{
|
||||||
return (bool) $this->getRecord()->activated;
|
return (bool) $this->getRecord()->activated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getUnbanTime(): ?string
|
||||||
|
{
|
||||||
|
return !is_null($this->getRecord()->unblock_time) ? date('d.m.Y', $this->getRecord()->unblock_time) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
function canUnbanThemself(): bool
|
||||||
|
{
|
||||||
|
if (!$this->isBanned())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ($this->getRecord()->unblock_time > time() || $this->getRecord()->unblock_time == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
use Traits\TSubscribable;
|
use Traits\TSubscribable;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@ class Video extends Media
|
||||||
protected $tableName = "videos";
|
protected $tableName = "videos";
|
||||||
protected $fileExtension = "ogv";
|
protected $fileExtension = "ogv";
|
||||||
|
|
||||||
|
protected $processingPlaceholder = "video/rendering";
|
||||||
|
|
||||||
protected function saveFile(string $filename, string $hash): bool
|
protected function saveFile(string $filename, string $hash): bool
|
||||||
{
|
{
|
||||||
if(!Shell::commandAvailable("ffmpeg") || !Shell::commandAvailable("ffprobe"))
|
if(!Shell::commandAvailable("ffmpeg") || !Shell::commandAvailable("ffprobe"))
|
||||||
|
@ -37,7 +39,7 @@ class Video extends Media
|
||||||
throw new \DomainException("$filename does not contain any meaningful video streams");
|
throw new \DomainException("$filename does not contain any meaningful video streams");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if(!is_dir($dirId = $this->pathFromHash($hash)))
|
if(!is_dir($dirId = dirname($this->pathFromHash($hash))))
|
||||||
mkdir($dirId);
|
mkdir($dirId);
|
||||||
|
|
||||||
$dir = $this->getBaseDir();
|
$dir = $this->getBaseDir();
|
||||||
|
@ -54,6 +56,22 @@ class Video extends Media
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function checkIfFileIsProcessed(): bool
|
||||||
|
{
|
||||||
|
if($this->getType() != Video::TYPE_DIRECT)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if(!file_exists($this->getFileName())) {
|
||||||
|
if((time() - $this->getRecord()->last_checked) > 3600) {
|
||||||
|
# TODO notify that video processor is probably dead
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
function getName(): string
|
function getName(): string
|
||||||
{
|
{
|
||||||
return $this->getRecord()->name;
|
return $this->getRecord()->name;
|
||||||
|
@ -83,6 +101,9 @@ class Video extends Media
|
||||||
function getThumbnailURL(): string
|
function getThumbnailURL(): string
|
||||||
{
|
{
|
||||||
if($this->getType() === Video::TYPE_DIRECT) {
|
if($this->getType() === Video::TYPE_DIRECT) {
|
||||||
|
if(!$this->isProcessed())
|
||||||
|
return "/assets/packages/static/openvk/video/rendering.apng";
|
||||||
|
|
||||||
return preg_replace("%\.[A-z]++$%", ".gif", $this->getURL());
|
return preg_replace("%\.[A-z]++$%", ".gif", $this->getURL());
|
||||||
} else {
|
} else {
|
||||||
return $this->getVideoDriver()->getThumbnailURL();
|
return $this->getVideoDriver()->getThumbnailURL();
|
||||||
|
|
69
Web/Models/Repositories/Applications.php
Normal file
69
Web/Models/Repositories/Applications.php
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Models\Repositories;
|
||||||
|
use Chandler\Database\DatabaseConnection;
|
||||||
|
use Nette\Database\Table\ActiveRow;
|
||||||
|
use openvk\Web\Models\Entities\Application;
|
||||||
|
use openvk\Web\Models\Entities\User;
|
||||||
|
|
||||||
|
class Applications
|
||||||
|
{
|
||||||
|
private $context;
|
||||||
|
private $apps;
|
||||||
|
private $appRels;
|
||||||
|
|
||||||
|
function __construct()
|
||||||
|
{
|
||||||
|
$this->context = DatabaseConnection::i()->getContext();
|
||||||
|
$this->apps = $this->context->table("apps");
|
||||||
|
$this->appRels = $this->context->table("app_users");
|
||||||
|
}
|
||||||
|
|
||||||
|
private function toApp(?ActiveRow $ar): ?Application
|
||||||
|
{
|
||||||
|
return is_null($ar) ? NULL : new Application($ar);
|
||||||
|
}
|
||||||
|
|
||||||
|
function get(int $id): ?Application
|
||||||
|
{
|
||||||
|
return $this->toApp($this->apps->get($id));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getList(int $page = 1, ?int $perPage = NULL): \Traversable
|
||||||
|
{
|
||||||
|
$perPage = $perPage ?? OPENVK_DEFAULT_PER_PAGE;
|
||||||
|
$apps = $this->apps->where("enabled", 1)->page($page, $perPage);
|
||||||
|
foreach($apps as $app)
|
||||||
|
yield new Application($app);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getListCount(): int
|
||||||
|
{
|
||||||
|
return sizeof($this->apps->where("enabled", 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getByOwner(User $owner, int $page = 1, ?int $perPage = NULL): \Traversable
|
||||||
|
{
|
||||||
|
$perPage = $perPage ?? OPENVK_DEFAULT_PER_PAGE;
|
||||||
|
$apps = $this->apps->where("owner", $owner->getId())->page($page, $perPage);
|
||||||
|
foreach($apps as $app)
|
||||||
|
yield new Application($app);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOwnCount(User $owner): int
|
||||||
|
{
|
||||||
|
return sizeof($this->apps->where("owner", $owner->getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getInstalled(User $user, int $page = 1, ?int $perPage = NULL): \Traversable
|
||||||
|
{
|
||||||
|
$perPage = $perPage ?? OPENVK_DEFAULT_PER_PAGE;
|
||||||
|
$apps = $this->appRels->where("user", $user->getId())->page($page, $perPage);
|
||||||
|
foreach($apps as $appRel)
|
||||||
|
yield $this->get($appRel->app);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getInstalledCount(User $user): int
|
||||||
|
{
|
||||||
|
return sizeof($this->appRels->where("user", $user->getId()));
|
||||||
|
}
|
||||||
|
}
|
73
Web/Models/Repositories/BannedLinks.php
Normal file
73
Web/Models/Repositories/BannedLinks.php
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Models\Repositories;
|
||||||
|
use Chandler\Database\DatabaseConnection as DB;
|
||||||
|
use Nette\Database\Table\{ActiveRow, Selection};
|
||||||
|
use openvk\Web\Models\Entities\BannedLink;
|
||||||
|
|
||||||
|
class BannedLinks
|
||||||
|
{
|
||||||
|
private $context;
|
||||||
|
private $bannedLinks;
|
||||||
|
|
||||||
|
function __construct()
|
||||||
|
{
|
||||||
|
$this->context = DB::i()->getContext();
|
||||||
|
$this->bannedLinks = $this->context->table("links_banned");
|
||||||
|
}
|
||||||
|
|
||||||
|
function toBannedLink(?ActiveRow $ar): ?BannedLink
|
||||||
|
{
|
||||||
|
return is_null($ar) ? NULL : new BannedLink($ar);
|
||||||
|
}
|
||||||
|
|
||||||
|
function get(int $id): ?BannedLink
|
||||||
|
{
|
||||||
|
return $this->toBannedLink($this->bannedLinks->get($id));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getList(?int $page = 1): \Traversable
|
||||||
|
{
|
||||||
|
foreach($this->bannedLinks->order("id DESC")->page($page, OPENVK_DEFAULT_PER_PAGE) as $link)
|
||||||
|
yield new BannedLink($link);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCount(int $page = 1): int
|
||||||
|
{
|
||||||
|
return sizeof($this->bannedLinks->fetch());
|
||||||
|
}
|
||||||
|
|
||||||
|
function getByDomain(string $domain): ?Selection
|
||||||
|
{
|
||||||
|
return $this->bannedLinks->where("domain", $domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isDomainBanned(string $domain): bool
|
||||||
|
{
|
||||||
|
return sizeof($this->bannedLinks->where(["link" => $domain, "regexp_rule" => ""])) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function genLinks($rules): \Traversable
|
||||||
|
{
|
||||||
|
foreach ($rules as $rule)
|
||||||
|
yield $this->get($rule->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function genEntries($links, $uri): \Traversable
|
||||||
|
{
|
||||||
|
foreach($links as $link)
|
||||||
|
if (preg_match($link->getRegexpRule(), $uri))
|
||||||
|
yield $link->getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
function check(string $url): ?array
|
||||||
|
{
|
||||||
|
$uri = strstr(str_replace(["https://", "http://"], "", $url), "/", true);
|
||||||
|
$domain = str_replace("www.", "", $uri);
|
||||||
|
$rules = $this->getByDomain($domain);
|
||||||
|
|
||||||
|
if (is_null($rules))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return iterator_to_array($this->genEntries($this->genLinks($rules), $uri));
|
||||||
|
}
|
||||||
|
}
|
|
@ -45,7 +45,7 @@ class Clubs
|
||||||
|
|
||||||
function getPopularClubs(): \Traversable
|
function getPopularClubs(): \Traversable
|
||||||
{
|
{
|
||||||
$query = "SELECT ROW_NUMBER() OVER (ORDER BY `subscriptions` DESC) as `place`, `target` as `id`, COUNT(`follower`) as `subscriptions` FROM `subscriptions` WHERE `model` = \"openvk\\\Web\\\Models\\\Entities\\\Club\" GROUP BY `target` ORDER BY `subscriptions` DESC, `id` LIMIT 10;";
|
$query = "SELECT ROW_NUMBER() OVER (ORDER BY `subscriptions` DESC) as `place`, `target` as `id`, COUNT(`follower`) as `subscriptions` FROM `subscriptions` WHERE `model` = \"openvk\\\Web\\\Models\\\Entities\\\Club\" GROUP BY `target` ORDER BY `subscriptions` DESC, `id` LIMIT 30;";
|
||||||
$entries = DatabaseConnection::i()->getConnection()->query($query);
|
$entries = DatabaseConnection::i()->getConnection()->query($query);
|
||||||
|
|
||||||
foreach($entries as $entry)
|
foreach($entries as $entry)
|
||||||
|
|
|
@ -26,13 +26,13 @@ class Comments
|
||||||
return $this->toComment($this->comments->get($id));
|
return $this->toComment($this->comments->get($id));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCommentsByTarget(Postable $target, int $page, ?int $perPage = NULL): \Traversable
|
function getCommentsByTarget(Postable $target, int $page, ?int $perPage = NULL, ?string $sort = "ASC"): \Traversable
|
||||||
{
|
{
|
||||||
$comments = $this->comments->where([
|
$comments = $this->comments->where([
|
||||||
"model" => get_class($target),
|
"model" => get_class($target),
|
||||||
"target" => $target->getId(),
|
"target" => $target->getId(),
|
||||||
"deleted" => false,
|
"deleted" => false,
|
||||||
])->page($page, $perPage ?? OPENVK_DEFAULT_PER_PAGE);
|
])->page($page, $perPage ?? OPENVK_DEFAULT_PER_PAGE)->order("created ".$sort);;
|
||||||
|
|
||||||
foreach($comments as $comment)
|
foreach($comments as $comment)
|
||||||
yield $this->toComment($comment);
|
yield $this->toComment($comment);
|
||||||
|
|
33
Web/Models/Repositories/EmailChangeVerifications.php
Normal file
33
Web/Models/Repositories/EmailChangeVerifications.php
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Models\Repositories;
|
||||||
|
use Chandler\Database\DatabaseConnection;
|
||||||
|
use openvk\Web\Models\Entities\EmailChangeVerification;
|
||||||
|
use openvk\Web\Models\Entities\User;
|
||||||
|
use Nette\Database\Table\ActiveRow;
|
||||||
|
|
||||||
|
class EmailChangeVerifications
|
||||||
|
{
|
||||||
|
private $context;
|
||||||
|
private $verifications;
|
||||||
|
|
||||||
|
function __construct()
|
||||||
|
{
|
||||||
|
$this->context = DatabaseConnection::i()->getContext();
|
||||||
|
$this->verifications = $this->context->table("email_change_verifications");
|
||||||
|
}
|
||||||
|
|
||||||
|
function toEmailChangeVerification(?ActiveRow $ar): ?EmailChangeVerification
|
||||||
|
{
|
||||||
|
return is_null($ar) ? NULL : new EmailChangeVerification($ar);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getByToken(string $token): ?EmailChangeVerification
|
||||||
|
{
|
||||||
|
return $this->toEmailChangeVerification($this->verifications->where("key", $token)->fetch());
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLatestByUser(User $user): ?EmailChangeVerification
|
||||||
|
{
|
||||||
|
return $this->toEmailChangeVerification($this->verifications->where("profile", $user->getId())->order("timestamp DESC")->fetch());
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,4 +44,15 @@ class Messages
|
||||||
yield new Correspondence($correspondent, $anotherCorrespondent);
|
yield new Correspondence($correspondent, $anotherCorrespondent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCorrespondenciesCount(RowModel $correspondent): ?int
|
||||||
|
{
|
||||||
|
$id = $correspondent->getId();
|
||||||
|
$class = get_class($correspondent);
|
||||||
|
$query = file_get_contents(__DIR__ . "/../sql/get-correspondencies-count.tsql");
|
||||||
|
DatabaseConnection::i()->getConnection()->query(file_get_contents(__DIR__ . "/../sql/mysql-msg-fix.tsql"));
|
||||||
|
$count = DatabaseConnection::i()->getConnection()->query($query, $id, $class, $id, $class)->fetch()->cnt;
|
||||||
|
bdump($count);
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ class Notes
|
||||||
if(!is_null($note))
|
if(!is_null($note))
|
||||||
return new Note($note);
|
return new Note($note);
|
||||||
else
|
else
|
||||||
return null;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUserNotesCount(User $user): int
|
function getUserNotesCount(User $user): int
|
||||||
|
|
|
@ -71,7 +71,7 @@ class Posts
|
||||||
{
|
{
|
||||||
$hashtag = "#$hashtag";
|
$hashtag = "#$hashtag";
|
||||||
$sel = $this->posts
|
$sel = $this->posts
|
||||||
->where("content LIKE ?", "%$hashtag%")
|
->where("MATCH (content) AGAINST (? IN BOOLEAN MODE)", "+$hashtag")
|
||||||
->where("deleted", 0)
|
->where("deleted", 0)
|
||||||
->order("created DESC")
|
->order("created DESC")
|
||||||
->page($page, $perPage ?? OPENVK_DEFAULT_PER_PAGE);
|
->page($page, $perPage ?? OPENVK_DEFAULT_PER_PAGE);
|
||||||
|
@ -96,7 +96,7 @@ class Posts
|
||||||
if(!is_null($post))
|
if(!is_null($post))
|
||||||
return new Post($post);
|
return new Post($post);
|
||||||
else
|
else
|
||||||
return null;
|
return NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Models\Repositories;
|
namespace openvk\Web\Models\Repositories;
|
||||||
// use openvk\Web\Models\Entities\Ticket;
|
|
||||||
// use openvk\Web\Models\Entities\User;
|
|
||||||
// use openvk\Web\Models\Repositories\Users;
|
|
||||||
use openvk\Web\Models\Entities\TicketComment;
|
use openvk\Web\Models\Entities\TicketComment;
|
||||||
use Chandler\Database\DatabaseConnection;
|
use Chandler\Database\DatabaseConnection;
|
||||||
|
|
||||||
|
@ -22,32 +19,6 @@ class TicketComments
|
||||||
foreach($this->comments->where(['ticket_id' => $ticket_id, 'deleted' => 0]) as $comment) yield new TicketComment($comment);
|
foreach($this->comments->where(['ticket_id' => $ticket_id, 'deleted' => 0]) as $comment) yield new TicketComment($comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
// private function toTicket(?ActiveRow $ar): ?Ticket
|
|
||||||
// {
|
|
||||||
// return is_null($ar) ? NULL : new Ticket($ar);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function getTicketsByuId(int $user_id): \Traversable
|
|
||||||
// {
|
|
||||||
// foreach($this->tickets->where(['user_id' => $user_id, 'deleted' => 0]) as $ticket) yield new Ticket($ticket);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function getRequestById(int $req_id): ?Ticket
|
|
||||||
// {
|
|
||||||
// $requests = $this->tickets->where(['id' => $req_id])->fetch();
|
|
||||||
// if(!is_null($requests))
|
|
||||||
|
|
||||||
// return new Req($requests);
|
|
||||||
// else
|
|
||||||
// return null;
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function get(int $id): ?Ticket
|
|
||||||
// {
|
|
||||||
// return $this->toTicket($this->tickets->get($id));
|
|
||||||
// }
|
|
||||||
|
|
||||||
function get(int $id): ?TicketComment
|
function get(int $id): ?TicketComment
|
||||||
{
|
{
|
||||||
$comment = $this->comments->get($id);;
|
$comment = $this->comments->get($id);;
|
||||||
|
|
|
@ -50,7 +50,7 @@ class Tickets
|
||||||
if(!is_null($requests))
|
if(!is_null($requests))
|
||||||
return new Req($requests);
|
return new Req($requests);
|
||||||
else
|
else
|
||||||
return null;
|
return NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ class Topics
|
||||||
{
|
{
|
||||||
$perPage = $perPage ?? OPENVK_DEFAULT_PER_PAGE;
|
$perPage = $perPage ?? OPENVK_DEFAULT_PER_PAGE;
|
||||||
|
|
||||||
// Get pinned topics first
|
# Get pinned topics first
|
||||||
$query = "SELECT `id` FROM `topics` WHERE `pinned` = 1 AND `group` = ? AND `deleted` = 0 UNION SELECT `id` FROM `topics` WHERE `pinned` = 0 AND `group` = ? AND `deleted` = 0";
|
$query = "SELECT `id` FROM `topics` WHERE `pinned` = 1 AND `group` = ? AND `deleted` = 0 UNION SELECT `id` FROM `topics` WHERE `pinned` = 0 AND `group` = ? AND `deleted` = 0";
|
||||||
$query .= " LIMIT " . $perPage . " OFFSET " . ($page - 1) * $perPage;
|
$query .= " LIMIT " . $perPage . " OFFSET " . ($page - 1) * $perPage;
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ Move-Item $file $temp
|
||||||
|
|
||||||
# video stub logic was implicitly deprecated, so we start processing at once
|
# video stub logic was implicitly deprecated, so we start processing at once
|
||||||
ffmpeg -i $temp -ss 00:00:01.000 -vframes 1 "$dir$hashT/$hash.gif"
|
ffmpeg -i $temp -ss 00:00:01.000 -vframes 1 "$dir$hashT/$hash.gif"
|
||||||
ffmpeg -i $temp -c:v libtheora -q:v 7 -c:a libvorbis -q:a 4 -vf scale=640x360,setsar=1:1 -y $temp2
|
ffmpeg -i $temp -c:v libtheora -q:v 7 -c:a libvorbis -q:a 4 -vf "scale=640:480:force_original_aspect_ratio=decrease,pad=640:480:(ow-iw)/2:(oh-ih)/2,setsar=1" -y $temp2
|
||||||
|
|
||||||
Move-Item $temp2 "$dir$hashT/$hash.ogv"
|
Move-Item $temp2 "$dir$hashT/$hash.ogv"
|
||||||
Remove-Item $temp
|
Remove-Item $temp
|
||||||
|
|
|
@ -5,7 +5,7 @@ cp ../files/video/rendering.apng $3${4:0:2}/$4.gif
|
||||||
cp ../files/video/rendering.ogv $3/${4:0:2}/$4.ogv
|
cp ../files/video/rendering.ogv $3/${4:0:2}/$4.ogv
|
||||||
|
|
||||||
nice ffmpeg -i "/tmp/vid_$tmpfile.bin" -ss 00:00:01.000 -vframes 1 $3${4:0:2}/$4.gif
|
nice ffmpeg -i "/tmp/vid_$tmpfile.bin" -ss 00:00:01.000 -vframes 1 $3${4:0:2}/$4.gif
|
||||||
nice -n 20 ffmpeg -i "/tmp/vid_$tmpfile.bin" -c:v libtheora -q:v 7 -c:a libvorbis -q:a 4 -vf scale=640x360,setsar=1:1 -y "/tmp/ffmOi$tmpfile.ogv"
|
nice -n 20 ffmpeg -i "/tmp/vid_$tmpfile.bin" -c:v libtheora -q:v 7 -c:a libvorbis -q:a 4 -vf "scale=640:480:force_original_aspect_ratio=decrease,pad=640:480:(ow-iw)/2:(oh-ih)/2,setsar=1" -y "/tmp/ffmOi$tmpfile.ogv"
|
||||||
|
|
||||||
rm -rf $3${4:0:2}/$4.ogv
|
rm -rf $3${4:0:2}/$4.ogv
|
||||||
mv "/tmp/ffmOi$tmpfile.ogv" $3${4:0:2}/$4.ogv
|
mv "/tmp/ffmOi$tmpfile.ogv" $3${4:0:2}/$4.ogv
|
||||||
|
|
20
Web/Models/sql/get-correspondencies-count.tsql
Normal file
20
Web/Models/sql/get-correspondencies-count.tsql
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
SELECT COUNT(id) AS cnt FROM
|
||||||
|
(
|
||||||
|
(
|
||||||
|
SELECT
|
||||||
|
recipient_id AS id
|
||||||
|
FROM messages
|
||||||
|
WHERE
|
||||||
|
sender_id = ?
|
||||||
|
AND
|
||||||
|
sender_type = ?
|
||||||
|
) UNION (
|
||||||
|
SELECT
|
||||||
|
sender_id AS id
|
||||||
|
FROM messages
|
||||||
|
WHERE
|
||||||
|
recipient_id = ?
|
||||||
|
AND
|
||||||
|
recipient_type = ?
|
||||||
|
)
|
||||||
|
) dt
|
6
Web/Models/sql/get-online-friends.tsql
Executable file
6
Web/Models/sql/get-online-friends.tsql
Executable file
|
@ -0,0 +1,6 @@
|
||||||
|
(SELECT follower AS __id FROM
|
||||||
|
(SELECT follower FROM subscriptions WHERE target=? AND model="openvk\\Web\\Models\\Entities\\User") u0
|
||||||
|
INNER JOIN
|
||||||
|
(SELECT target FROM subscriptions WHERE follower=? AND model="openvk\\Web\\Models\\Entities\\User") u1
|
||||||
|
ON u0.follower = u1.target) u2
|
||||||
|
INNER JOIN profiles ON profiles.id = u2.__id WHERE online > (UNIX_TIMESTAMP() - 300)
|
|
@ -9,19 +9,19 @@ final class AboutPresenter extends OpenVKPresenter
|
||||||
{
|
{
|
||||||
protected $banTolerant = true;
|
protected $banTolerant = true;
|
||||||
protected $activationTolerant = true;
|
protected $activationTolerant = true;
|
||||||
|
protected $deactivationTolerant = true;
|
||||||
|
|
||||||
function renderIndex(): void
|
function renderIndex(): void
|
||||||
{
|
{
|
||||||
if(!is_null($this->user)) {
|
if(!is_null($this->user)) {
|
||||||
header("HTTP/1.1 302 Found");
|
if($this->user->identity->getMainPage())
|
||||||
header("Location: /id" . $this->user->id);
|
$this->redirect("/feed");
|
||||||
exit;
|
else
|
||||||
|
$this->redirect($this->user->identity->getURL());
|
||||||
}
|
}
|
||||||
|
|
||||||
if($_SERVER['REQUEST_URI'] == "/id0") {
|
if($_SERVER['REQUEST_URI'] == "/id0") {
|
||||||
header("HTTP/1.1 302 Found");
|
$this->redirect("/");
|
||||||
header("Location: /");
|
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->template->stats = (new Users)->getStatistics();
|
$this->template->stats = (new Users)->getStatistics();
|
||||||
|
@ -85,7 +85,7 @@ final class AboutPresenter extends OpenVKPresenter
|
||||||
if(is_null($lg))
|
if(is_null($lg))
|
||||||
$this->throwError(404, "Not found", "Language is not found");
|
$this->throwError(404, "Not found", "Language is not found");
|
||||||
header("Content-Type: application/javascript");
|
header("Content-Type: application/javascript");
|
||||||
echo "window.lang = " . json_encode($localizer->export($lang)) . ";"; // привет хардкод :DDD
|
echo "window.lang = " . json_encode($localizer->export($lang)) . ";"; # привет хардкод :DDD
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,6 +102,15 @@ final class AboutPresenter extends OpenVKPresenter
|
||||||
. "# covered from unauthorized persons (for example, due to\n"
|
. "# covered from unauthorized persons (for example, due to\n"
|
||||||
. "# lack of rights to access the admin panel)\n\n"
|
. "# lack of rights to access the admin panel)\n\n"
|
||||||
. "User-Agent: *\n"
|
. "User-Agent: *\n"
|
||||||
|
. "Disallow: /albums/create\n"
|
||||||
|
. "Disallow: /videos/upload\n"
|
||||||
|
. "Disallow: /invite\n"
|
||||||
|
. "Disallow: /groups_create\n"
|
||||||
|
. "Disallow: /notifications\n"
|
||||||
|
. "Disallow: /settings\n"
|
||||||
|
. "Disallow: /edit\n"
|
||||||
|
. "Disallow: /gifts\n"
|
||||||
|
. "Disallow: /support\n"
|
||||||
. "Disallow: /rpc\n"
|
. "Disallow: /rpc\n"
|
||||||
. "Disallow: /language\n"
|
. "Disallow: /language\n"
|
||||||
. "Disallow: /badbrowser.php\n"
|
. "Disallow: /badbrowser.php\n"
|
||||||
|
@ -120,10 +129,12 @@ final class AboutPresenter extends OpenVKPresenter
|
||||||
|
|
||||||
function renderHumansTxt(): void
|
function renderHumansTxt(): void
|
||||||
{
|
{
|
||||||
// :D
|
# :D
|
||||||
|
$this->redirect("https://github.com/openvk/openvk#readme");
|
||||||
|
}
|
||||||
|
|
||||||
header("HTTP/1.1 302 Found");
|
function renderDev(): void
|
||||||
header("Location: https://github.com/openvk/openvk#readme");
|
{
|
||||||
exit;
|
$this->redirect("https://docs.openvk.su/");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Presenters;
|
namespace openvk\Web\Presenters;
|
||||||
use openvk\Web\Models\Entities\{Voucher, Gift, GiftCategory, User};
|
use openvk\Web\Models\Entities\{Voucher, Gift, GiftCategory, User, BannedLink};
|
||||||
use openvk\Web\Models\Repositories\{Users, Clubs, Vouchers, Gifts};
|
use openvk\Web\Models\Repositories\{Users, Clubs, Vouchers, Gifts, BannedLinks};
|
||||||
|
use Chandler\Database\DatabaseConnection;
|
||||||
|
|
||||||
final class AdminPresenter extends OpenVKPresenter
|
final class AdminPresenter extends OpenVKPresenter
|
||||||
{
|
{
|
||||||
|
@ -9,13 +10,15 @@ final class AdminPresenter extends OpenVKPresenter
|
||||||
private $clubs;
|
private $clubs;
|
||||||
private $vouchers;
|
private $vouchers;
|
||||||
private $gifts;
|
private $gifts;
|
||||||
|
private $bannedLinks;
|
||||||
|
|
||||||
function __construct(Users $users, Clubs $clubs, Vouchers $vouchers, Gifts $gifts)
|
function __construct(Users $users, Clubs $clubs, Vouchers $vouchers, Gifts $gifts, BannedLinks $bannedLinks)
|
||||||
{
|
{
|
||||||
$this->users = $users;
|
$this->users = $users;
|
||||||
$this->clubs = $clubs;
|
$this->clubs = $clubs;
|
||||||
$this->vouchers = $vouchers;
|
$this->vouchers = $vouchers;
|
||||||
$this->gifts = $gifts;
|
$this->gifts = $gifts;
|
||||||
|
$this->bannedLinks = $bannedLinks;
|
||||||
|
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
|
@ -23,7 +26,7 @@ final class AdminPresenter extends OpenVKPresenter
|
||||||
private function warnIfNoCommerce(): void
|
private function warnIfNoCommerce(): void
|
||||||
{
|
{
|
||||||
if(!OPENVK_ROOT_CONF["openvk"]["preferences"]["commerce"])
|
if(!OPENVK_ROOT_CONF["openvk"]["preferences"]["commerce"])
|
||||||
$this->flash("warn", "Коммерция отключена системным администратором", "Настройки ваучеров и подарков будут сохранены, но не будут оказывать никакого влияния.");
|
$this->flash("warn", tr("admin_commerce_disabled"), tr("admin_commerce_disabled_desc"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function searchResults(object $repo, &$count)
|
private function searchResults(object $repo, &$count)
|
||||||
|
@ -70,14 +73,14 @@ final class AdminPresenter extends OpenVKPresenter
|
||||||
$user->setLast_Name($this->postParam("last_name"));
|
$user->setLast_Name($this->postParam("last_name"));
|
||||||
$user->setPseudo($this->postParam("nickname"));
|
$user->setPseudo($this->postParam("nickname"));
|
||||||
$user->setStatus($this->postParam("status"));
|
$user->setStatus($this->postParam("status"));
|
||||||
$user->setVerified(empty($this->postParam("verify") ? 0 : 1));
|
|
||||||
if($user->onlineStatus() != $this->postParam("online")) $user->setOnline(intval($this->postParam("online")));
|
|
||||||
if(!$user->setShortCode(empty($this->postParam("shortcode")) ? NULL : $this->postParam("shortcode")))
|
if(!$user->setShortCode(empty($this->postParam("shortcode")) ? NULL : $this->postParam("shortcode")))
|
||||||
$this->flash("err", tr("error"), tr("error_shorturl_incorrect"));
|
$this->flash("err", tr("error"), tr("error_shorturl_incorrect"));
|
||||||
|
$user->changeEmail($this->postParam("email"));
|
||||||
|
if($user->onlineStatus() != $this->postParam("online")) $user->setOnline(intval($this->postParam("online")));
|
||||||
|
$user->setVerified(empty($this->postParam("verify") ? 0 : 1));
|
||||||
|
|
||||||
$user->save();
|
$user->save();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,8 +173,7 @@ final class AdminPresenter extends OpenVKPresenter
|
||||||
|
|
||||||
$voucher->save();
|
$voucher->save();
|
||||||
|
|
||||||
$this->redirect("/admin/vouchers/id" . $voucher->getId(), static::REDIRECT_TEMPORARY);
|
$this->redirect("/admin/vouchers/id" . $voucher->getId());
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderGiftCategories(): void
|
function renderGiftCategories(): void
|
||||||
|
@ -193,7 +195,7 @@ final class AdminPresenter extends OpenVKPresenter
|
||||||
if(!$cat)
|
if(!$cat)
|
||||||
$this->notFound();
|
$this->notFound();
|
||||||
else if($cat->getSlug() !== $slug)
|
else if($cat->getSlug() !== $slug)
|
||||||
$this->redirect("/admin/gifts/" . $cat->getSlug() . "." . $id . ".meta", static::REDIRECT_TEMPORARY);
|
$this->redirect("/admin/gifts/" . $cat->getSlug() . "." . $id . ".meta");
|
||||||
} else {
|
} else {
|
||||||
$gen = true;
|
$gen = true;
|
||||||
$cat = new GiftCategory;
|
$cat = new GiftCategory;
|
||||||
|
@ -234,7 +236,7 @@ final class AdminPresenter extends OpenVKPresenter
|
||||||
$cat->setDescription($code, $this->postParam("description_$code"));
|
$cat->setDescription($code, $this->postParam("description_$code"));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->redirect("/admin/gifts/" . $cat->getSlug() . "." . $cat->getId() . ".meta", static::REDIRECT_TEMPORARY);
|
$this->redirect("/admin/gifts/" . $cat->getSlug() . "." . $cat->getId() . ".meta");
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderGifts(string $catSlug, int $catId): void
|
function renderGifts(string $catSlug, int $catId): void
|
||||||
|
@ -245,7 +247,7 @@ final class AdminPresenter extends OpenVKPresenter
|
||||||
if(!$cat)
|
if(!$cat)
|
||||||
$this->notFound();
|
$this->notFound();
|
||||||
else if($cat->getSlug() !== $catSlug)
|
else if($cat->getSlug() !== $catSlug)
|
||||||
$this->redirect("/admin/gifts/" . $cat->getSlug() . "." . $catId . "/", static::REDIRECT_TEMPORARY);
|
$this->redirect("/admin/gifts/" . $cat->getSlug() . "." . $catId . "/");
|
||||||
|
|
||||||
$this->template->cat = $cat;
|
$this->template->cat = $cat;
|
||||||
$this->template->gifts = iterator_to_array($cat->getGifts((int) ($this->queryParam("p") ?? 1), NULL, $this->template->count));
|
$this->template->gifts = iterator_to_array($cat->getGifts((int) ($this->queryParam("p") ?? 1), NULL, $this->template->count));
|
||||||
|
@ -284,7 +286,7 @@ final class AdminPresenter extends OpenVKPresenter
|
||||||
|
|
||||||
$name = $catTo->getName();
|
$name = $catTo->getName();
|
||||||
$this->flash("succ", "Gift moved successfully", "This gift will now be in <b>$name</b>.");
|
$this->flash("succ", "Gift moved successfully", "This gift will now be in <b>$name</b>.");
|
||||||
$this->redirect("/admin/gifts/" . $catTo->getSlug() . "." . $catTo->getId() . "/", static::REDIRECT_TEMPORARY);
|
$this->redirect("/admin/gifts/" . $catTo->getSlug() . "." . $catTo->getId() . "/");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
case "edit":
|
case "edit":
|
||||||
|
@ -328,7 +330,7 @@ final class AdminPresenter extends OpenVKPresenter
|
||||||
$cat->addGift($gift);
|
$cat->addGift($gift);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->redirect("/admin/gifts/id" . $gift->getId(), static::REDIRECT_TEMPORARY);
|
$this->redirect("/admin/gifts/id" . $gift->getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,11 +343,13 @@ final class AdminPresenter extends OpenVKPresenter
|
||||||
{
|
{
|
||||||
$this->assertNoCSRF();
|
$this->assertNoCSRF();
|
||||||
|
|
||||||
|
$unban_time = strtotime($this->queryParam("date")) ?: NULL;
|
||||||
|
|
||||||
$user = $this->users->get($id);
|
$user = $this->users->get($id);
|
||||||
if(!$user)
|
if(!$user)
|
||||||
exit(json_encode([ "error" => "User does not exist" ]));
|
exit(json_encode([ "error" => "User does not exist" ]));
|
||||||
|
|
||||||
$user->ban($this->queryParam("reason"));
|
$user->ban($this->queryParam("reason"), true, $unban_time);
|
||||||
exit(json_encode([ "success" => true, "reason" => $this->queryParam("reason") ]));
|
exit(json_encode([ "success" => true, "reason" => $this->queryParam("reason") ]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,7 +361,8 @@ final class AdminPresenter extends OpenVKPresenter
|
||||||
if(!$user)
|
if(!$user)
|
||||||
exit(json_encode([ "error" => "User does not exist" ]));
|
exit(json_encode([ "error" => "User does not exist" ]));
|
||||||
|
|
||||||
$user->setBlock_Reason(null);
|
$user->setBlock_Reason(NULL);
|
||||||
|
$user->setUnblock_time(NULL);
|
||||||
$user->save();
|
$user->save();
|
||||||
exit(json_encode([ "success" => true ]));
|
exit(json_encode([ "success" => true ]));
|
||||||
}
|
}
|
||||||
|
@ -373,4 +378,73 @@ final class AdminPresenter extends OpenVKPresenter
|
||||||
$user->adminNotify("⚠️ " . $this->queryParam("message"));
|
$user->adminNotify("⚠️ " . $this->queryParam("message"));
|
||||||
exit(json_encode([ "message" => $this->queryParam("message") ]));
|
exit(json_encode([ "message" => $this->queryParam("message") ]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderBannedLinks(): void
|
||||||
|
{
|
||||||
|
$this->template->links = $this->bannedLinks->getList((int) $this->queryParam("p") ?: 1);
|
||||||
|
$this->template->users = new Users;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderBannedLink(int $id): void
|
||||||
|
{
|
||||||
|
$this->template->form = (object) [];
|
||||||
|
|
||||||
|
if($id === 0) {
|
||||||
|
$this->template->form->id = 0;
|
||||||
|
$this->template->form->link = NULL;
|
||||||
|
$this->template->form->reason = NULL;
|
||||||
|
} else {
|
||||||
|
$link = (new BannedLinks)->get($id);
|
||||||
|
if(!$link)
|
||||||
|
$this->notFound();
|
||||||
|
|
||||||
|
$this->template->form->id = $link->getId();
|
||||||
|
$this->template->form->link = $link->getDomain();
|
||||||
|
$this->template->form->reason = $link->getReason();
|
||||||
|
$this->template->form->regexp = $link->getRawRegexp();
|
||||||
|
}
|
||||||
|
|
||||||
|
if($_SERVER["REQUEST_METHOD"] !== "POST")
|
||||||
|
return;
|
||||||
|
|
||||||
|
$link = (new BannedLinks)->get($id);
|
||||||
|
|
||||||
|
$new_domain = parse_url($this->postParam("link"))["host"];
|
||||||
|
$new_reason = $this->postParam("reason") ?: NULL;
|
||||||
|
|
||||||
|
$lid = $id;
|
||||||
|
|
||||||
|
if ($link) {
|
||||||
|
$link->setDomain($new_domain ?? $this->postParam("link"));
|
||||||
|
$link->setReason($new_reason);
|
||||||
|
$link->setRegexp_rule($this->postParam("regexp"));
|
||||||
|
$link->save();
|
||||||
|
} else {
|
||||||
|
if (!$new_domain)
|
||||||
|
$this->flashFail("err", tr("error"), tr("admin_banned_link_not_specified"));
|
||||||
|
|
||||||
|
$link = new BannedLink;
|
||||||
|
$link->setDomain($new_domain);
|
||||||
|
$link->setReason($new_reason);
|
||||||
|
$link->setRegexp_rule($this->postParam("regexp"));
|
||||||
|
$link->setInitiator($this->user->identity->getId());
|
||||||
|
$link->save();
|
||||||
|
|
||||||
|
$lid = $link->getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->redirect("/admin/bannedLink/id" . $lid);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderUnbanLink(int $id): void
|
||||||
|
{
|
||||||
|
$link = (new BannedLinks)->get($id);
|
||||||
|
|
||||||
|
if (!$link)
|
||||||
|
$this->flashFail("err", tr("error"), tr("admin_banned_link_not_found"));
|
||||||
|
|
||||||
|
$link->delete(false);
|
||||||
|
|
||||||
|
$this->redirect("/admin/bannedLinks");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
138
Web/Presenters/AppsPresenter.php
Normal file
138
Web/Presenters/AppsPresenter.php
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Presenters;
|
||||||
|
use openvk\Web\Models\Entities\Application;
|
||||||
|
use openvk\Web\Models\Repositories\Applications;
|
||||||
|
|
||||||
|
final class AppsPresenter extends OpenVKPresenter
|
||||||
|
{
|
||||||
|
private $apps;
|
||||||
|
|
||||||
|
function __construct(Applications $apps)
|
||||||
|
{
|
||||||
|
$this->apps = $apps;
|
||||||
|
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPlay(int $app): void
|
||||||
|
{
|
||||||
|
$this->assertUserLoggedIn();
|
||||||
|
|
||||||
|
$app = $this->apps->get($app);
|
||||||
|
if(!$app || !$app->isEnabled())
|
||||||
|
$this->notFound();
|
||||||
|
|
||||||
|
$this->template->id = $app->getId();
|
||||||
|
$this->template->name = $app->getName();
|
||||||
|
$this->template->desc = $app->getDescription();
|
||||||
|
$this->template->origin = $app->getOrigin();
|
||||||
|
$this->template->url = $app->getURL();
|
||||||
|
$this->template->owner = $app->getOwner();
|
||||||
|
$this->template->news = $app->getNote();
|
||||||
|
$this->template->perms = $app->getPermissions($this->user->identity);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderUnInstall(): void
|
||||||
|
{
|
||||||
|
$this->assertUserLoggedIn();
|
||||||
|
$this->assertNoCSRF();
|
||||||
|
|
||||||
|
$app = $this->apps->get((int) $this->queryParam("app"));
|
||||||
|
if(!$app)
|
||||||
|
$this->flashFail("err", tr("app_err_not_found"), tr("app_err_not_found_desc"));
|
||||||
|
|
||||||
|
$app->uninstall($this->user->identity);
|
||||||
|
$this->flashFail("succ", tr("app_uninstalled"), tr("app_uninstalled_desc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderEdit(): void
|
||||||
|
{
|
||||||
|
$this->assertUserLoggedIn();
|
||||||
|
|
||||||
|
$app = NULL;
|
||||||
|
if($this->queryParam("act") !== "create") {
|
||||||
|
if(empty($this->queryParam("app")))
|
||||||
|
$this->flashFail("err", tr("app_err_not_found"), tr("app_err_not_found_desc"));
|
||||||
|
|
||||||
|
$app = $this->apps->get((int) $this->queryParam("app"));
|
||||||
|
if(!$app)
|
||||||
|
$this->flashFail("err", tr("app_err_not_found"), tr("app_err_not_found_desc"));
|
||||||
|
|
||||||
|
if($app->getOwner()->getId() != $this->user->identity->getId())
|
||||||
|
$this->flashFail("err", tr("forbidden"), tr("app_err_forbidden_desc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||||
|
if(!$app) {
|
||||||
|
$app = new Application;
|
||||||
|
$app->setOwner($this->user->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!filter_var($this->postParam("url"), FILTER_VALIDATE_URL))
|
||||||
|
$this->flashFail("err", tr("app_err_url"), tr("app_err_url_desc"));
|
||||||
|
|
||||||
|
if(isset($_FILES["ava"]) && $_FILES["ava"]["size"] > 0) {
|
||||||
|
if(($res = $app->setAvatar($_FILES["ava"])) !== 0)
|
||||||
|
$this->flashFail("err", tr("app_err_ava"), tr("app_err_ava_desc", $res));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(empty($this->postParam("note"))) {
|
||||||
|
$app->setNoteLink(NULL);
|
||||||
|
} else {
|
||||||
|
if(!$app->setNoteLink($this->postParam("note")))
|
||||||
|
$this->flashFail("err", tr("app_err_note"), tr("app_err_note_desc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$app->setName($this->postParam("name"));
|
||||||
|
$app->setDescription($this->postParam("desc"));
|
||||||
|
$app->setAddress($this->postParam("url"));
|
||||||
|
if($this->postParam("enable") === "on")
|
||||||
|
$app->enable();
|
||||||
|
else
|
||||||
|
$app->disable(); # no need to save since enable/disable will call save() internally
|
||||||
|
|
||||||
|
$this->redirect("/editapp?act=edit&app=" . $app->getId()); # will exit here
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!is_null($app)) {
|
||||||
|
$this->template->create = false;
|
||||||
|
$this->template->id = $app->getId();
|
||||||
|
$this->template->name = $app->getName();
|
||||||
|
$this->template->desc = $app->getDescription();
|
||||||
|
$this->template->coins = $app->getBalance();
|
||||||
|
$this->template->origin = $app->getOrigin();
|
||||||
|
$this->template->url = $app->getURL();
|
||||||
|
$this->template->note = $app->getNoteLink();
|
||||||
|
$this->template->users = $app->getUsersCount();
|
||||||
|
$this->template->on = $app->isEnabled();
|
||||||
|
} else {
|
||||||
|
$this->template->create = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderList(): void
|
||||||
|
{
|
||||||
|
$this->assertUserLoggedIn();
|
||||||
|
|
||||||
|
$act = $this->queryParam("act");
|
||||||
|
if(!in_array($act, ["list", "installed", "dev"]))
|
||||||
|
$act = "installed";
|
||||||
|
|
||||||
|
$page = (int) ($this->queryParam("p") ?? 1);
|
||||||
|
if($act == "list") {
|
||||||
|
$apps = $this->apps->getList($page);
|
||||||
|
$count = $this->apps->getListCount();
|
||||||
|
} else if($act == "installed") {
|
||||||
|
$apps = $this->apps->getInstalled($this->user->identity, $page);
|
||||||
|
$count = $this->apps->getInstalledCount($this->user->identity);
|
||||||
|
} else if($act == "dev") {
|
||||||
|
$apps = $this->apps->getByOwner($this->user->identity, $page);
|
||||||
|
$count = $this->apps->getOwnCount($this->user->identity);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->template->act = $act;
|
||||||
|
$this->template->iterator = $apps;
|
||||||
|
$this->template->count = $count;
|
||||||
|
$this->template->page = $page;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,14 +1,8 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Presenters;
|
namespace openvk\Web\Presenters;
|
||||||
use openvk\Web\Models\Entities\IP;
|
use openvk\Web\Models\Entities\{IP, User, PasswordReset, EmailVerification};
|
||||||
use openvk\Web\Models\Entities\User;
|
use openvk\Web\Models\Repositories\{IPs, Users, Restores, Verifications};
|
||||||
use openvk\Web\Models\Entities\PasswordReset;
|
|
||||||
use openvk\Web\Models\Entities\EmailVerification;
|
|
||||||
use openvk\Web\Models\Exceptions\InvalidUserNameException;
|
use openvk\Web\Models\Exceptions\InvalidUserNameException;
|
||||||
use openvk\Web\Models\Repositories\IPs;
|
|
||||||
use openvk\Web\Models\Repositories\Users;
|
|
||||||
use openvk\Web\Models\Repositories\Restores;
|
|
||||||
use openvk\Web\Models\Repositories\Verifications;
|
|
||||||
use openvk\Web\Util\Validator;
|
use openvk\Web\Util\Validator;
|
||||||
use Chandler\Session\Session;
|
use Chandler\Session\Session;
|
||||||
use Chandler\Security\User as ChandlerUser;
|
use Chandler\Security\User as ChandlerUser;
|
||||||
|
@ -20,6 +14,7 @@ final class AuthPresenter extends OpenVKPresenter
|
||||||
{
|
{
|
||||||
protected $banTolerant = true;
|
protected $banTolerant = true;
|
||||||
protected $activationTolerant = true;
|
protected $activationTolerant = true;
|
||||||
|
protected $deactivationTolerant = true;
|
||||||
|
|
||||||
private $authenticator;
|
private $authenticator;
|
||||||
private $db;
|
private $db;
|
||||||
|
@ -50,7 +45,7 @@ final class AuthPresenter extends OpenVKPresenter
|
||||||
function renderRegister(): void
|
function renderRegister(): void
|
||||||
{
|
{
|
||||||
if(!is_null($this->user))
|
if(!is_null($this->user))
|
||||||
$this->redirect("/id" . $this->user->id, static::REDIRECT_TEMPORARY);
|
$this->redirect($this->user->identity->getURL());
|
||||||
|
|
||||||
if(!$this->hasPermission("user", "register", -1)) exit("Вас забанили");
|
if(!$this->hasPermission("user", "register", -1)) exit("Вас забанили");
|
||||||
|
|
||||||
|
@ -89,6 +84,9 @@ final class AuthPresenter extends OpenVKPresenter
|
||||||
if (strtotime($this->postParam("birthday")) > time())
|
if (strtotime($this->postParam("birthday")) > time())
|
||||||
$this->flashFail("err", tr("invalid_birth_date"), tr("invalid_birth_date_comment"));
|
$this->flashFail("err", tr("invalid_birth_date"), tr("invalid_birth_date_comment"));
|
||||||
|
|
||||||
|
if (!$this->postParam("confirmation"))
|
||||||
|
$this->flashFail("err", tr("error"), tr("checkbox_in_registration_unchecked"));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$user = new User;
|
$user = new User;
|
||||||
$user->setFirst_Name($this->postParam("first_name"));
|
$user->setFirst_Name($this->postParam("first_name"));
|
||||||
|
@ -97,7 +95,7 @@ final class AuthPresenter extends OpenVKPresenter
|
||||||
$user->setEmail($this->postParam("email"));
|
$user->setEmail($this->postParam("email"));
|
||||||
$user->setSince(date("Y-m-d H:i:s"));
|
$user->setSince(date("Y-m-d H:i:s"));
|
||||||
$user->setRegistering_Ip(CONNECTING_IP);
|
$user->setRegistering_Ip(CONNECTING_IP);
|
||||||
$user->setBirthday(strtotime($this->postParam("birthday")));
|
$user->setBirthday(empty($this->postParam("birthday")) ? NULL : strtotime($this->postParam("birthday")));
|
||||||
$user->setActivated((int)!OPENVK_ROOT_CONF['openvk']['preferences']['security']['requireEmail']);
|
$user->setActivated((int)!OPENVK_ROOT_CONF['openvk']['preferences']['security']['requireEmail']);
|
||||||
} catch(InvalidUserNameException $ex) {
|
} catch(InvalidUserNameException $ex) {
|
||||||
$this->flashFail("err", tr("error"), tr("invalid_real_name"));
|
$this->flashFail("err", tr("error"), tr("invalid_real_name"));
|
||||||
|
@ -128,7 +126,7 @@ final class AuthPresenter extends OpenVKPresenter
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->authenticator->authenticate($chUser->getId());
|
$this->authenticator->authenticate($chUser->getId());
|
||||||
$this->redirect("/id" . $user->getId(), static::REDIRECT_TEMPORARY);
|
$this->redirect("/id" . $user->getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,12 +135,11 @@ final class AuthPresenter extends OpenVKPresenter
|
||||||
$redirUrl = $this->requestParam("jReturnTo");
|
$redirUrl = $this->requestParam("jReturnTo");
|
||||||
|
|
||||||
if(!is_null($this->user))
|
if(!is_null($this->user))
|
||||||
$this->redirect($redirUrl ?? "/id" . $this->user->id, static::REDIRECT_TEMPORARY);
|
$this->redirect($redirUrl ?? $this->user->identity->getURL());
|
||||||
|
|
||||||
if(!$this->hasPermission("user", "login", -1)) exit("Вас забанили");
|
if(!$this->hasPermission("user", "login", -1)) exit("Вас забанили");
|
||||||
|
|
||||||
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||||
|
|
||||||
$user = $this->db->table("ChandlerUsers")->where("login", $this->postParam("login"))->fetch();
|
$user = $this->db->table("ChandlerUsers")->where("login", $this->postParam("login"))->fetch();
|
||||||
if(!$user)
|
if(!$user)
|
||||||
$this->flashFail("err", tr("login_failed"), tr("invalid_username_or_password"));
|
$this->flashFail("err", tr("login_failed"), tr("invalid_username_or_password"));
|
||||||
|
@ -151,7 +148,7 @@ final class AuthPresenter extends OpenVKPresenter
|
||||||
$this->flashFail("err", tr("login_failed"), tr("invalid_username_or_password"));
|
$this->flashFail("err", tr("login_failed"), tr("invalid_username_or_password"));
|
||||||
|
|
||||||
$ovkUser = new User($user->related("profiles.user")->fetch());
|
$ovkUser = new User($user->related("profiles.user")->fetch());
|
||||||
if($ovkUser->isDeleted())
|
if($ovkUser->isDeleted() && !$ovkUser->isDeactivated())
|
||||||
$this->flashFail("err", tr("login_failed"), tr("invalid_username_or_password"));
|
$this->flashFail("err", tr("login_failed"), tr("invalid_username_or_password"));
|
||||||
|
|
||||||
$secret = $user->related("profiles.user")->fetch()["2fa_secret"];
|
$secret = $user->related("profiles.user")->fetch()["2fa_secret"];
|
||||||
|
@ -171,8 +168,7 @@ final class AuthPresenter extends OpenVKPresenter
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->authenticator->authenticate($user->id);
|
$this->authenticator->authenticate($user->id);
|
||||||
$this->redirect($redirUrl ?? "/id" . $user->related("profiles.user")->fetch()->id, static::REDIRECT_TEMPORARY);
|
$this->redirect($redirUrl ?? $ovkUser->getURL());
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +179,7 @@ final class AuthPresenter extends OpenVKPresenter
|
||||||
|
|
||||||
if($uuid === "unset") {
|
if($uuid === "unset") {
|
||||||
Session::i()->set("_su", NULL);
|
Session::i()->set("_su", NULL);
|
||||||
$this->redirect("/", static::REDIRECT_TEMPORARY);
|
$this->redirect("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!$this->db->table("ChandlerUsers")->where("id", $uuid))
|
if(!$this->db->table("ChandlerUsers")->where("id", $uuid))
|
||||||
|
@ -192,8 +188,7 @@ final class AuthPresenter extends OpenVKPresenter
|
||||||
$this->assertPermission('openvk\Web\Models\Entities\User', 'substitute', 0);
|
$this->assertPermission('openvk\Web\Models\Entities\User', 'substitute', 0);
|
||||||
Session::i()->set("_su", $uuid);
|
Session::i()->set("_su", $uuid);
|
||||||
$this->flash("succ", tr("profile_changed"), tr("profile_changed_comment"));
|
$this->flash("succ", tr("profile_changed"), tr("profile_changed_comment"));
|
||||||
$this->redirect("/", static::REDIRECT_TEMPORARY);
|
$this->redirect("/");
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderLogout(): void
|
function renderLogout(): void
|
||||||
|
@ -203,7 +198,7 @@ final class AuthPresenter extends OpenVKPresenter
|
||||||
$this->authenticator->logout();
|
$this->authenticator->logout();
|
||||||
Session::i()->set("_su", NULL);
|
Session::i()->set("_su", NULL);
|
||||||
|
|
||||||
$this->redirect("/", static::REDIRECT_TEMPORARY_PRESISTENT);
|
$this->redirect("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderFinishRestoringPassword(): void
|
function renderFinishRestoringPassword(): void
|
||||||
|
@ -243,7 +238,7 @@ final class AuthPresenter extends OpenVKPresenter
|
||||||
function renderRestore(): void
|
function renderRestore(): void
|
||||||
{
|
{
|
||||||
if(!is_null($this->user))
|
if(!is_null($this->user))
|
||||||
$this->redirect("/id" . $this->user->id, static::REDIRECT_TEMPORARY);
|
$this->redirect($this->user->identity->getURL());
|
||||||
|
|
||||||
if(($this->queryParam("act") ?? "default") === "finish")
|
if(($this->queryParam("act") ?? "default") === "finish")
|
||||||
$this->pass("openvk!Auth->finishRestoringPassword");
|
$this->pass("openvk!Auth->finishRestoringPassword");
|
||||||
|
@ -273,7 +268,6 @@ final class AuthPresenter extends OpenVKPresenter
|
||||||
];
|
];
|
||||||
$this->sendmail($uRow->login, "password-reset", $params); #Vulnerability possible
|
$this->sendmail($uRow->login, "password-reset", $params); #Vulnerability possible
|
||||||
|
|
||||||
|
|
||||||
$this->flashFail("succ", tr("information_-1"), tr("password_reset_email_sent"));
|
$this->flashFail("succ", tr("information_-1"), tr("password_reset_email_sent"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -281,7 +275,7 @@ final class AuthPresenter extends OpenVKPresenter
|
||||||
function renderResendEmail(): void
|
function renderResendEmail(): void
|
||||||
{
|
{
|
||||||
if(!is_null($this->user) && $this->user->identity->isActivated())
|
if(!is_null($this->user) && $this->user->identity->isActivated())
|
||||||
$this->redirect("/id" . $this->user->id, static::REDIRECT_TEMPORARY);
|
$this->redirect($this->user->identity->getURL());
|
||||||
|
|
||||||
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||||
$user = $this->user->identity;
|
$user = $this->user->identity;
|
||||||
|
@ -321,4 +315,49 @@ final class AuthPresenter extends OpenVKPresenter
|
||||||
$this->redirect("/");
|
$this->redirect("/");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderReactivatePage(): void
|
||||||
|
{
|
||||||
|
$this->assertUserLoggedIn();
|
||||||
|
$this->willExecuteWriteAction();
|
||||||
|
|
||||||
|
$this->user->identity->reactivate();
|
||||||
|
|
||||||
|
$this->redirect("/");
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderUnbanThemself(): void
|
||||||
|
{
|
||||||
|
$this->assertUserLoggedIn();
|
||||||
|
$this->willExecuteWriteAction();
|
||||||
|
|
||||||
|
if(!$this->user->identity->canUnbanThemself())
|
||||||
|
$this->flashFail("err", tr("error"), tr("forbidden"));
|
||||||
|
|
||||||
|
$user = $this->users->get($this->user->id);
|
||||||
|
|
||||||
|
$user->setBlock_Reason(NULL);
|
||||||
|
$user->setUnblock_Time(NULL);
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
$this->flashFail("succ", tr("banned_unban_title"), tr("banned_unban_description"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function will revoke all tokens, including API and Web tokens and except active one
|
||||||
|
*
|
||||||
|
* OF COURSE it requires CSRF
|
||||||
|
*/
|
||||||
|
function renderRevokeAllTokens(): void
|
||||||
|
{
|
||||||
|
$this->assertUserLoggedIn();
|
||||||
|
$this->willExecuteWriteAction();
|
||||||
|
$this->assertNoCSRF();
|
||||||
|
|
||||||
|
// API tokens
|
||||||
|
$this->db->table("api_tokens")->where("user", $this->user->identity->getId())->delete();
|
||||||
|
// Web tokens
|
||||||
|
$this->db->table("ChandlerTokens")->where("user", $this->user->identity->getChandlerGUID())->where("token != ?", Session::i()->get("tok"))->delete();
|
||||||
|
$this->flashFail("succ", tr("information_-1"), tr("end_all_sessions_done"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,29 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Presenters;
|
namespace openvk\Web\Presenters;
|
||||||
|
use openvk\Web\Models\Repositories\BannedLinks;
|
||||||
|
use openvk\Web\Models\Entities\BannedLink;
|
||||||
|
|
||||||
final class AwayPresenter extends OpenVKPresenter
|
final class AwayPresenter extends OpenVKPresenter
|
||||||
{
|
{
|
||||||
function renderAway(): void
|
function renderAway(): void
|
||||||
{
|
{
|
||||||
|
$checkBanEntries = (new BannedLinks)->check($this->queryParam("to") . "/");
|
||||||
|
if (OPENVK_ROOT_CONF["openvk"]["preferences"]["susLinks"]["warnings"])
|
||||||
|
if (sizeof($checkBanEntries) > 0)
|
||||||
|
$this->pass("openvk!Away->view", $checkBanEntries[0]);
|
||||||
|
|
||||||
header("HTTP/1.0 302 Found");
|
header("HTTP/1.0 302 Found");
|
||||||
header("X-Robots-Tag: noindex, nofollow, noarchive");
|
header("X-Robots-Tag: noindex, nofollow, noarchive");
|
||||||
header("Location: " . $this->queryParam("to"));
|
header("Location: " . $this->queryParam("to"));
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderView(int $lid) {
|
||||||
|
$this->template->link = (new BannedLinks)->get($lid);
|
||||||
|
|
||||||
|
if (!$this->template->link)
|
||||||
|
$this->notFound();
|
||||||
|
|
||||||
|
$this->template->to = $this->queryParam("to");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
13
Web/Presenters/BannedLinkPresenter.php
Normal file
13
Web/Presenters/BannedLinkPresenter.php
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Presenters;
|
||||||
|
|
||||||
|
use openvk\Web\Models\Entities\BannedLink;
|
||||||
|
use openvk\Web\Models\Repositories\BannedLinks;
|
||||||
|
|
||||||
|
final class BannedLinkPresenter extends OpenVKPresenter
|
||||||
|
{
|
||||||
|
function renderView(int $lid) {
|
||||||
|
$this->template->link = (new BannedLinks)->get($lid);
|
||||||
|
$this->template->to = $this->queryParam("to");
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,20 +19,23 @@ final class BlobPresenter extends OpenVKPresenter
|
||||||
header("Access-Control-Allow-Origin: *");
|
header("Access-Control-Allow-Origin: *");
|
||||||
|
|
||||||
$dir = $this->getDirName($dir);
|
$dir = $this->getDirName($dir);
|
||||||
$name = preg_replace("%[^a-zA-Z0-9_\-]++%", "", $name);
|
$base = realpath(OPENVK_ROOT . "/storage/$dir");
|
||||||
$path = OPENVK_ROOT . "/storage/$dir/$name.$format";
|
$path = realpath(OPENVK_ROOT . "/storage/$dir/$name.$format");
|
||||||
if(!file_exists($path)) {
|
if(!$path) # Will also check if file exists since realpath fails on ENOENT
|
||||||
$this->notFound();
|
$this->notFound();
|
||||||
} else {
|
else if(strpos($path, $path) !== 0) # Prevent directory traversal and storage container escape
|
||||||
|
$this->notFound();
|
||||||
|
|
||||||
if(isset($_SERVER["HTTP_IF_NONE_MATCH"]))
|
if(isset($_SERVER["HTTP_IF_NONE_MATCH"]))
|
||||||
exit(header("HTTP/1.1 304 Not Modified"));
|
exit(header("HTTP/1.1 304 Not Modified"));
|
||||||
|
|
||||||
header("Content-Type: " . mime_content_type($path));
|
header("Content-Type: " . mime_content_type($path));
|
||||||
header("Content-Size: " . filesize($path));
|
header("Content-Size: " . filesize($path));
|
||||||
|
header("Cache-Control: public, max-age=1210000");
|
||||||
|
header("X-Accel-Expires: 1210000");
|
||||||
header("ETag: W/\"" . hash_file("snefru", $path) . "\"");
|
header("ETag: W/\"" . hash_file("snefru", $path) . "\"");
|
||||||
|
|
||||||
readfile($path);
|
readfile($path);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ final class CommentPresenter extends OpenVKPresenter
|
||||||
|
|
||||||
if(!is_null($this->user)) $comment->toggleLike($this->user->identity);
|
if(!is_null($this->user)) $comment->toggleLike($this->user->identity);
|
||||||
|
|
||||||
$this->redirect($_SERVER["HTTP_REFERER"], static::REDIRECT_TEMPORARY);
|
$this->redirect($_SERVER["HTTP_REFERER"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderMakeComment(string $repo, int $eId): void
|
function renderMakeComment(string $repo, int $eId): void
|
||||||
|
@ -60,7 +60,7 @@ final class CommentPresenter extends OpenVKPresenter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO move to trait
|
# TODO move to trait
|
||||||
try {
|
try {
|
||||||
$photo = NULL;
|
$photo = NULL;
|
||||||
$video = NULL;
|
$video = NULL;
|
||||||
|
|
|
@ -91,7 +91,7 @@ final class GiftsPresenter extends OpenVKPresenter
|
||||||
$gift->used();
|
$gift->used();
|
||||||
|
|
||||||
$this->flash("succ", "Подарок отправлен", "Вы отправили подарок <b>" . $user->getFirstName() . "</b> за " . $gift->getPrice() . " голосов.");
|
$this->flash("succ", "Подарок отправлен", "Вы отправили подарок <b>" . $user->getFirstName() . "</b> за " . $gift->getPrice() . " голосов.");
|
||||||
$this->redirect($user->getURL(), static::REDIRECT_TEMPORARY);
|
$this->redirect($user->getURL());
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderStub(): void
|
function renderStub(): void
|
||||||
|
|
|
@ -22,15 +22,12 @@ final class GroupPresenter extends OpenVKPresenter
|
||||||
if(!$club) {
|
if(!$club) {
|
||||||
$this->notFound();
|
$this->notFound();
|
||||||
} else {
|
} else {
|
||||||
if($club->getShortCode())
|
|
||||||
if(parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH) !== "/" . $club->getShortCode())
|
|
||||||
$this->redirect("/" . $club->getShortCode(), static::REDIRECT_TEMPORARY_PRESISTENT);
|
|
||||||
|
|
||||||
$this->template->club = $club;
|
|
||||||
$this->template->albums = (new Albums)->getClubAlbums($club, 1, 3);
|
$this->template->albums = (new Albums)->getClubAlbums($club, 1, 3);
|
||||||
$this->template->albumsCount = (new Albums)->getClubAlbumsCount($club);
|
$this->template->albumsCount = (new Albums)->getClubAlbumsCount($club);
|
||||||
$this->template->topics = (new Topics)->getLastTopics($club, 3);
|
$this->template->topics = (new Topics)->getLastTopics($club, 3);
|
||||||
$this->template->topicsCount = (new Topics)->getClubTopicsCount($club);
|
$this->template->topicsCount = (new Topics)->getClubTopicsCount($club);
|
||||||
|
|
||||||
|
$this->template->club = $club;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,8 +54,7 @@ final class GroupPresenter extends OpenVKPresenter
|
||||||
}
|
}
|
||||||
|
|
||||||
$club->toggleSubscription($this->user->identity);
|
$club->toggleSubscription($this->user->identity);
|
||||||
header("HTTP/1.1 302 Found");
|
$this->redirect("/club" . $club->getId());
|
||||||
header("Location: /club" . $club->getId());
|
|
||||||
}else{
|
}else{
|
||||||
$this->flashFail("err", "Ошибка", "Вы не ввели название группы.");
|
$this->flashFail("err", "Ошибка", "Вы не ввели название группы.");
|
||||||
}
|
}
|
||||||
|
@ -77,9 +73,7 @@ final class GroupPresenter extends OpenVKPresenter
|
||||||
|
|
||||||
$club->toggleSubscription($this->user->identity);
|
$club->toggleSubscription($this->user->identity);
|
||||||
|
|
||||||
header("HTTP/1.1 302 Found");
|
$this->redirect($club->getURL());
|
||||||
header("Location: /club" . $club->getId());
|
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderFollowers(int $id): void
|
function renderFollowers(int $id): void
|
||||||
|
@ -89,7 +83,7 @@ final class GroupPresenter extends OpenVKPresenter
|
||||||
$this->template->club = $this->clubs->get($id);
|
$this->template->club = $this->clubs->get($id);
|
||||||
$this->template->onlyShowManagers = $this->queryParam("onlyAdmins") == "1";
|
$this->template->onlyShowManagers = $this->queryParam("onlyAdmins") == "1";
|
||||||
if($this->template->onlyShowManagers) {
|
if($this->template->onlyShowManagers) {
|
||||||
$this->template->followers = null;
|
$this->template->followers = NULL;
|
||||||
|
|
||||||
$this->template->managers = $this->template->club->getManagers((int) ($this->queryParam("p") ?? 1), !$this->template->club->canBeModifiedBy($this->user->identity));
|
$this->template->managers = $this->template->club->getManagers((int) ($this->queryParam("p") ?? 1), !$this->template->club->canBeModifiedBy($this->user->identity));
|
||||||
if($this->template->club->canBeModifiedBy($this->user->identity) || !$this->template->club->isOwnerHidden()) {
|
if($this->template->club->canBeModifiedBy($this->user->identity) || !$this->template->club->isOwnerHidden()) {
|
||||||
|
@ -99,7 +93,7 @@ final class GroupPresenter extends OpenVKPresenter
|
||||||
$this->template->count = $this->template->club->getManagersCount();
|
$this->template->count = $this->template->club->getManagersCount();
|
||||||
} else {
|
} else {
|
||||||
$this->template->followers = $this->template->club->getFollowers((int) ($this->queryParam("p") ?? 1));
|
$this->template->followers = $this->template->club->getFollowers((int) ($this->queryParam("p") ?? 1));
|
||||||
$this->template->managers = null;
|
$this->template->managers = NULL;
|
||||||
$this->template->count = $this->template->club->getFollowersCount();
|
$this->template->count = $this->template->club->getFollowersCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +110,7 @@ final class GroupPresenter extends OpenVKPresenter
|
||||||
$user = is_null($this->queryParam("user")) ? $this->postParam("user") : $this->queryParam("user");
|
$user = is_null($this->queryParam("user")) ? $this->postParam("user") : $this->queryParam("user");
|
||||||
$comment = $this->postParam("comment");
|
$comment = $this->postParam("comment");
|
||||||
$removeComment = $this->postParam("removeComment") === "1";
|
$removeComment = $this->postParam("removeComment") === "1";
|
||||||
$hidden = ["0" => false, "1" => true][$this->queryParam("hidden")] ?? null;
|
$hidden = ["0" => false, "1" => true][$this->queryParam("hidden")] ?? NULL;
|
||||||
//$index = $this->queryParam("index");
|
//$index = $this->queryParam("index");
|
||||||
if(!$user)
|
if(!$user)
|
||||||
$this->badRequest();
|
$this->badRequest();
|
||||||
|
@ -202,9 +196,11 @@ final class GroupPresenter extends OpenVKPresenter
|
||||||
$this->template->club = $club;
|
$this->template->club = $club;
|
||||||
|
|
||||||
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||||
|
if(!$club->setShortcode( empty($this->postParam("shortcode")) ? NULL : $this->postParam("shortcode") ))
|
||||||
|
$this->flashFail("err", tr("error"), tr("error_shorturl_incorrect"));
|
||||||
|
|
||||||
$club->setName(empty($this->postParam("name")) ? $club->getName() : $this->postParam("name"));
|
$club->setName(empty($this->postParam("name")) ? $club->getName() : $this->postParam("name"));
|
||||||
$club->setAbout(empty($this->postParam("about")) ? NULL : $this->postParam("about"));
|
$club->setAbout(empty($this->postParam("about")) ? NULL : $this->postParam("about"));
|
||||||
$club->setShortcode(empty($this->postParam("shortcode")) ? NULL : $this->postParam("shortcode"));
|
|
||||||
$club->setWall(empty($this->postParam("wall")) ? 0 : 1);
|
$club->setWall(empty($this->postParam("wall")) ? 0 : 1);
|
||||||
$club->setAdministrators_List_Display(empty($this->postParam("administrators_list_display")) ? 0 : $this->postParam("administrators_list_display"));
|
$club->setAdministrators_List_Display(empty($this->postParam("administrators_list_display")) ? 0 : $this->postParam("administrators_list_display"));
|
||||||
$club->setEveryone_Can_Create_Topics(empty($this->postParam("everyone_can_create_topics")) ? 0 : 1);
|
$club->setEveryone_Can_Create_Topics(empty($this->postParam("everyone_can_create_topics")) ? 0 : 1);
|
||||||
|
|
|
@ -29,9 +29,10 @@ final class InternalAPIPresenter extends OpenVKPresenter
|
||||||
|
|
||||||
function renderRoute(): void
|
function renderRoute(): void
|
||||||
{
|
{
|
||||||
if($_SERVER["REQUEST_METHOD"] !== "POST")
|
if($_SERVER["REQUEST_METHOD"] !== "POST") {
|
||||||
|
header("HTTP/1.1 405 Method Not Allowed");
|
||||||
exit("ты дебил это точка апи");
|
exit("ты дебил это точка апи");
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
$input = (object) MessagePack::unpack(file_get_contents("php://input"));
|
$input = (object) MessagePack::unpack(file_get_contents("php://input"));
|
||||||
} catch (\Exception $ex) {
|
} catch (\Exception $ex) {
|
||||||
|
@ -71,20 +72,21 @@ final class InternalAPIPresenter extends OpenVKPresenter
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderTimezone() {
|
function renderTimezone() {
|
||||||
if($_SERVER["REQUEST_METHOD"] !== "POST")
|
if($_SERVER["REQUEST_METHOD"] !== "POST") {
|
||||||
|
header("HTTP/1.1 405 Method Not Allowed");
|
||||||
exit("ты дебил это метод апи");
|
exit("ты дебил это метод апи");
|
||||||
|
}
|
||||||
$sessionOffset = Session::i()->get("_timezoneOffset");
|
$sessionOffset = Session::i()->get("_timezoneOffset");
|
||||||
if(is_numeric($this->postParam("timezone", false))) {
|
if(is_numeric($this->postParam("timezone", false))) {
|
||||||
$postTZ = intval($this->postParam("timezone", false));
|
$postTZ = intval($this->postParam("timezone", false));
|
||||||
if ($postTZ != $sessionOffset || $sessionOffset == null) {
|
if ($postTZ != $sessionOffset || $sessionOffset == null) {
|
||||||
Session::i()->set("_timezoneOffset", $postTZ ? $postTZ : 3 * MINUTE );
|
Session::i()->set("_timezoneOffset", $postTZ ? $postTZ : 3 * MINUTE );
|
||||||
$this->returnJson([
|
$this->returnJson([
|
||||||
"success" => 1 // If it's new value
|
"success" => 1 # If it's new value
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
$this->returnJson([
|
$this->returnJson([
|
||||||
"success" => 2 // If it's the same value (if for some reason server will call this func)
|
"success" => 2 # If it's the same value (if for some reason server will call this func)
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -34,10 +34,18 @@ final class MessengerPresenter extends OpenVKPresenter
|
||||||
if(isset($_GET["sel"]))
|
if(isset($_GET["sel"]))
|
||||||
$this->pass("openvk!Messenger->app", $_GET["sel"]);
|
$this->pass("openvk!Messenger->app", $_GET["sel"]);
|
||||||
|
|
||||||
$page = $_GET["p"] ?? 1;
|
$page = (int) ($_GET["p"] ?? 1);
|
||||||
$correspondences = iterator_to_array($this->messages->getCorrespondencies($this->user->identity, $page));
|
$correspondences = iterator_to_array($this->messages->getCorrespondencies($this->user->identity, $page));
|
||||||
|
|
||||||
|
// #КакаоПрокакалось
|
||||||
|
|
||||||
$this->template->corresps = $correspondences;
|
$this->template->corresps = $correspondences;
|
||||||
|
$this->template->paginatorConf = (object) [
|
||||||
|
"count" => $this->messages->getCorrespondenciesCount($this->user->identity),
|
||||||
|
"page" => (int) ($_GET["p"] ?? 1),
|
||||||
|
"amount" => sizeof($this->template->corresps),
|
||||||
|
"perPage" => OPENVK_DEFAULT_PER_PAGE,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderApp(int $sel): void
|
function renderApp(int $sel): void
|
||||||
|
@ -106,7 +114,7 @@ final class MessengerPresenter extends OpenVKPresenter
|
||||||
|
|
||||||
$messages = [];
|
$messages = [];
|
||||||
$correspondence = new Correspondence($this->user->identity, $correspondent);
|
$correspondence = new Correspondence($this->user->identity, $correspondent);
|
||||||
foreach($correspondence->getMessages(1, $lastMsg === 0 ? null : $lastMsg) as $message)
|
foreach($correspondence->getMessages(1, $lastMsg === 0 ? NULL : $lastMsg) as $message)
|
||||||
$messages[] = $message->simplify();
|
$messages[] = $message->simplify();
|
||||||
|
|
||||||
header("Content-Type: application/json");
|
header("Content-Type: application/json");
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Presenters;
|
namespace openvk\Web\Presenters;
|
||||||
use openvk\Web\Models\Repositories\Users;
|
use openvk\Web\Models\Repositories\{Users, Notes};
|
||||||
use openvk\Web\Models\Repositories\Notes;
|
|
||||||
use openvk\Web\Models\Entities\Note;
|
use openvk\Web\Models\Entities\Note;
|
||||||
|
|
||||||
final class NotesPresenter extends OpenVKPresenter
|
final class NotesPresenter extends OpenVKPresenter
|
||||||
|
@ -47,6 +46,29 @@ final class NotesPresenter extends OpenVKPresenter
|
||||||
$this->template->note = $note;
|
$this->template->note = $note;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderPreView(): void
|
||||||
|
{
|
||||||
|
$this->assertUserLoggedIn();
|
||||||
|
$this->willExecuteWriteAction();
|
||||||
|
|
||||||
|
if($_SERVER["REQUEST_METHOD"] !== "POST") {
|
||||||
|
header("HTTP/1.1 400 Bad Request");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(empty($this->postParam("html")) || empty($this->postParam("title"))) {
|
||||||
|
header("HTTP/1.1 400 Bad Request");
|
||||||
|
exit(tr("note_preview_empty_err"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$note = new Note;
|
||||||
|
$note->setSource($this->postParam("html"));
|
||||||
|
|
||||||
|
$this->flash("info", tr("note_preview_warn"), tr("note_preview_warn_details"));
|
||||||
|
$this->template->title = $this->postParam("title");
|
||||||
|
$this->template->html = $note->getText();
|
||||||
|
}
|
||||||
|
|
||||||
function renderCreate(): void
|
function renderCreate(): void
|
||||||
{
|
{
|
||||||
$this->assertUserLoggedIn();
|
$this->assertUserLoggedIn();
|
||||||
|
|
|
@ -8,10 +8,19 @@ final class NotificationPresenter extends OpenVKPresenter
|
||||||
$this->assertUserLoggedIn();
|
$this->assertUserLoggedIn();
|
||||||
|
|
||||||
$archive = $this->queryParam("act") === "archived";
|
$archive = $this->queryParam("act") === "archived";
|
||||||
$this->template->mode = $archive ? "archived" : "new";
|
$count = $this->user->identity->getNotificationsCount($archive);
|
||||||
|
|
||||||
|
if($count == 0 && $this->queryParam("act") == NULL) {
|
||||||
|
$mode = "archived";
|
||||||
|
$archive = true;
|
||||||
|
} else {
|
||||||
|
$mode = $archive ? "archived" : "new";
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->template->mode = $mode;
|
||||||
$this->template->page = (int) ($this->queryParam("p") ?? 1);
|
$this->template->page = (int) ($this->queryParam("p") ?? 1);
|
||||||
$this->template->iterator = iterator_to_array($this->user->identity->getNotifications($this->template->page, $archive));
|
$this->template->iterator = iterator_to_array($this->user->identity->getNotifications($this->template->page, $archive));
|
||||||
$this->template->count = $this->user->identity->getNotificationsCount($archive);
|
$this->template->count = $count;
|
||||||
|
|
||||||
$this->user->identity->updateNotificationOffset();
|
$this->user->identity->updateNotificationOffset();
|
||||||
$this->user->identity->save();
|
$this->user->identity->save();
|
||||||
|
|
|
@ -14,6 +14,7 @@ abstract class OpenVKPresenter extends SimplePresenter
|
||||||
{
|
{
|
||||||
protected $banTolerant = false;
|
protected $banTolerant = false;
|
||||||
protected $activationTolerant = false;
|
protected $activationTolerant = false;
|
||||||
|
protected $deactivationTolerant = false;
|
||||||
protected $errorTemplate = "@error";
|
protected $errorTemplate = "@error";
|
||||||
protected $user = NULL;
|
protected $user = NULL;
|
||||||
|
|
||||||
|
@ -60,9 +61,7 @@ abstract class OpenVKPresenter extends SimplePresenter
|
||||||
$this->flash($type, $title, $message, $code);
|
$this->flash($type, $title, $message, $code);
|
||||||
$referer = $_SERVER["HTTP_REFERER"] ?? "/";
|
$referer = $_SERVER["HTTP_REFERER"] ?? "/";
|
||||||
|
|
||||||
header("HTTP/1.1 302 Found");
|
$this->redirect($referer);
|
||||||
header("Location: $referer");
|
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,9 +97,8 @@ abstract class OpenVKPresenter extends SimplePresenter
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->flash("err", tr("login_required_error"), tr("login_required_error_comment"));
|
$this->flash("err", tr("login_required_error"), tr("login_required_error_comment"));
|
||||||
header("HTTP/1.1 302 Found");
|
|
||||||
header("Location: $loginUrl");
|
$this->redirect($loginUrl);
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,15 +108,13 @@ abstract class OpenVKPresenter extends SimplePresenter
|
||||||
if($model !== "user") {
|
if($model !== "user") {
|
||||||
$this->flash("info", tr("login_required_error"), tr("login_required_error_comment"));
|
$this->flash("info", tr("login_required_error"), tr("login_required_error_comment"));
|
||||||
|
|
||||||
header("HTTP/1.1 302 Found");
|
$this->redirect("/login");
|
||||||
header("Location: /login");
|
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ($action === "register" || $action === "login");
|
return ($action === "register" || $action === "login");
|
||||||
}
|
}
|
||||||
|
|
||||||
return (bool) $this->user->raw->can($action)->model($model)->whichBelongsTo($context === -1 ? null : $context);
|
return (bool) $this->user->raw->can($action)->model($model)->whichBelongsTo($context === -1 ? NULL : $context);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function assertPermission(string $model, string $action, int $context, bool $throw = false): void
|
protected function assertPermission(string $model, string $action, int $context, bool $throw = false): void
|
||||||
|
@ -214,32 +210,21 @@ abstract class OpenVKPresenter extends SimplePresenter
|
||||||
$this->template->thisUser = $this->user->identity;
|
$this->template->thisUser = $this->user->identity;
|
||||||
$this->template->userTainted = $user->isTainted();
|
$this->template->userTainted = $user->isTainted();
|
||||||
|
|
||||||
if($this->user->identity->isDeleted()) {
|
if($this->user->identity->isDeleted() && !$this->deactivationTolerant) {
|
||||||
/*
|
if($this->user->identity->isDeactivated()) {
|
||||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣴⠶⠶⣶⠶⠶⠶⠶⠶⠶⠶⠶⠶⢶⠶⠶⠶⠤⠤⠤⠤⣄⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
header("HTTP/1.1 403 Forbidden");
|
||||||
⠀⠀⠀⠀⠀⠀⠀⠀⣠⡾⠋⠀⠀⠊⠀⠀⠀⠀⠀⠀⠀⠀⠒⠒⠒⠀⠀⠀⠀⠤⢤⣤⣄⠉⠉⠛⠛⠷⣦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
$this->getTemplatingEngine()->render(__DIR__ . "/templates/@deactivated.xml", [
|
||||||
⠀⠀⠀⠀⠀⠀⠀⣰⠟⠀⠀⠀⠀⠀⠐⠋⢑⣤⣶⣶⣤⡢⡀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣄⡂⠀⠀⠶⢄⠙⢷⣤⠀⠀⠀⠀⠀⠀⠀⠀
|
"thisUser" => $this->user->identity,
|
||||||
⠀⠀⠀⠀⠀⠀⣸⡿⠚⠉⡀⠀⠀⠀⠀⢰⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⢢⠀⠀⡀⣰⣿⣿⣿⣿⣦⡀⠀⠀⠡⡀⢹⡆⠀⠀⠀⠀⠀⠀⠀
|
"csrfToken" => $GLOBALS["csrfToken"],
|
||||||
⠀⠀⠀⠀⢀⣴⠏⠀⣀⣀⣀⡤⢤⣄⣠⣿⣿⣿⣿⣻⣿⣿⣷⠀⢋⣾⠈⠙⣶⠒⢿⣿⣿⣿⣿⡿⠟⠃⠀⡀⠡⠼⣧⡀⠀⠀⠀⠀⠀⠀
|
"isTimezoned" => Session::i()->get("_timezoneOffset"),
|
||||||
⠀⠀⢀⣴⣿⢃⡴⢊⢽⣶⣤⣀⠀⠊⠉⠉⡛⢿⣿⣿⣿⠿⠋⢀⡀⠁⠀⠀⢸⣁⣀⣉⣉⣉⡉⠀⠩⡡⠀⣩⣦⠀⠈⠻⣦⡀⠀⠀⠀⠀
|
]);
|
||||||
⠀⢠⡟⢡⠇⡞⢀⠆⠀⢻⣿⣿⣷⣄⠀⢀⠈⠂⠈⢁⡤⠚⡟⠉⠀⣀⣀⠀⠈⠳⣍⠓⢆⢀⡠⢀⣨⣴⣿⣿⡏⢀⡆⠀⢸⡇⠀⠀⠀⠀
|
} else {
|
||||||
⠀⣾⠁⢸⠀⠀⢸⠀⠀⠀⠹⣿⣿⣿⣿⣶⣬⣦⣤⡈⠀⠀⠇⠀⠛⠉⣩⣤⣤⣤⣿⣤⣤⣴⣾⣿⣿⣿⣿⣿⣧⠞⠀⠀⢸⡇⠀⠀⠀⠀
|
|
||||||
⠀⢹⣆⠸⠀⠀⢸⠀⠀⠀⠀⠘⢿⣿⣿⣿⣿⣿⣿⣟⣛⠛⠛⣛⡛⠛⠛⣛⣋⡉⠉⣡⠶⢾⣿⣿⣿⣿⣿⣿⡇⠀⠀⢀⣾⠃⠀⠀⠀⠀
|
|
||||||
⠀⠀⠻⣆⡀⠀⠈⢂⠀⠀⠀⠠⡈⢻⣿⣿⣿⣿⡟⠁⠈⢧⡼⠉⠙⣆⡞⠁⠈⢹⣴⠃⠀⢸⣿⣿⣿⣿⣿⣿⠃⠀⡆⣾⠃⠀⠀⠀⠀⠀
|
|
||||||
⠀⠀⠀⠈⢻⣇⠀⠀⠀⠀⠀⠀⢡⠀⠹⣿⣿⣿⣷⡀⠀⣸⡇⠀⠀⣿⠁⠀⠀⠘⣿⠀⠀⠘⣿⣿⣿⣿⣿⣿⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀
|
|
||||||
⠀⠀⠀⠀⠀⠹⣇⠀⠠⠀⠀⠀⠀⠡⠐⢬⡻⣿⣿⣿⣿⣿⣷⣶⣶⣿⣦⣤⣤⣤⣿⣦⣶⣿⣿⣿⣿⣿⣿⣿⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀
|
|
||||||
⠀⠀⠀⠀⠀⠀⠹⣧⡀⠡⡀⠀⠀⠀⠑⠄⠙⢎⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⠀⢿⡇⠀⠀⠀⠀⠀⠀
|
|
||||||
⠀⠀⠀⠀⠀⠀⠀⠈⠳⣤⡐⡄⠀⠀⠀⠈⠂⠀⠱⣌⠻⣿⣿⣿⣿⣿⣿⣿⠿⣿⠟⢻⡏⢻⣿⣿⣿⣿⣿⣿⣿⠀⢸⡇⠀⠀⠀⠀⠀⠀
|
|
||||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⢮⣦⡀⠂⠀⢀⠀⠀⠈⠳⣈⠻⣿⣿⣿⡇⠘⡄⢸⠀⠀⣇⠀⣻⣿⣿⣿⣿⣿⡏⠀⠸⡇⠀⠀⠀⠀⠀⠀
|
|
||||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⢶⣤⣄⡑⠄⠀⠀⠈⠑⠢⠙⠻⢷⣶⣵⣞⣑⣒⣋⣉⣁⣻⣿⠿⠟⠱⠃⡸⠀⣧⠀⠀⠀⠀⠀⠀
|
|
||||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠻⣷⣄⡀⠐⠢⣄⣀⡀⠀⠉⠉⠉⠉⠛⠙⠭⠭⠄⠒⠈⠀⠐⠁⢀⣿⠀⠀⠀⠀⠀⠀
|
|
||||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠷⢦⣤⣤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣒⡠⠄⣠⡾⠃⠀⠀⠀⠀⠀⠀
|
|
||||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠙⠛⠷⠶⣦⣤⣭⣤⣬⣭⣭⣴⠶⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀
|
|
||||||
*/
|
|
||||||
Authenticator::i()->logout();
|
Authenticator::i()->logout();
|
||||||
Session::i()->set("_su", NULL);
|
Session::i()->set("_su", NULL);
|
||||||
$this->flashFail("err", tr("error"), tr("profile_not_found"));
|
$this->flashFail("err", tr("error"), tr("profile_not_found"));
|
||||||
$this->redirect("/", static::REDIRECT_TEMPORARY);
|
$this->redirect("/");
|
||||||
|
}
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->user->identity->isBanned() && !$this->banTolerant) {
|
if($this->user->identity->isBanned() && !$this->banTolerant) {
|
||||||
|
@ -252,7 +237,7 @@ abstract class OpenVKPresenter extends SimplePresenter
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ето для емейл уже надо (и по хорошему надо бы избавится от повторяющегося кода мда)
|
# ето для емейл уже надо (и по хорошему надо бы избавится от повторяющегося кода мда)
|
||||||
if(!$this->user->identity->isActivated() && !$this->activationTolerant) {
|
if(!$this->user->identity->isActivated() && !$this->activationTolerant) {
|
||||||
header("HTTP/1.1 403 Forbidden");
|
header("HTTP/1.1 403 Forbidden");
|
||||||
$this->getTemplatingEngine()->render(__DIR__ . "/templates/@email.xml", [
|
$this->getTemplatingEngine()->render(__DIR__ . "/templates/@email.xml", [
|
||||||
|
@ -265,7 +250,7 @@ abstract class OpenVKPresenter extends SimplePresenter
|
||||||
|
|
||||||
$userValidated = 1;
|
$userValidated = 1;
|
||||||
$cacheTime = 0; # Force no cache
|
$cacheTime = 0; # Force no cache
|
||||||
if ($this->user->identity->onlineStatus() == 0) {
|
if($this->user->identity->onlineStatus() == 0 && !($this->user->identity->isDeleted() || $this->user->identity->isBanned())) {
|
||||||
$this->user->identity->setOnline(time());
|
$this->user->identity->setOnline(time());
|
||||||
$this->user->identity->save();
|
$this->user->identity->save();
|
||||||
}
|
}
|
||||||
|
@ -288,7 +273,7 @@ abstract class OpenVKPresenter extends SimplePresenter
|
||||||
|
|
||||||
$whichbrowser = new WhichBrowser\Parser(getallheaders());
|
$whichbrowser = new WhichBrowser\Parser(getallheaders());
|
||||||
$mobiletheme = OPENVK_ROOT_CONF["openvk"]["preferences"]["defaultMobileTheme"];
|
$mobiletheme = OPENVK_ROOT_CONF["openvk"]["preferences"]["defaultMobileTheme"];
|
||||||
if($mobiletheme && $whichbrowser->isType('mobile') && Session::i()->get("_tempTheme") == null)
|
if($mobiletheme && $whichbrowser->isType('mobile') && Session::i()->get("_tempTheme") == NULL)
|
||||||
$this->setSessionTheme($mobiletheme);
|
$this->setSessionTheme($mobiletheme);
|
||||||
|
|
||||||
$theme = NULL;
|
$theme = NULL;
|
||||||
|
@ -299,7 +284,7 @@ abstract class OpenVKPresenter extends SimplePresenter
|
||||||
$theme = Themepacks::i()[Session::i()->get("_sessionTheme", "ovk")];
|
$theme = Themepacks::i()[Session::i()->get("_sessionTheme", "ovk")];
|
||||||
} else if($this->requestParam("themePreview")) {
|
} else if($this->requestParam("themePreview")) {
|
||||||
$theme = Themepacks::i()[$this->requestParam("themePreview")];
|
$theme = Themepacks::i()[$this->requestParam("themePreview")];
|
||||||
} else if($this->user->identity !== null && $this->user->identity->getTheme()) {
|
} else if($this->user->identity !== NULL && $this->user->identity->getTheme()) {
|
||||||
$theme = $this->user->identity->getTheme();
|
$theme = $this->user->identity->getTheme();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Presenters;
|
namespace openvk\Web\Presenters;
|
||||||
use openvk\Web\Models\Entities\Club;
|
use openvk\Web\Models\Entities\{Club, Photo, Album};
|
||||||
use openvk\Web\Models\Entities\Photo;
|
use openvk\Web\Models\Repositories\{Photos, Albums, Users, Clubs};
|
||||||
use openvk\Web\Models\Entities\Album;
|
|
||||||
use openvk\Web\Models\Repositories\Photos;
|
|
||||||
use openvk\Web\Models\Repositories\Albums;
|
|
||||||
use openvk\Web\Models\Repositories\Users;
|
|
||||||
use openvk\Web\Models\Repositories\Clubs;
|
|
||||||
use Nette\InvalidStateException as ISE;
|
use Nette\InvalidStateException as ISE;
|
||||||
|
|
||||||
final class PhotosPresenter extends OpenVKPresenter
|
final class PhotosPresenter extends OpenVKPresenter
|
||||||
|
@ -72,6 +67,8 @@ final class PhotosPresenter extends OpenVKPresenter
|
||||||
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||||
if(empty($this->postParam("name")))
|
if(empty($this->postParam("name")))
|
||||||
$this->flashFail("err", tr("error"), tr("error_segmentation"));
|
$this->flashFail("err", tr("error"), tr("error_segmentation"));
|
||||||
|
else if(strlen($this->postParam("name")) > 36)
|
||||||
|
$this->flashFail("err", tr("error"), tr("error_data_too_big", "name", 36, "bytes"));
|
||||||
|
|
||||||
$album = new Album;
|
$album = new Album;
|
||||||
$album->setOwner(isset($club) ? $club->getId() * -1 : $this->user->id);
|
$album->setOwner(isset($club) ? $club->getId() * -1 : $this->user->id);
|
||||||
|
@ -81,9 +78,9 @@ final class PhotosPresenter extends OpenVKPresenter
|
||||||
$album->save();
|
$album->save();
|
||||||
|
|
||||||
if(isset($club))
|
if(isset($club))
|
||||||
$this->redirect("/album-" . $album->getOwner()->getId() . "_" . $album->getId(), static::REDIRECT_TEMPORARY);
|
$this->redirect("/album-" . $album->getOwner()->getId() . "_" . $album->getId());
|
||||||
else
|
else
|
||||||
$this->redirect("/album" . $album->getOwner()->getId() . "_" . $album->getId(), static::REDIRECT_TEMPORARY);
|
$this->redirect("/album" . $album->getOwner()->getId() . "_" . $album->getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,6 +97,9 @@ final class PhotosPresenter extends OpenVKPresenter
|
||||||
$this->template->album = $album;
|
$this->template->album = $album;
|
||||||
|
|
||||||
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||||
|
if(strlen($this->postParam("name")) > 36)
|
||||||
|
$this->flashFail("err", tr("error"), tr("error_data_too_big", "name", 36, "bytes"));
|
||||||
|
|
||||||
$album->setName(empty($this->postParam("name")) ? $album->getName() : $this->postParam("name"));
|
$album->setName(empty($this->postParam("name")) ? $album->getName() : $this->postParam("name"));
|
||||||
$album->setDescription(empty($this->postParam("desc")) ? NULL : $this->postParam("desc"));
|
$album->setDescription(empty($this->postParam("desc")) ? NULL : $this->postParam("desc"));
|
||||||
$album->setEdited(time());
|
$album->setEdited(time());
|
||||||
|
@ -124,6 +124,7 @@ final class PhotosPresenter extends OpenVKPresenter
|
||||||
$name = $album->getName();
|
$name = $album->getName();
|
||||||
$owner = $album->getOwner();
|
$owner = $album->getOwner();
|
||||||
$album->delete();
|
$album->delete();
|
||||||
|
|
||||||
$this->flash("succ", "Альбом удалён", "Альбом $name был успешно удалён.");
|
$this->flash("succ", "Альбом удалён", "Альбом $name был успешно удалён.");
|
||||||
$this->redirect("/albums" . ($owner instanceof Club ? "-" : "") . $owner->getId());
|
$this->redirect("/albums" . ($owner instanceof Club ? "-" : "") . $owner->getId());
|
||||||
}
|
}
|
||||||
|
@ -198,7 +199,7 @@ final class PhotosPresenter extends OpenVKPresenter
|
||||||
$photo->save();
|
$photo->save();
|
||||||
|
|
||||||
$this->flash("succ", "Изменения сохранены", "Обновлённое описание появится на странице с фоткой.");
|
$this->flash("succ", "Изменения сохранены", "Обновлённое описание появится на странице с фоткой.");
|
||||||
$this->redirect("/photo" . $photo->getPrettyId(), static::REDIRECT_TEMPORARY);
|
$this->redirect("/photo" . $photo->getPrettyId());
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->template->photo = $photo;
|
$this->template->photo = $photo;
|
||||||
|
@ -236,7 +237,10 @@ final class PhotosPresenter extends OpenVKPresenter
|
||||||
}
|
}
|
||||||
|
|
||||||
$album->addPhoto($photo);
|
$album->addPhoto($photo);
|
||||||
$this->redirect("/photo" . $photo->getPrettyId(), static::REDIRECT_TEMPORARY);
|
$album->setEdited(time());
|
||||||
|
$album->save();
|
||||||
|
|
||||||
|
$this->redirect("/photo" . $photo->getPrettyId() . "?from=album" . $album->getId());
|
||||||
} else {
|
} else {
|
||||||
$this->template->album = $album;
|
$this->template->album = $album;
|
||||||
}
|
}
|
||||||
|
@ -257,9 +261,11 @@ final class PhotosPresenter extends OpenVKPresenter
|
||||||
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||||
$this->assertNoCSRF();
|
$this->assertNoCSRF();
|
||||||
$album->removePhoto($photo);
|
$album->removePhoto($photo);
|
||||||
|
$album->setEdited(time());
|
||||||
|
$album->save();
|
||||||
|
|
||||||
$this->flash("succ", "Фотография удалена", "Эта фотография была успешно удалена.");
|
$this->flash("succ", "Фотография удалена", "Эта фотография была успешно удалена.");
|
||||||
$this->redirect("/album" . $album->getPrettyId(), static::REDIRECT_TEMPORARY);
|
$this->redirect("/album" . $album->getPrettyId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,6 +284,6 @@ final class PhotosPresenter extends OpenVKPresenter
|
||||||
$photo->delete();
|
$photo->delete();
|
||||||
|
|
||||||
$this->flash("succ", "Фотография удалена", "Эта фотография была успешно удалена.");
|
$this->flash("succ", "Фотография удалена", "Эта фотография была успешно удалена.");
|
||||||
$this->redirect("/id0", static::REDIRECT_TEMPORARY);
|
$this->redirect("/id0");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Presenters;
|
namespace openvk\Web\Presenters;
|
||||||
use openvk\Web\Models\Repositories\Users;
|
use openvk\Web\Models\Entities\{User, Club};
|
||||||
use openvk\Web\Models\Entities\User;
|
use openvk\Web\Models\Repositories\{Users, Clubs};
|
||||||
use openvk\Web\Models\Repositories\Clubs;
|
|
||||||
use openvk\Web\Models\Entities\Club;
|
|
||||||
use Chandler\Database\DatabaseConnection;
|
use Chandler\Database\DatabaseConnection;
|
||||||
|
|
||||||
final class SearchPresenter extends OpenVKPresenter
|
final class SearchPresenter extends OpenVKPresenter
|
||||||
|
@ -29,7 +27,7 @@ final class SearchPresenter extends OpenVKPresenter
|
||||||
if($query != "")
|
if($query != "")
|
||||||
$this->assertUserLoggedIn();
|
$this->assertUserLoggedIn();
|
||||||
|
|
||||||
// https://youtu.be/pSAWM5YuXx8
|
# https://youtu.be/pSAWM5YuXx8
|
||||||
|
|
||||||
$repos = [ "groups" => "clubs", "users" => "users" ];
|
$repos = [ "groups" => "clubs", "users" => "users" ];
|
||||||
$repo = $repos[$type] or $this->throwError(400, "Bad Request", "Invalid search entity $type.");
|
$repo = $repos[$type] or $this->throwError(400, "Bad Request", "Invalid search entity $type.");
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Presenters;
|
namespace openvk\Web\Presenters;
|
||||||
use openvk\Web\Models\Entities\Ticket;
|
use openvk\Web\Models\Entities\{Ticket, TicketComment};
|
||||||
use openvk\Web\Models\Repositories\{Tickets, Users};
|
use openvk\Web\Models\Repositories\{Tickets, Users, TicketComments};
|
||||||
use openvk\Web\Models\Entities\TicketComment;
|
|
||||||
use openvk\Web\Models\Repositories\TicketComments;
|
|
||||||
use openvk\Web\Util\Telegram;
|
use openvk\Web\Util\Telegram;
|
||||||
use Chandler\Session\Session;
|
use Chandler\Session\Session;
|
||||||
|
use Chandler\Database\DatabaseConnection;
|
||||||
use Parsedown;
|
use Parsedown;
|
||||||
|
|
||||||
final class SupportPresenter extends OpenVKPresenter
|
final class SupportPresenter extends OpenVKPresenter
|
||||||
{
|
{
|
||||||
protected $banTolerant = true;
|
protected $banTolerant = true;
|
||||||
|
protected $deactivationTolerant = true;
|
||||||
|
|
||||||
private $tickets;
|
private $tickets;
|
||||||
private $comments;
|
private $comments;
|
||||||
|
@ -28,6 +28,41 @@ final class SupportPresenter extends OpenVKPresenter
|
||||||
$this->assertUserLoggedIn();
|
$this->assertUserLoggedIn();
|
||||||
$this->template->mode = in_array($this->queryParam("act"), ["faq", "new", "list"]) ? $this->queryParam("act") : "faq";
|
$this->template->mode = in_array($this->queryParam("act"), ["faq", "new", "list"]) ? $this->queryParam("act") : "faq";
|
||||||
|
|
||||||
|
if($this->template->mode === "faq") {
|
||||||
|
$lang = Session::i()->get("lang", "ru");
|
||||||
|
$base = OPENVK_ROOT . "/data/knowledgebase/faq";
|
||||||
|
if(file_exists("$base.$lang.md"))
|
||||||
|
$file = "$base.$lang.md";
|
||||||
|
else if(file_exists("$base.md"))
|
||||||
|
$file = "$base.md";
|
||||||
|
else
|
||||||
|
$file = NULL;
|
||||||
|
|
||||||
|
if(is_null($file)) {
|
||||||
|
$this->template->faq = [];
|
||||||
|
} else {
|
||||||
|
$lines = file($file);
|
||||||
|
$faq = [];
|
||||||
|
$index = 0;
|
||||||
|
|
||||||
|
foreach($lines as $line) {
|
||||||
|
if(strpos($line, "# ") === 0)
|
||||||
|
++$index;
|
||||||
|
|
||||||
|
$faq[$index][] = $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->template->faq = array_map(function($section) {
|
||||||
|
$title = substr($section[0], 2);
|
||||||
|
array_shift($section);
|
||||||
|
return [
|
||||||
|
$title,
|
||||||
|
(new Parsedown())->text(implode("\n", $section))
|
||||||
|
];
|
||||||
|
}, $faq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$this->template->count = $this->tickets->getTicketsCountByUserId($this->user->id);
|
$this->template->count = $this->tickets->getTicketsCountByUserId($this->user->id);
|
||||||
if($this->template->mode === "list") {
|
if($this->template->mode === "list") {
|
||||||
$this->template->page = (int) ($this->queryParam("p") ?? 1);
|
$this->template->page = (int) ($this->queryParam("p") ?? 1);
|
||||||
|
@ -63,8 +98,7 @@ final class SupportPresenter extends OpenVKPresenter
|
||||||
Telegram::send($helpdeskChat, $telegramText);
|
Telegram::send($helpdeskChat, $telegramText);
|
||||||
}
|
}
|
||||||
|
|
||||||
header("HTTP/1.1 302 Found");
|
$this->redirect("/support/view/" . $ticket->getId());
|
||||||
header("Location: /support/view/" . $ticket->getId());
|
|
||||||
} else {
|
} else {
|
||||||
$this->flashFail("err", tr("error"), tr("you_have_not_entered_name_or_text"));
|
$this->flashFail("err", tr("error"), tr("you_have_not_entered_name_or_text"));
|
||||||
}
|
}
|
||||||
|
@ -79,6 +113,7 @@ final class SupportPresenter extends OpenVKPresenter
|
||||||
$act = $this->queryParam("act") ?? "open";
|
$act = $this->queryParam("act") ?? "open";
|
||||||
switch($act) {
|
switch($act) {
|
||||||
default:
|
default:
|
||||||
|
# NOTICE falling through
|
||||||
case "open":
|
case "open":
|
||||||
$state = 0;
|
$state = 0;
|
||||||
break;
|
break;
|
||||||
|
@ -154,8 +189,7 @@ final class SupportPresenter extends OpenVKPresenter
|
||||||
$comment->setCreated(time());
|
$comment->setCreated(time());
|
||||||
$comment->save();
|
$comment->save();
|
||||||
|
|
||||||
header("HTTP/1.1 302 Found");
|
$this->redirect("/support/view/" . $id);
|
||||||
header("Location: /support/view/" . $id);
|
|
||||||
} else {
|
} else {
|
||||||
$this->flashFail("err", tr("error"), tr("you_have_not_entered_text"));
|
$this->flashFail("err", tr("error"), tr("you_have_not_entered_text"));
|
||||||
}
|
}
|
||||||
|
@ -286,6 +320,10 @@ final class SupportPresenter extends OpenVKPresenter
|
||||||
|
|
||||||
$user->setBlock_In_Support_Reason($this->queryParam("reason"));
|
$user->setBlock_In_Support_Reason($this->queryParam("reason"));
|
||||||
$user->save();
|
$user->save();
|
||||||
|
|
||||||
|
if($this->queryParam("close_tickets"))
|
||||||
|
DatabaseConnection::i()->getConnection()->query("UPDATE tickets SET type = 2 WHERE user_id = ".$id);
|
||||||
|
|
||||||
$this->returnJson([ "success" => true, "reason" => $this->queryParam("reason") ]);
|
$this->returnJson([ "success" => true, "reason" => $this->queryParam("reason") ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ final class TopicsPresenter extends OpenVKPresenter
|
||||||
$topic->setFlags($flags);
|
$topic->setFlags($flags);
|
||||||
$topic->save();
|
$topic->save();
|
||||||
|
|
||||||
// TODO move to trait
|
# TODO move to trait
|
||||||
try {
|
try {
|
||||||
$photo = NULL;
|
$photo = NULL;
|
||||||
$video = NULL;
|
$video = NULL;
|
||||||
|
@ -108,7 +108,7 @@ final class TopicsPresenter extends OpenVKPresenter
|
||||||
}
|
}
|
||||||
} catch(ISE $ex) {
|
} catch(ISE $ex) {
|
||||||
$this->flash("err", "Не удалось опубликовать комментарий", "Файл медиаконтента повреждён или слишком велик.");
|
$this->flash("err", "Не удалось опубликовать комментарий", "Файл медиаконтента повреждён или слишком велик.");
|
||||||
$this->redirect("/topic" . $topic->getPrettyId(), static::REDIRECT_TEMPORARY);
|
$this->redirect("/topic" . $topic->getPrettyId());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!empty($this->postParam("text")) || $photo || $video) {
|
if(!empty($this->postParam("text")) || $photo || $video) {
|
||||||
|
@ -123,7 +123,7 @@ final class TopicsPresenter extends OpenVKPresenter
|
||||||
$comment->save();
|
$comment->save();
|
||||||
} catch (\LengthException $ex) {
|
} catch (\LengthException $ex) {
|
||||||
$this->flash("err", "Не удалось опубликовать комментарий", "Комментарий слишком большой.");
|
$this->flash("err", "Не удалось опубликовать комментарий", "Комментарий слишком большой.");
|
||||||
$this->redirect("/topic" . $topic->getPrettyId(), static::REDIRECT_TEMPORARY);
|
$this->redirect("/topic" . $topic->getPrettyId());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!is_null($photo))
|
if(!is_null($photo))
|
||||||
|
@ -133,7 +133,7 @@ final class TopicsPresenter extends OpenVKPresenter
|
||||||
$comment->attach($video);
|
$comment->attach($video);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->redirect("/topic" . $topic->getPrettyId(), static::REDIRECT_TEMPORARY);
|
$this->redirect("/topic" . $topic->getPrettyId());
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->template->club = $club;
|
$this->template->club = $club;
|
||||||
|
@ -167,7 +167,7 @@ final class TopicsPresenter extends OpenVKPresenter
|
||||||
$topic->save();
|
$topic->save();
|
||||||
|
|
||||||
$this->flash("succ", tr("changes_saved"), tr("topic_changes_saved_comment"));
|
$this->flash("succ", tr("changes_saved"), tr("topic_changes_saved_comment"));
|
||||||
$this->redirect("/topic" . $topic->getPrettyId(), static::REDIRECT_TEMPORARY);
|
$this->redirect("/topic" . $topic->getPrettyId());
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->template->topic = $topic;
|
$this->template->topic = $topic;
|
||||||
|
@ -189,6 +189,6 @@ final class TopicsPresenter extends OpenVKPresenter
|
||||||
$this->willExecuteWriteAction();
|
$this->willExecuteWriteAction();
|
||||||
$topic->deleteTopic();
|
$topic->deleteTopic();
|
||||||
|
|
||||||
$this->redirect("/board" . $topic->getClub()->getId(), static::REDIRECT_TEMPORARY);
|
$this->redirect("/board" . $topic->getClub()->getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Presenters;
|
namespace openvk\Web\Presenters;
|
||||||
use openvk\Web\Models\Repositories\Users;
|
use openvk\Web\Models\Repositories\{Users, Clubs};
|
||||||
use openvk\Web\Models\Repositories\Clubs;
|
|
||||||
|
|
||||||
final class UnknownTextRouteStrategyPresenter extends OpenVKPresenter
|
final class UnknownTextRouteStrategyPresenter extends OpenVKPresenter
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,24 +2,21 @@
|
||||||
namespace openvk\Web\Presenters;
|
namespace openvk\Web\Presenters;
|
||||||
use openvk\Web\Util\Sms;
|
use openvk\Web\Util\Sms;
|
||||||
use openvk\Web\Themes\Themepacks;
|
use openvk\Web\Themes\Themepacks;
|
||||||
use openvk\Web\Models\Entities\Photo;
|
use openvk\Web\Models\Entities\{Photo, Post, EmailChangeVerification};
|
||||||
use openvk\Web\Models\Repositories\Users;
|
use openvk\Web\Models\Entities\Notifications\{CoinsTransferNotification, RatingUpNotification};
|
||||||
use openvk\Web\Models\Repositories\Clubs;
|
use openvk\Web\Models\Repositories\{Users, Clubs, Albums, Videos, Notes, Vouchers, EmailChangeVerifications};
|
||||||
use openvk\Web\Models\Repositories\Albums;
|
|
||||||
use openvk\Web\Models\Repositories\Videos;
|
|
||||||
use openvk\Web\Models\Repositories\Notes;
|
|
||||||
use openvk\Web\Models\Repositories\Vouchers;
|
|
||||||
use openvk\Web\Models\Exceptions\InvalidUserNameException;
|
use openvk\Web\Models\Exceptions\InvalidUserNameException;
|
||||||
use openvk\Web\Util\Validator;
|
use openvk\Web\Util\Validator;
|
||||||
use openvk\Web\Models\Entities\Notifications\{CoinsTransferNotification, RatingUpNotification};
|
|
||||||
use Chandler\Security\Authenticator;
|
use Chandler\Security\Authenticator;
|
||||||
use lfkeitel\phptotp\{Base32, Totp};
|
use lfkeitel\phptotp\{Base32, Totp};
|
||||||
use chillerlan\QRCode\{QRCode, QROptions};
|
use chillerlan\QRCode\{QRCode, QROptions};
|
||||||
|
use Nette\Database\UniqueConstraintViolationException;
|
||||||
|
|
||||||
final class UserPresenter extends OpenVKPresenter
|
final class UserPresenter extends OpenVKPresenter
|
||||||
{
|
{
|
||||||
private $users;
|
private $users;
|
||||||
|
|
||||||
|
public $deactivationTolerant = false;
|
||||||
function __construct(Users $users)
|
function __construct(Users $users)
|
||||||
{
|
{
|
||||||
$this->users = $users;
|
$this->users = $users;
|
||||||
|
@ -30,13 +27,15 @@ final class UserPresenter extends OpenVKPresenter
|
||||||
function renderView(int $id): void
|
function renderView(int $id): void
|
||||||
{
|
{
|
||||||
$user = $this->users->get($id);
|
$user = $this->users->get($id);
|
||||||
if(!$user || $user->isDeleted())
|
if(!$user || $user->isDeleted()) {
|
||||||
$this->template->_template = "User/deleted.xml";
|
if($user->isDeactivated()) {
|
||||||
else {
|
$this->template->_template = "User/deactivated.xml";
|
||||||
if($user->getShortCode())
|
|
||||||
if(parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH) !== "/" . $user->getShortCode())
|
|
||||||
$this->redirect("/" . $user->getShortCode(), static::REDIRECT_TEMPORARY_PRESISTENT);
|
|
||||||
|
|
||||||
|
$this->template->user = $user;
|
||||||
|
} else {
|
||||||
|
$this->template->_template = "User/deleted.xml";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
$this->template->albums = (new Albums)->getUserAlbums($user);
|
$this->template->albums = (new Albums)->getUserAlbums($user);
|
||||||
$this->template->albumsCount = (new Albums)->getUserAlbumsCount($user);
|
$this->template->albumsCount = (new Albums)->getUserAlbumsCount($user);
|
||||||
$this->template->videos = (new Videos)->getByUser($user, 1, 2);
|
$this->template->videos = (new Videos)->getByUser($user, 1, 2);
|
||||||
|
@ -72,7 +71,7 @@ final class UserPresenter extends OpenVKPresenter
|
||||||
$name = $user->getFullName();
|
$name = $user->getFullName();
|
||||||
$this->flash("err", "Ошибка доступа", "Вы не можете просматривать полный список подписок $name.");
|
$this->flash("err", "Ошибка доступа", "Вы не можете просматривать полный список подписок $name.");
|
||||||
|
|
||||||
$this->redirect("/id$id", static::REDIRECT_TEMPORARY_PRESISTENT);
|
$this->redirect($user->getURL());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,6 +86,9 @@ final class UserPresenter extends OpenVKPresenter
|
||||||
elseif (!$user->getPrivacyPermission('groups.read', $this->user->identity ?? NULL))
|
elseif (!$user->getPrivacyPermission('groups.read', $this->user->identity ?? NULL))
|
||||||
$this->flashFail("err", tr("forbidden"), tr("forbidden_comment"));
|
$this->flashFail("err", tr("forbidden"), tr("forbidden_comment"));
|
||||||
else {
|
else {
|
||||||
|
if($this->queryParam("act") === "managed" && $this->user->id !== $user->getId())
|
||||||
|
$this->flashFail("err", tr("forbidden"), tr("forbidden_comment"));
|
||||||
|
|
||||||
$this->template->user = $user;
|
$this->template->user = $user;
|
||||||
$this->template->page = (int) ($this->queryParam("p") ?? 1);
|
$this->template->page = (int) ($this->queryParam("p") ?? 1);
|
||||||
$this->template->admin = $this->queryParam("act") == "managed";
|
$this->template->admin = $this->queryParam("act") == "managed";
|
||||||
|
@ -151,7 +153,10 @@ final class UserPresenter extends OpenVKPresenter
|
||||||
|
|
||||||
|
|
||||||
if (strtotime($this->postParam("birthday")) < time())
|
if (strtotime($this->postParam("birthday")) < time())
|
||||||
$user->setBirthday(strtotime($this->postParam("birthday")));
|
$user->setBirthday(empty($this->postParam("birthday")) ? NULL : strtotime($this->postParam("birthday")));
|
||||||
|
|
||||||
|
if ($this->postParam("birthday_privacy") <= 1 && $this->postParam("birthday_privacy") >= 0)
|
||||||
|
$user->setBirthday_Privacy($this->postParam("birthday_privacy"));
|
||||||
|
|
||||||
if ($this->postParam("marialstatus") <= 8 && $this->postParam("marialstatus") >= 0)
|
if ($this->postParam("marialstatus") <= 8 && $this->postParam("marialstatus") >= 0)
|
||||||
$user->setMarital_Status($this->postParam("marialstatus"));
|
$user->setMarital_Status($this->postParam("marialstatus"));
|
||||||
|
@ -267,9 +272,7 @@ final class UserPresenter extends OpenVKPresenter
|
||||||
|
|
||||||
$user->toggleSubscription($this->user->identity);
|
$user->toggleSubscription($this->user->identity);
|
||||||
|
|
||||||
header("HTTP/1.1 302 Found");
|
$this->redirect($user->getURL());
|
||||||
header("Location: /id" . $user->getId());
|
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderSetAvatar(): void
|
function renderSetAvatar(): void
|
||||||
|
@ -288,7 +291,11 @@ final class UserPresenter extends OpenVKPresenter
|
||||||
$this->flashFail("err", tr("error"), tr("error_upload_failed"));
|
$this->flashFail("err", tr("error"), tr("error_upload_failed"));
|
||||||
}
|
}
|
||||||
|
|
||||||
(new Albums)->getUserAvatarAlbum($this->user->identity)->addPhoto($photo);
|
$album = (new Albums)->getUserAvatarAlbum($this->user->identity);
|
||||||
|
$album->addPhoto($photo);
|
||||||
|
$album->setEdited(time());
|
||||||
|
$album->save();
|
||||||
|
|
||||||
$this->flashFail("succ", tr("photo_saved"), tr("photo_saved_comment"));
|
$this->flashFail("succ", tr("photo_saved"), tr("photo_saved_comment"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,7 +319,7 @@ final class UserPresenter extends OpenVKPresenter
|
||||||
if($this->postParam("old_pass") && $this->postParam("new_pass") && $this->postParam("repeat_pass")) {
|
if($this->postParam("old_pass") && $this->postParam("new_pass") && $this->postParam("repeat_pass")) {
|
||||||
if($this->postParam("new_pass") === $this->postParam("repeat_pass")) {
|
if($this->postParam("new_pass") === $this->postParam("repeat_pass")) {
|
||||||
if($this->user->identity->is2faEnabled()) {
|
if($this->user->identity->is2faEnabled()) {
|
||||||
$code = $this->postParam("code");
|
$code = $this->postParam("password_change_code");
|
||||||
if(!($code === (new Totp)->GenerateToken(Base32::decode($this->user->identity->get2faSecret())) || $this->user->identity->use2faBackupCode((int) $code)))
|
if(!($code === (new Totp)->GenerateToken(Base32::decode($this->user->identity->get2faSecret())) || $this->user->identity->use2faBackupCode((int) $code)))
|
||||||
$this->flashFail("err", tr("error"), tr("incorrect_2fa_code"));
|
$this->flashFail("err", tr("error"), tr("incorrect_2fa_code"));
|
||||||
}
|
}
|
||||||
|
@ -324,6 +331,46 @@ final class UserPresenter extends OpenVKPresenter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($this->postParam("new_email")) {
|
||||||
|
if(!Validator::i()->emailValid($this->postParam("new_email")))
|
||||||
|
$this->flashFail("err", tr("invalid_email_address"), tr("invalid_email_address_comment"));
|
||||||
|
|
||||||
|
if(!Authenticator::verifyHash($this->postParam("email_change_pass"), $user->getChandlerUser()->getRaw()->passwordHash))
|
||||||
|
$this->flashFail("err", tr("error"), tr("incorrect_password"));
|
||||||
|
|
||||||
|
if($user->is2faEnabled()) {
|
||||||
|
$code = $this->postParam("email_change_code");
|
||||||
|
if(!($code === (new Totp)->GenerateToken(Base32::decode($user->get2faSecret())) || $user->use2faBackupCode((int) $code)))
|
||||||
|
$this->flashFail("err", tr("error"), tr("incorrect_2fa_code"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if($this->postParam("new_email") !== $user->getEmail()) {
|
||||||
|
if (OPENVK_ROOT_CONF['openvk']['preferences']['security']['requireEmail']) {
|
||||||
|
$request = (new EmailChangeVerifications)->getLatestByUser($user);
|
||||||
|
if(!is_null($request) && $request->isNew())
|
||||||
|
$this->flashFail("err", tr("forbidden"), tr("email_rate_limit_error"));
|
||||||
|
|
||||||
|
$verification = new EmailChangeVerification;
|
||||||
|
$verification->setProfile($user->getId());
|
||||||
|
$verification->setNew_Email($this->postParam("new_email"));
|
||||||
|
$verification->save();
|
||||||
|
|
||||||
|
$params = [
|
||||||
|
"key" => $verification->getKey(),
|
||||||
|
"name" => $user->getCanonicalName(),
|
||||||
|
];
|
||||||
|
$this->sendmail($this->postParam("new_email"), "change-email", $params); #Vulnerability possible
|
||||||
|
$this->flashFail("succ", tr("information_-1"), tr("email_change_confirm_message"));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$user->changeEmail($this->postParam("new_email"));
|
||||||
|
} catch(UniqueConstraintViolationException $ex) {
|
||||||
|
$this->flashFail("err", tr("error"), tr("user_already_exists"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(!$user->setShortCode(empty($this->postParam("sc")) ? NULL : $this->postParam("sc")))
|
if(!$user->setShortCode(empty($this->postParam("sc")) ? NULL : $this->postParam("sc")))
|
||||||
$this->flashFail("err", tr("error"), tr("error_shorturl_incorrect"));
|
$this->flashFail("err", tr("error"), tr("error_shorturl_incorrect"));
|
||||||
} else if($_GET['act'] === "privacy") {
|
} else if($_GET['act'] === "privacy") {
|
||||||
|
@ -376,6 +423,9 @@ final class UserPresenter extends OpenVKPresenter
|
||||||
|
|
||||||
if(in_array($this->postParam("nsfw"), [0, 1, 2]))
|
if(in_array($this->postParam("nsfw"), [0, 1, 2]))
|
||||||
$user->setNsfwTolerance((int) $this->postParam("nsfw"));
|
$user->setNsfwTolerance((int) $this->postParam("nsfw"));
|
||||||
|
|
||||||
|
if(in_array($this->postParam("main_page"), [0, 1]))
|
||||||
|
$user->setMain_Page((int) $this->postParam("main_page"));
|
||||||
} else if($_GET['act'] === "lMenu") {
|
} else if($_GET['act'] === "lMenu") {
|
||||||
$settings = [
|
$settings = [
|
||||||
"menu_bildoj" => "photos",
|
"menu_bildoj" => "photos",
|
||||||
|
@ -400,20 +450,54 @@ final class UserPresenter extends OpenVKPresenter
|
||||||
throw $ex;
|
throw $ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->flash(
|
$this->flash("succ", tr("changes_saved"), tr("changes_saved_comment"));
|
||||||
"succ",
|
|
||||||
"Изменения сохранены",
|
|
||||||
"Новые данные появятся на вашей странице."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
$this->template->mode = in_array($this->queryParam("act"), [
|
$this->template->mode = in_array($this->queryParam("act"), [
|
||||||
"main", "privacy", "finance", "finance.top-up", "interface"
|
"main", "security", "privacy", "finance", "finance.top-up", "interface"
|
||||||
]) ? $this->queryParam("act")
|
]) ? $this->queryParam("act")
|
||||||
: "main";
|
: "main";
|
||||||
|
|
||||||
|
if($this->template->mode == "finance") {
|
||||||
|
$address = OPENVK_ROOT_CONF["openvk"]["preferences"]["ton"]["address"];
|
||||||
|
$text = str_replace("$1", (string) $this->user->identity->getId(), OPENVK_ROOT_CONF["openvk"]["preferences"]["ton"]["hint"]);
|
||||||
|
$qrCode = explode("base64,", (new QRCode(new QROptions([
|
||||||
|
"imageTransparent" => false
|
||||||
|
])))->render("ton://transfer/$address?text=$text"));
|
||||||
|
|
||||||
|
$this->template->qrCodeType = substr($qrCode[0], 5);
|
||||||
|
$this->template->qrCodeData = $qrCode[1];
|
||||||
|
}
|
||||||
|
|
||||||
$this->template->user = $user;
|
$this->template->user = $user;
|
||||||
$this->template->themes = Themepacks::i()->getThemeList();
|
$this->template->themes = Themepacks::i()->getThemeList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderDeactivate(): void
|
||||||
|
{
|
||||||
|
$this->assertUserLoggedIn();
|
||||||
|
$this->willExecuteWriteAction();
|
||||||
|
|
||||||
|
$flags = 0;
|
||||||
|
$reason = $this->postParam("deactivate_reason");
|
||||||
|
$share = $this->postParam("deactivate_share");
|
||||||
|
|
||||||
|
if($share) {
|
||||||
|
$flags |= 0b00100000;
|
||||||
|
|
||||||
|
$post = new Post;
|
||||||
|
$post->setOwner($this->user->id);
|
||||||
|
$post->setWall($this->user->id);
|
||||||
|
$post->setCreated(time());
|
||||||
|
$post->setContent($reason);
|
||||||
|
$post->setFlags($flags);
|
||||||
|
$post->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->user->identity->deactivate($reason);
|
||||||
|
|
||||||
|
$this->redirect("/");
|
||||||
|
}
|
||||||
|
|
||||||
function renderTwoFactorAuthSettings(): void
|
function renderTwoFactorAuthSettings(): void
|
||||||
{
|
{
|
||||||
$this->assertUserLoggedIn();
|
$this->assertUserLoggedIn();
|
||||||
|
@ -456,7 +540,7 @@ final class UserPresenter extends OpenVKPresenter
|
||||||
$this->template->secret = $secret;
|
$this->template->secret = $secret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Why are these crutch? For some reason, the QR code is not displayed if you just pass the render output to the view
|
# Why are these crutch? For some reason, the QR code is not displayed if you just pass the render output to the view
|
||||||
|
|
||||||
$issuer = OPENVK_ROOT_CONF["openvk"]["appearance"]["name"];
|
$issuer = OPENVK_ROOT_CONF["openvk"]["appearance"]["name"];
|
||||||
$email = $this->user->identity->getEmail();
|
$email = $this->user->identity->getEmail();
|
||||||
|
@ -481,11 +565,30 @@ final class UserPresenter extends OpenVKPresenter
|
||||||
$this->flashFail("succ", tr("information_-1"), tr("two_factor_authentication_disabled_message"));
|
$this->flashFail("succ", tr("information_-1"), tr("two_factor_authentication_disabled_message"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderResetThemepack(): void
|
||||||
|
{
|
||||||
|
$this->assertNoCSRF();
|
||||||
|
|
||||||
|
$this->setSessionTheme(Themepacks::DEFAULT_THEME_ID);
|
||||||
|
|
||||||
|
if($this->user) {
|
||||||
|
$this->willExecuteWriteAction();
|
||||||
|
|
||||||
|
$this->user->identity->setStyle(Themepacks::DEFAULT_THEME_ID);
|
||||||
|
$this->user->identity->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->redirect("/");
|
||||||
|
}
|
||||||
|
|
||||||
function renderCoinsTransfer(): void
|
function renderCoinsTransfer(): void
|
||||||
{
|
{
|
||||||
$this->assertUserLoggedIn();
|
$this->assertUserLoggedIn();
|
||||||
$this->willExecuteWriteAction();
|
$this->willExecuteWriteAction();
|
||||||
|
|
||||||
|
if(!OPENVK_ROOT_CONF["openvk"]["preferences"]["commerce"])
|
||||||
|
$this->flashFail("err", tr("error"), tr("feature_disabled"));
|
||||||
|
|
||||||
$receiverAddress = $this->postParam("receiver");
|
$receiverAddress = $this->postParam("receiver");
|
||||||
$value = (int) $this->postParam("value");
|
$value = (int) $this->postParam("value");
|
||||||
$message = $this->postParam("message");
|
$message = $this->postParam("message");
|
||||||
|
@ -558,4 +661,24 @@ final class UserPresenter extends OpenVKPresenter
|
||||||
|
|
||||||
$this->flashFail("succ", tr("information_-1"), tr("rating_increase_successful", $receiver->getURL(), htmlentities($receiver->getCanonicalName()), $value));
|
$this->flashFail("succ", tr("information_-1"), tr("rating_increase_successful", $receiver->getURL(), htmlentities($receiver->getCanonicalName()), $value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderEmailChangeFinish(): void
|
||||||
|
{
|
||||||
|
$request = (new EmailChangeVerifications)->getByToken(str_replace(" ", "+", $this->queryParam("key")));
|
||||||
|
if(!$request || !$request->isStillValid()) {
|
||||||
|
$this->flash("err", tr("token_manipulation_error"), tr("token_manipulation_error_comment"));
|
||||||
|
$this->redirect("/settings");
|
||||||
|
} else {
|
||||||
|
$request->delete(false);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$request->getUser()->changeEmail($request->getNewEmail());
|
||||||
|
} catch(UniqueConstraintViolationException $ex) {
|
||||||
|
$this->flashFail("err", tr("error"), tr("user_already_exists"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->flash("succ", tr("changes_saved"), tr("changes_saved_comment"));
|
||||||
|
$this->redirect("/settings");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,24 @@ final class VKAPIPresenter extends OpenVKPresenter
|
||||||
exit(json_encode($payload));
|
exit(json_encode($payload));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function twofaFail(int $userId): void
|
||||||
|
{
|
||||||
|
header("HTTP/1.1 401 Unauthorized");
|
||||||
|
header("Content-Type: application/json");
|
||||||
|
|
||||||
|
$payload = [
|
||||||
|
"error" => "need_validation",
|
||||||
|
"error_description" => "use app code",
|
||||||
|
"validation_type" => "2fa_app",
|
||||||
|
"validation_sid" => "2fa_".$userId."_2839041_randommessdontread",
|
||||||
|
"phone_mask" => "+374 ** *** 420",
|
||||||
|
"redirect_url" => "https://http.cat/418", // Not implemented yet :( So there is a photo of cat :3
|
||||||
|
"validation_resend" => "nowhere"
|
||||||
|
];
|
||||||
|
|
||||||
|
exit(json_encode($payload));
|
||||||
|
}
|
||||||
|
|
||||||
private function badMethod(string $object, string $method): void
|
private function badMethod(string $object, string $method): void
|
||||||
{
|
{
|
||||||
$this->fail(3, "Unknown method passed.", $object, $method);
|
$this->fail(3, "Unknown method passed.", $object, $method);
|
||||||
|
@ -249,8 +267,12 @@ final class VKAPIPresenter extends OpenVKPresenter
|
||||||
$user = (new Users)->get($uId);
|
$user = (new Users)->get($uId);
|
||||||
|
|
||||||
$code = $this->requestParam("code");
|
$code = $this->requestParam("code");
|
||||||
if($user->is2faEnabled() && !($code === (new Totp)->GenerateToken(Base32::decode($user->get2faSecret())) || $user->use2faBackupCode((int) $code)))
|
if($user->is2faEnabled() && !($code === (new Totp)->GenerateToken(Base32::decode($user->get2faSecret())) || $user->use2faBackupCode((int) $code))) {
|
||||||
|
if($this->requestParam("2fa_supported") == "1")
|
||||||
|
$this->twofaFail($user->getId());
|
||||||
|
else
|
||||||
$this->fail(28, "Invalid 2FA code", "internal", "acquireToken");
|
$this->fail(28, "Invalid 2FA code", "internal", "acquireToken");
|
||||||
|
}
|
||||||
|
|
||||||
$token = new APIToken;
|
$token = new APIToken;
|
||||||
$token->setUser($user);
|
$token->setUser($user);
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Presenters;
|
namespace openvk\Web\Presenters;
|
||||||
use openvk\Web\Models\Entities\Video;
|
use openvk\Web\Models\Entities\Video;
|
||||||
use openvk\Web\Models\Repositories\Users;
|
use openvk\Web\Models\Repositories\{Users, Videos};
|
||||||
use openvk\Web\Models\Repositories\Videos;
|
|
||||||
use Nette\InvalidStateException as ISE;
|
use Nette\InvalidStateException as ISE;
|
||||||
|
|
||||||
final class VideosPresenter extends OpenVKPresenter
|
final class VideosPresenter extends OpenVKPresenter
|
||||||
|
@ -80,7 +79,7 @@ final class VideosPresenter extends OpenVKPresenter
|
||||||
|
|
||||||
$video->save();
|
$video->save();
|
||||||
|
|
||||||
$this->redirect("/video" . $video->getPrettyId(), static::REDIRECT_TEMPORARY);
|
$this->redirect("/video" . $video->getPrettyId());
|
||||||
} else {
|
} else {
|
||||||
$this->flashFail("err", "Произошла ошибка", "Видео не может быть опубликовано без названия.");
|
$this->flashFail("err", "Произошла ошибка", "Видео не может быть опубликовано без названия.");
|
||||||
}
|
}
|
||||||
|
@ -104,7 +103,7 @@ final class VideosPresenter extends OpenVKPresenter
|
||||||
$video->save();
|
$video->save();
|
||||||
|
|
||||||
$this->flash("succ", "Изменения сохранены", "Обновлённое описание появится на странице с видосиком.");
|
$this->flash("succ", "Изменения сохранены", "Обновлённое описание появится на странице с видосиком.");
|
||||||
$this->redirect("/video" . $video->getPrettyId(), static::REDIRECT_TEMPORARY);
|
$this->redirect("/video" . $video->getPrettyId());
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->template->video = $video;
|
$this->template->video = $video;
|
||||||
|
@ -128,7 +127,6 @@ final class VideosPresenter extends OpenVKPresenter
|
||||||
$this->flashFail("err", "Не удалось удалить пост", "Вы не вошли в аккаунт.");
|
$this->flashFail("err", "Не удалось удалить пост", "Вы не вошли в аккаунт.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->redirect("/videos".$owner, static::REDIRECT_TEMPORARY);
|
$this->redirect("/videos" . $owner);
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,14 +113,14 @@ final class WallPresenter extends OpenVKPresenter
|
||||||
$feed = new Feed();
|
$feed = new Feed();
|
||||||
|
|
||||||
$channel = new Channel();
|
$channel = new Channel();
|
||||||
$channel->title(OPENVK_ROOT_CONF['openvk']['appearance']['name'])->url(ovk_scheme(true) . $_SERVER["SERVER_NAME"])->appendTo($feed);
|
$channel->title($owner->getCanonicalName() . " — " . OPENVK_ROOT_CONF['openvk']['appearance']['name'])->url(ovk_scheme(true) . $_SERVER["HTTP_HOST"])->appendTo($feed);
|
||||||
|
|
||||||
foreach($posts as $post) {
|
foreach($posts as $post) {
|
||||||
$item = new Item();
|
$item = new Item();
|
||||||
$item
|
$item
|
||||||
->title($post->getOwner()->getCanonicalName())
|
->title($post->getOwner()->getCanonicalName())
|
||||||
->description($post->getText())
|
->description($post->getText())
|
||||||
->url(ovk_scheme(true).$_SERVER["SERVER_NAME"]."/wall{$post->getPrettyId()}")
|
->url(ovk_scheme(true).$_SERVER["HTTP_HOST"]."/wall{$post->getPrettyId()}")
|
||||||
->pubDate($post->getPublicationTime()->timestamp())
|
->pubDate($post->getPublicationTime()->timestamp())
|
||||||
->appendTo($channel);
|
->appendTo($channel);
|
||||||
}
|
}
|
||||||
|
@ -294,17 +294,11 @@ final class WallPresenter extends OpenVKPresenter
|
||||||
if($wall > 0 && $wall !== $this->user->identity->getId())
|
if($wall > 0 && $wall !== $this->user->identity->getId())
|
||||||
(new WallPostNotification($wallOwner, $post, $this->user->identity))->emit();
|
(new WallPostNotification($wallOwner, $post, $this->user->identity))->emit();
|
||||||
|
|
||||||
if($wall > 0)
|
$this->redirect($wallOwner->getURL());
|
||||||
$this->redirect("/id$wall", 2); #Will exit
|
|
||||||
|
|
||||||
$wall = $wall * -1;
|
|
||||||
$this->redirect("/club$wall", 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderPost(int $wall, int $post_id): void
|
function renderPost(int $wall, int $post_id): void
|
||||||
{
|
{
|
||||||
$this->assertUserLoggedIn();
|
|
||||||
|
|
||||||
$post = $this->posts->getPostById($wall, $post_id);
|
$post = $this->posts->getPostById($wall, $post_id);
|
||||||
if(!$post || $post->isDeleted())
|
if(!$post || $post->isDeleted())
|
||||||
$this->notFound();
|
$this->notFound();
|
||||||
|
@ -339,10 +333,7 @@ final class WallPresenter extends OpenVKPresenter
|
||||||
$post->toggleLike($this->user->identity);
|
$post->toggleLike($this->user->identity);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->redirect(
|
$this->redirect("$_SERVER[HTTP_REFERER]#postGarter=" . $post->getId());
|
||||||
"$_SERVER[HTTP_REFERER]#postGarter=" . $post->getId(),
|
|
||||||
static::REDIRECT_TEMPORARY
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderShare(int $wall, int $post_id): void
|
function renderShare(int $wall, int $post_id): void
|
||||||
|
@ -394,8 +385,7 @@ final class WallPresenter extends OpenVKPresenter
|
||||||
$this->flashFail("err", tr("failed_to_delete_post"), tr("login_required_error_comment"));
|
$this->flashFail("err", tr("failed_to_delete_post"), tr("login_required_error_comment"));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->redirect($wall < 0 ? "/club".($wall*-1) : "/id".$wall, static::REDIRECT_TEMPORARY);
|
$this->redirect($wall < 0 ? "/club" . ($wall*-1) : "/id" . $wall);
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderPin(int $wall, int $post_id): void
|
function renderPin(int $wall, int $post_id): void
|
||||||
|
@ -416,7 +406,7 @@ final class WallPresenter extends OpenVKPresenter
|
||||||
$post->unpin();
|
$post->unpin();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO localize message based on language and ?act=(un)pin
|
# TODO localize message based on language and ?act=(un)pin
|
||||||
$this->flashFail("succ", tr("information_-1"), tr("changes_saved_comment"));
|
$this->flashFail("succ", tr("information_-1"), tr("changes_saved_comment"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container_gray">
|
<div class="container_gray">
|
||||||
{var data = is_array($iterator) ? $iterator : iterator_to_array($iterator)}
|
{var $data = is_array($iterator) ? $iterator : iterator_to_array($iterator)}
|
||||||
|
|
||||||
{if sizeof($data) > 0}
|
{if sizeof($data) > 0}
|
||||||
<div class="content" n:foreach="$data as $dat">
|
<div class="content" n:foreach="$data as $dat">
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
{block wrap}
|
{block wrap}
|
||||||
<div class="ovk-lw-container">
|
<div class="ovk-lw-container">
|
||||||
<div class="ovk-lw--list">
|
<div class="ovk-lw--list">
|
||||||
{var data = is_array($iterator) ? $iterator : iterator_to_array($iterator)}
|
{var $data = is_array($iterator) ? $iterator : iterator_to_array($iterator)}
|
||||||
|
|
||||||
{if sizeof($data) > 0}
|
{if sizeof($data) > 0}
|
||||||
<table n:foreach="$data as $dat" border="0" style="font-size:11px;" class="post">
|
<table n:foreach="$data as $dat" border="0" style="font-size:11px;" class="post">
|
||||||
|
@ -52,9 +52,9 @@
|
||||||
{include actions}
|
{include actions}
|
||||||
<hr/>
|
<hr/>
|
||||||
<div n:if="$sorting ?? true" class="tile">
|
<div n:if="$sorting ?? true" class="tile">
|
||||||
<a href="?C=I;O=R" class="profile_link">{_"sort_randomly"}</a>
|
<a href="?C=I;O=R" class="profile_link">{_sort_randomly}</a>
|
||||||
<a href="?C=M;O=D" class="profile_link">{_"sort_up"}</a>
|
<a href="?C=M;O=D" class="profile_link">{_sort_up}</a>
|
||||||
<a href="?C=M;O=A" class="profile_link">{_"sort_down"}</a>
|
<a href="?C=M;O=A" class="profile_link">{_sort_down}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,17 +1,27 @@
|
||||||
{extends "@layout.xml"}
|
{extends "@layout.xml"}
|
||||||
{block title}{_"banned_title"}{/block}
|
{block title}{_banned_title}{/block}
|
||||||
|
|
||||||
{block header}
|
{block header}
|
||||||
{_"banned_header"}
|
{_banned_header}
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
{block content}
|
{block content}
|
||||||
<center>
|
<center>
|
||||||
<img src="/assets/packages/static/openvk/img/oof.apng" alt="{_'banned_alt'}" style="width: 20%;" />
|
<img src="/assets/packages/static/openvk/img/oof.apng" alt="{_banned_alt}" style="width: 20%;" />
|
||||||
</center>
|
</center>
|
||||||
<p>
|
<p>
|
||||||
{tr("banned_1", htmlentities($thisUser->getCanonicalName()))|noescape}<br/>
|
{tr("banned_1", htmlentities($thisUser->getCanonicalName()))|noescape}<br/>
|
||||||
{tr("banned_2", htmlentities($thisUser->getBanReason()))|noescape}
|
{tr("banned_2", htmlentities($thisUser->getBanReason()))|noescape}
|
||||||
|
|
||||||
|
{if !$thisUser->getUnbanTime()}
|
||||||
|
{_banned_perm}
|
||||||
|
{else}
|
||||||
|
{tr("banned_until_time", $thisUser->getUnbanTime())|noescape}
|
||||||
|
{/if}
|
||||||
|
</p>
|
||||||
|
<p n:if="$thisUser->canUnbanThemself()">
|
||||||
|
<hr/>
|
||||||
|
<center><a class="button" href="/unban.php">{_banned_unban_myself}</a></center>
|
||||||
</p>
|
</p>
|
||||||
<hr/>
|
<hr/>
|
||||||
<p>
|
<p>
|
||||||
|
|
34
Web/Presenters/templates/@deactivated.xml
Normal file
34
Web/Presenters/templates/@deactivated.xml
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
{extends "@layout.xml"}
|
||||||
|
{block title}{$thisUser->getCanonicalName()}{/block}
|
||||||
|
|
||||||
|
{block header}
|
||||||
|
{$thisUser->getCanonicalName()}
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block content}
|
||||||
|
<div class="container_gray bottom" style="margin: -10px -10px 10px;">
|
||||||
|
{tr("profile_deactivated_msg", $thisUser->getDeactivationDate()->format("%e %B %G" . tr("time_at_sp") . "%R"))|noescape}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="left_small_block">
|
||||||
|
<div>
|
||||||
|
<img src="{$thisUser->getAvatarUrl('normal')}"
|
||||||
|
alt="{$thisUser->getCanonicalName()}"
|
||||||
|
style="width: 100%; image-rendering: -webkit-optimize-contrast;" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="right_big_block">
|
||||||
|
<div class="page_info">
|
||||||
|
<div class="accountInfo clearFix">
|
||||||
|
<div class="profileName">
|
||||||
|
<h2>{$thisUser->getFullName()}</h2>
|
||||||
|
<div class="page_status" style="color: #AAA;">{_profile_deactivated_status}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<center style="color: #AAA; margin: 40px 0; font-size: 13px;">
|
||||||
|
{_profile_deactivated_info|noescape}
|
||||||
|
</center>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/block}
|
|
@ -1,5 +1,4 @@
|
||||||
{var instance_name = OPENVK_ROOT_CONF['openvk']['appearance']['name']}
|
{var $instance_name = OPENVK_ROOT_CONF['openvk']['appearance']['name']}
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{var instance_name = OPENVK_ROOT_CONF['openvk']['appearance']['name']}
|
{var $instance_name = OPENVK_ROOT_CONF['openvk']['appearance']['name']}
|
||||||
|
{if !isset($parentModule) || substr($parentModule, 0, 21) === 'libchandler:absolute.'}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html n:if="!isset($parentModule) || substr($parentModule, 0, 21) === 'libchandler:absolute.'">
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>
|
<title>
|
||||||
{ifset title}{include title} - {/ifset}{$instance_name}
|
{ifset title}{include title} - {/ifset}{$instance_name}
|
||||||
|
@ -17,7 +17,7 @@
|
||||||
{script "js/l10n.js"}
|
{script "js/l10n.js"}
|
||||||
{script "js/openvk.cls.js"}
|
{script "js/openvk.cls.js"}
|
||||||
|
|
||||||
{if $isTimezoned == null}
|
{if $isTimezoned == NULL}
|
||||||
{script "js/timezone.js"}
|
{script "js/timezone.js"}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
{css "css/nsfw-posts.css"}
|
{css "css/nsfw-posts.css"}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{if $theme !== null}
|
{if $theme !== NULL}
|
||||||
{if $theme->inheritDefault()}
|
{if $theme->inheritDefault()}
|
||||||
{css "css/style.css"}
|
{css "css/style.css"}
|
||||||
{css "css/dialog.css"}
|
{css "css/dialog.css"}
|
||||||
|
@ -102,8 +102,13 @@
|
||||||
<a href="/" class="home_button{if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME} home_button_custom{/if}" title="{$instance_name}">{if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME}{$instance_name}{/if}</a>
|
<a href="/" class="home_button{if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME} home_button_custom{/if}" title="{$instance_name}">{if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME}{$instance_name}{/if}</a>
|
||||||
<div n:if="isset($thisUser) ? (!$thisUser->isBanned() XOR !$thisUser->isActivated()) : true" class="header_navigation">
|
<div n:if="isset($thisUser) ? (!$thisUser->isBanned() XOR !$thisUser->isActivated()) : true" class="header_navigation">
|
||||||
{ifset $thisUser}
|
{ifset $thisUser}
|
||||||
|
{if $thisUser->isDeactivated()}
|
||||||
<div class="link">
|
<div class="link">
|
||||||
<a href="/" title="[Alt+Shift+,]" accesskey=",">{_header_home}</a>
|
<a href="/logout?hash={urlencode($csrfToken)}">{_header_log_out}</a>
|
||||||
|
</div>
|
||||||
|
{else}
|
||||||
|
<div class="link">
|
||||||
|
<a href="/">{_header_home}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="link">
|
<div class="link">
|
||||||
<a href="/search?type=groups">{_header_groups}</a>
|
<a href="/search?type=groups">{_header_groups}</a>
|
||||||
|
@ -125,6 +130,7 @@
|
||||||
<input type="search" name="query" placeholder="{_header_search}" style="height: 20px;background: url('/assets/packages/static/openvk/img/search_icon.png') no-repeat 3px 4px; background-color: #fff; padding-left: 18px;width: 120px;" title="{_header_search} [Alt+Shift+F]" accesskey="f" />
|
<input type="search" name="query" placeholder="{_header_search}" style="height: 20px;background: url('/assets/packages/static/openvk/img/search_icon.png') no-repeat 3px 4px; background-color: #fff; padding-left: 18px;width: 120px;" title="{_header_search} [Alt+Shift+F]" accesskey="f" />
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
{else}
|
{else}
|
||||||
<div class="link">
|
<div class="link">
|
||||||
<a href="/login">{_header_login}</a>
|
<a href="/login">{_header_login}</a>
|
||||||
|
@ -142,7 +148,7 @@
|
||||||
<div class="sidebar">
|
<div class="sidebar">
|
||||||
<div class="navigation">
|
<div class="navigation">
|
||||||
{ifset $thisUser}
|
{ifset $thisUser}
|
||||||
{if !$thisUser->isBanned() XOR !$thisUser->isActivated()}
|
{if !$thisUser->isBanned() XOR !$thisUser->isActivated() XOR $thisUser->isDeactivated()}
|
||||||
<a href="/edit" class="link edit-button">{_edit_button}</a>
|
<a href="/edit" class="link edit-button">{_edit_button}</a>
|
||||||
<a href="{$thisUser->getURL()}" class="link" title="{_my_page} [Alt+Shift+.]" accesskey=".">{_my_page}</a>
|
<a href="{$thisUser->getURL()}" class="link" title="{_my_page} [Alt+Shift+.]" accesskey=".">{_my_page}</a>
|
||||||
<a href="/friends{$thisUser->getId()}" class="link">{_my_friends}
|
<a href="/friends{$thisUser->getId()}" class="link">{_my_friends}
|
||||||
|
@ -161,19 +167,20 @@
|
||||||
</a>
|
</a>
|
||||||
<a n:if="$thisUser->getLeftMenuItemStatus('notes')" href="/notes{$thisUser->getId()}" class="link">{_my_notes}</a>
|
<a n:if="$thisUser->getLeftMenuItemStatus('notes')" href="/notes{$thisUser->getId()}" class="link">{_my_notes}</a>
|
||||||
<a n:if="$thisUser->getLeftMenuItemStatus('groups')" href="/groups{$thisUser->getId()}" class="link">{_my_groups}</a>
|
<a n:if="$thisUser->getLeftMenuItemStatus('groups')" href="/groups{$thisUser->getId()}" class="link">{_my_groups}</a>
|
||||||
<a n:if="$thisUser->getLeftMenuItemStatus('news')" href="/feed" class="link" title="{_my_feed} [Alt+Shift+W]" accesskey="w">{_my_feed}</a>
|
<a n:if="$thisUser->getLeftMenuItemStatus('news')" href="/feed" class="link" title="{_my_feed} [Alt+Shift+,]" accesskey=",">{_my_feed}</a>
|
||||||
<a href="/notifications" class="link" title="{_my_feedback} [Alt+Shift+N]" accesskey="n">{_my_feedback}
|
<a href="/notifications" class="link" title="{_my_feedback} [Alt+Shift+N]" accesskey="n">{_my_feedback}
|
||||||
{if $thisUser->getNotificationsCount() > 0}
|
{if $thisUser->getNotificationsCount() > 0}
|
||||||
(<b>{$thisUser->getNotificationsCount()}</b>)
|
(<b>{$thisUser->getNotificationsCount()}</b>)
|
||||||
{/if}
|
{/if}
|
||||||
</a>
|
</a>
|
||||||
|
<a href="/apps?act=installed" class="link">{_my_apps}</a>
|
||||||
<a href="/settings" class="link">{_my_settings}</a>
|
<a href="/settings" class="link">{_my_settings}</a>
|
||||||
|
|
||||||
{var canAccessAdminPanel = $thisUser->getChandlerUser()->can("access")->model("admin")->whichBelongsTo(NULL)}
|
{var $canAccessAdminPanel = $thisUser->getChandlerUser()->can("access")->model("admin")->whichBelongsTo(NULL)}
|
||||||
{var canAccessHelpdesk = $thisUser->getChandlerUser()->can("write")->model('openvk\Web\Models\Entities\TicketReply')->whichBelongsTo(0)}
|
{var $canAccessHelpdesk = $thisUser->getChandlerUser()->can("write")->model('openvk\Web\Models\Entities\TicketReply')->whichBelongsTo(0)}
|
||||||
{var menuLinksAvaiable = sizeof(OPENVK_ROOT_CONF['openvk']['preferences']['menu']['links']) > 0 && $thisUser->getLeftMenuItemStatus('links')}
|
{var $menuLinksAvaiable = sizeof(OPENVK_ROOT_CONF['openvk']['preferences']['menu']['links']) > 0 && $thisUser->getLeftMenuItemStatus('links')}
|
||||||
<div n:if="$canAccessAdminPanel || $canAccessHelpdesk || $menuLinksAvaiable" class="menu_divider"></div>
|
<div n:if="$canAccessAdminPanel || $canAccessHelpdesk || $menuLinksAvaiable" class="menu_divider"></div>
|
||||||
<a href="/admin" class="link" n:if="$canAccessAdminPanel" title="Админ-панель [Alt+Shift+A]" accesskey="a">Админ-панель</a>
|
<a href="/admin" class="link" n:if="$canAccessAdminPanel" title="{_admin} [Alt+Shift+A]" accesskey="a">{_admin}</a>
|
||||||
<a href="/support/tickets" class="link" n:if="$canAccessHelpdesk">Helpdesk
|
<a href="/support/tickets" class="link" n:if="$canAccessHelpdesk">Helpdesk
|
||||||
{if $helpdeskTicketNotAnsweredCount > 0}
|
{if $helpdeskTicketNotAnsweredCount > 0}
|
||||||
(<b>{$helpdeskTicketNotAnsweredCount}</b>)
|
(<b>{$helpdeskTicketNotAnsweredCount}</b>)
|
||||||
|
@ -186,9 +193,50 @@
|
||||||
<div n:if="$thisUser->getPinnedClubCount() > 0" class="menu_divider"></div>
|
<div n:if="$thisUser->getPinnedClubCount() > 0" class="menu_divider"></div>
|
||||||
<a n:foreach="$thisUser->getPinnedClubs() as $club" href="{$club->getURL()}" class="link group_link">{$club->getName()}</a>
|
<a n:foreach="$thisUser->getPinnedClubs() as $club" href="{$club->getURL()}" class="link group_link">{$club->getName()}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div n:if="OPENVK_ROOT_CONF['openvk']['preferences']['commerce'] && $thisUser->getCoins() != 0" id="votesBalance">
|
||||||
|
{tr("you_still_have_x_points", $thisUser->getCoins())|noescape}
|
||||||
|
<br /><br />
|
||||||
|
|
||||||
|
<a href="/settings?act=finance">{_top_up_your_account} »</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a n:if="OPENVK_ROOT_CONF['openvk']['preferences']['adPoster']['enable'] && $thisUser->getLeftMenuItemStatus('poster')" href="{php echo OPENVK_ROOT_CONF['openvk']['preferences']['adPoster']['link']}" >
|
<a n:if="OPENVK_ROOT_CONF['openvk']['preferences']['adPoster']['enable'] && $thisUser->getLeftMenuItemStatus('poster')" href="{php echo OPENVK_ROOT_CONF['openvk']['preferences']['adPoster']['link']}" >
|
||||||
<img src="{php echo OPENVK_ROOT_CONF['openvk']['preferences']['adPoster']['src']}" alt="{php echo OPENVK_ROOT_CONF['openvk']['preferences']['adPoster']['caption']}" class="psa-poster" style="max-width: 100%; margin-top: 50px;" />
|
<img src="{php echo OPENVK_ROOT_CONF['openvk']['preferences']['adPoster']['src']}" alt="{php echo OPENVK_ROOT_CONF['openvk']['preferences']['adPoster']['caption']}" class="psa-poster" style="max-width: 100%; margin-top: 10px;" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
<div class="floating_sidebar">
|
||||||
|
<a class="minilink" href="/friends{$thisUser->getId()}">
|
||||||
|
<object type="internal/link" n:if="$thisUser->getFollowersCount() > 0">
|
||||||
|
<div class="counter">
|
||||||
|
+{$thisUser->getFollowersCount()}
|
||||||
|
</div>
|
||||||
|
</object>
|
||||||
|
<img src="/assets/packages/static/openvk/img/friends.svg">
|
||||||
|
</a>
|
||||||
|
<a class="minilink" href="/albums{$thisUser->getId()}">
|
||||||
|
<img src="/assets/packages/static/openvk/img/photos.svg">
|
||||||
|
</a>
|
||||||
|
<a class="minilink" href="/im">
|
||||||
|
<object type="internal/link" n:if="$thisUser->getUnreadMessagesCount() > 0">
|
||||||
|
<div class="counter">
|
||||||
|
+{$thisUser->getUnreadMessagesCount()}
|
||||||
|
</div>
|
||||||
|
</object>
|
||||||
|
<img src="/assets/packages/static/openvk/img/messages.svg">
|
||||||
|
</a>
|
||||||
|
<a class="minilink" href="/groups{$thisUser->getId()}">
|
||||||
|
<img src="/assets/packages/static/openvk/img/groups.svg">
|
||||||
|
</a>
|
||||||
|
<a class="minilink" href="/notifications">
|
||||||
|
<object type="internal/link" n:if="$thisUser->getNotificationsCount() > 0">
|
||||||
|
<div class="counter">
|
||||||
|
+{$thisUser->getNotificationsCount()}
|
||||||
|
</div>
|
||||||
|
</object>
|
||||||
|
<img src="/assets/packages/static/openvk/img/feedback.svg">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
{elseif !$thisUser->isActivated()}
|
{elseif !$thisUser->isActivated()}
|
||||||
<a href="/logout?hash={urlencode($csrfToken)}" class="link">{_menu_logout}</a>
|
<a href="/logout?hash={urlencode($csrfToken)}" class="link">{_menu_logout}</a>
|
||||||
{else}
|
{else}
|
||||||
|
@ -251,7 +299,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="page_footer">
|
<div class="page_footer">
|
||||||
{var dbVersion = \Chandler\Database\DatabaseConnection::i()->getConnection()->getPdo()->getAttribute(\PDO::ATTR_SERVER_VERSION)}
|
{var $dbVersion = \Chandler\Database\DatabaseConnection::i()->getConnection()->getPdo()->getAttribute(\PDO::ATTR_SERVER_VERSION)}
|
||||||
|
|
||||||
<div class="navigation_footer">
|
<div class="navigation_footer">
|
||||||
<a href="/about" class="link">{_footer_about_instance}</a>
|
<a href="/about" class="link">{_footer_about_instance}</a>
|
||||||
|
@ -267,6 +315,8 @@
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{include "components/cookies.xml"}
|
||||||
|
|
||||||
{script "js/node_modules/msgpack-lite/dist/msgpack.min.js"}
|
{script "js/node_modules/msgpack-lite/dist/msgpack.min.js"}
|
||||||
{script "js/node_modules/soundjs/lib/soundjs.min.js"}
|
{script "js/node_modules/soundjs/lib/soundjs.min.js"}
|
||||||
{script "js/node_modules/ky/umd.js"}
|
{script "js/node_modules/ky/umd.js"}
|
||||||
|
@ -325,6 +375,7 @@
|
||||||
{/ifset}
|
{/ifset}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
{/if}
|
||||||
|
|
||||||
{if isset($parentModule) && substr($parentModule, 0, 21) !== 'libchandler:absolute.'}
|
{if isset($parentModule) && substr($parentModule, 0, 21) !== 'libchandler:absolute.'}
|
||||||
<!-- INCLUDING TEMPLATE FROM PARENTMODULE: {$parentModule} -->
|
<!-- INCLUDING TEMPLATE FROM PARENTMODULE: {$parentModule} -->
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<div class="wrap2">
|
<div class="wrap2">
|
||||||
<div class="wrap1">
|
<div class="wrap1">
|
||||||
<div class="page_wrap padding_top">
|
<div class="page_wrap padding_top">
|
||||||
<div n:ifset="tabs" class="tabs">
|
<div n:ifset="tabs" n:ifcontent class="tabs stupid-fix">
|
||||||
{include tabs}
|
{include tabs}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
{include specpage, x => $dat}
|
{include specpage, x => $dat}
|
||||||
{else}
|
{else}
|
||||||
<div class="container_gray">
|
<div class="container_gray">
|
||||||
{var data = is_array($iterator) ? $iterator : iterator_to_array($iterator)}
|
{var $data = is_array($iterator) ? $iterator : iterator_to_array($iterator)}
|
||||||
|
|
||||||
{if sizeof($data) > 0}
|
{if sizeof($data) > 0}
|
||||||
<div class="content" n:foreach="$data as $dat">
|
<div class="content" n:foreach="$data as $dat">
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
{include description, x => $dat}
|
{include description, x => $dat}
|
||||||
{/ifset}
|
{/ifset}
|
||||||
</td>
|
</td>
|
||||||
<td n:ifset="actions" valign="top" class="action_links" style="width: 150px; text-transform: lowercase;">
|
<td n:ifset="actions" valign="top" class="action_links" style="width: 150px;">
|
||||||
{include actions, x => $dat}
|
{include actions, x => $dat}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -21,6 +21,15 @@
|
||||||
<li><span>{tr("about_wall_posts", $postsCount)|noescape}</span></li>
|
<li><span>{tr("about_wall_posts", $postsCount)|noescape}</span></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
{if OPENVK_ROOT_CONF['openvk']['preferences']['about']['links']}
|
||||||
|
<h4>{_about_links}</h4>
|
||||||
|
<div style="margin-top: 5px;">
|
||||||
|
{_instance_links}
|
||||||
|
<ul>
|
||||||
|
<li n:foreach="OPENVK_ROOT_CONF['openvk']['preferences']['about']['links'] as $aboutLink"><a href="{$aboutLink['url']}" target="_blank" class="link">{$aboutLink["name"]}</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</td>
|
</td>
|
||||||
<td n:if="sizeof($admins) > 0">
|
<td n:if="sizeof($admins) > 0">
|
||||||
<h4>{_administrators}</h4>
|
<h4>{_administrators}</h4>
|
||||||
|
@ -44,14 +53,23 @@
|
||||||
|
|
||||||
{if sizeof($popularClubs) !== 0}
|
{if sizeof($popularClubs) !== 0}
|
||||||
<h4>{_most_popular_groups}</h4>
|
<h4>{_most_popular_groups}</h4>
|
||||||
|
{var $entries = array_chunk($popularClubs, 10, true)}
|
||||||
|
<table width="100%" cellspacing="0" cellpadding="0">
|
||||||
|
<tbody>
|
||||||
|
<tr valign="top">
|
||||||
|
<td n:foreach="$entries as $chunk">
|
||||||
<ol>
|
<ol>
|
||||||
<li n:foreach="$popularClubs as $entry" style="margin-top: 5px;">
|
<li value="{$num+1}" style="margin-top: 5px;" n:foreach="$chunk as $num => $club">
|
||||||
<a href="{$entry->club->getURL()}">{$entry->club->getName()}</a>
|
<a href="{$club->club->getURL()}">{$club->club->getName()}</a>
|
||||||
<div>
|
<div>
|
||||||
{tr("participants", $entry->subscriptions)}
|
{tr("participants", $club->subscriptions)}
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<h4>{_rules}</h4>
|
<h4>{_rules}</h4>
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
{extends "../@layout.xml"}
|
{extends "../@layout.xml"}
|
||||||
{block title}{_"welcome"}{/block}
|
{block title}{_welcome}{/block}
|
||||||
|
|
||||||
{block header}
|
{block header}
|
||||||
{_"welcome"}
|
{_welcome}
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
{block content}
|
{block content}
|
||||||
{presenter "openvk!Support->knowledgeBaseArticle", "about"}
|
{presenter "openvk!Support->knowledgeBaseArticle", "about"}
|
||||||
<center>
|
<center>
|
||||||
<a class="button" style="margin-right: 5px;cursor: pointer;" href="/login">{_"log_in"}</a>
|
<a class="button" style="margin-right: 5px;cursor: pointer;" href="/login">{_log_in}</a>
|
||||||
<a class="button" style="cursor: pointer;" href="/reg">{_"registration"}</a>
|
<a class="button" style="cursor: pointer;" href="/reg">{_registration}</a>
|
||||||
</center>
|
</center>
|
||||||
{* TO-DO: Add statistics about this instance as on mastodon.social *}
|
{* TO-DO: Add statistics about this instance as on mastodon.social *}
|
||||||
{/block}
|
{/block}
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
{block content}
|
{block content}
|
||||||
{_"you_can_invite"}<br><br>
|
{_you_can_invite}<br><br>
|
||||||
<center>
|
<center>
|
||||||
<input type="text" readonly value="https://{$_SERVER["HTTP_HOST"]}/reg?ref={rawurlencode($thisUser->getRefLinkId())}" size="50" />
|
<input type="text" readonly value="https://{$_SERVER["HTTP_HOST"]}/reg?ref={rawurlencode($thisUser->getRefLinkId())}" size="50" />
|
||||||
</center>
|
</center>
|
||||||
<p>{_"you_can_invite_2"}</p>
|
<p>{_you_can_invite_2}</p>
|
||||||
{/block}
|
{/block}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
{extends "../@layout.xml"}
|
{extends "../@layout.xml"}
|
||||||
{block title}{_"select_language"}{/block}
|
{block title}{_select_language}{/block}
|
||||||
|
|
||||||
{block header}
|
{block header}
|
||||||
{_"select_language"}
|
{_select_language}
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
{block content}
|
{block content}
|
||||||
|
|
|
@ -396,8 +396,8 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td class="e">
|
<td class="e">
|
||||||
Vladimir Barinov (veselcraft), Celestora, Konstantin Kichulkin (kosfurler),
|
Vladimir Barinov (veselcraft), Celestora, Konstantin Kichulkin (kosfurler),
|
||||||
Nikita Volkov (sup_ban), Daniel Myslivets, Alexander Kotov (l-lacker),
|
Nikita Volkov (sup_ban), Daniel Myslivets, Maxim Leshchenko (maksales / maksalees)
|
||||||
Alexey Assemblerov (BiosNod), Ilya Prokopenko (dsrev) and Maxim Leshchenko (maksales / maksalees)
|
and n1rwana
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -474,7 +474,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="e">Best barmaid</td>
|
<td class="e">Best barmaid</td>
|
||||||
<td class="v">Jill</td> {* I can agree ~~ dsrev *}
|
<td class="v">Jill</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="e">Initial Helpdesk implementation</td>
|
<td class="e">Initial Helpdesk implementation</td>
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
|
{var $instance_name = OPENVK_ROOT_CONF['openvk']['appearance']['name']}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
|
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
|
||||||
<style>
|
<style>
|
||||||
{var css = file_get_contents(OPENVK_ROOT . "/Web/static/js/node_modules/@atlassian/aui/dist/aui/aui-prototyping.css")}
|
{var $css = file_get_contents(OPENVK_ROOT . "/Web/static/js/node_modules/@atlassian/aui/dist/aui/aui-prototyping.css")}
|
||||||
{str_replace("fonts/", "/assets/packages/static/openvk/js/node_modules/@atlassian/aui/dist/aui/fonts/", $css)|noescape}
|
{str_replace("fonts/", "/assets/packages/static/openvk/js/node_modules/@atlassian/aui/dist/aui/fonts/", $css)|noescape}
|
||||||
</style>
|
</style>
|
||||||
<title>{include title} - Админ-панель {=OPENVK_ROOT_CONF['openvk']['appearance']['name']}</title>
|
<title>{include title} - {_admin} {$instance_name}</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="page">
|
<div id="page">
|
||||||
|
@ -15,23 +16,15 @@
|
||||||
<div class="aui-header-inner">
|
<div class="aui-header-inner">
|
||||||
<div class="aui-header-primary">
|
<div class="aui-header-primary">
|
||||||
<h1 id="logo" class="aui-header-logo aui-header-logo-textonly">
|
<h1 id="logo" class="aui-header-logo aui-header-logo-textonly">
|
||||||
<a href="/admin">
|
<a href="/">
|
||||||
<span class="aui-header-logo-device">{=OPENVK_ROOT_CONF['openvk']['appearance']['name']}</span>
|
<span class="aui-header-logo-device">{$instance_name}</span>
|
||||||
</a>
|
</a>
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<div n:if="$search ?? false" class="aui-header-secondary">
|
<div n:if="$search ?? false" class="aui-header-secondary">
|
||||||
<ul class="aui-nav">
|
<ul class="aui-nav">
|
||||||
<form class="aui-quicksearch dont-default-focus ajs-dirty-warning-exempt">
|
<form class="aui-quicksearch dont-default-focus ajs-dirty-warning-exempt">
|
||||||
<input
|
<input id="quickSearchInput" autocomplete="off" class="search" type="text" placeholder="{include searchTitle}" value="{$_GET['q'] ?? ''}" name="q" accesskey="Q" />
|
||||||
id="quickSearchInput"
|
|
||||||
autocomplete="off"
|
|
||||||
class="search"
|
|
||||||
type="text"
|
|
||||||
placeholder="{include searchTitle}"
|
|
||||||
value="{$_GET['q'] ?? ''}"
|
|
||||||
name="q"
|
|
||||||
accesskey="Q" />
|
|
||||||
<input type="hidden" value=1 name=p />
|
<input type="hidden" value=1 name=p />
|
||||||
</form>
|
</form>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -46,83 +39,67 @@
|
||||||
<div class="aui-navgroup-inner">
|
<div class="aui-navgroup-inner">
|
||||||
<div class="aui-navgroup-primary">
|
<div class="aui-navgroup-primary">
|
||||||
<div class="aui-nav-heading">
|
<div class="aui-nav-heading">
|
||||||
<strong>Обзор</strong>
|
<strong>{_admin_overview}</strong>
|
||||||
</div>
|
</div>
|
||||||
<ul class="aui-nav">
|
<ul class="aui-nav">
|
||||||
<li>
|
<li>
|
||||||
<a href="/admin">
|
<a href="/admin">{_admin_overview_summary}</a>
|
||||||
Сводка
|
|
||||||
</a>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="aui-nav-heading">
|
<div class="aui-nav-heading">
|
||||||
<strong>Пользовательский контент</strong>
|
<strong>{_admin_content}</strong>
|
||||||
</div>
|
</div>
|
||||||
<ul class="aui-nav">
|
<ul class="aui-nav">
|
||||||
<li>
|
<li>
|
||||||
<a href="/admin/users">
|
<a href="/admin/users">{_users}</a>
|
||||||
Пользователи
|
|
||||||
</a>
|
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="/admin/clubs">
|
<a href="/admin/clubs">{_groups}</a>
|
||||||
Группы
|
</li>
|
||||||
</a>
|
<li>
|
||||||
|
<a href="/admin/bannedLinks">{_admin_banned_links}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="aui-nav-heading">
|
<div class="aui-nav-heading">
|
||||||
<strong>Платные услуги</strong>
|
<strong>{_admin_services}</strong>
|
||||||
</div>
|
</div>
|
||||||
<ul class="aui-nav">
|
<ul class="aui-nav">
|
||||||
<li>
|
<li>
|
||||||
<a href="/admin/vouchers">
|
<a href="/admin/vouchers">{_vouchers}</a>
|
||||||
{_vouchers}
|
|
||||||
</a>
|
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="/admin/gifts">
|
<a href="/admin/gifts">{_gifts}</a>
|
||||||
Подарки
|
|
||||||
</a>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="aui-nav-heading">
|
<div class="aui-nav-heading">
|
||||||
<strong>Настройки</strong>
|
<strong>{_admin_settings}</strong>
|
||||||
</div>
|
</div>
|
||||||
<ul class="aui-nav">
|
<ul class="aui-nav">
|
||||||
<li>
|
<li>
|
||||||
<a href="/admin/settings/tuning">
|
<a href="/admin/settings/tuning">{_admin_settings_tuning}</a>
|
||||||
Общие
|
|
||||||
</a>
|
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="/admin/settings/appearance">
|
<a href="/admin/settings/appearance">{_admin_settings_appearance}</a>
|
||||||
Внешний вид
|
|
||||||
</a>
|
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="/admin/settings/security">
|
<a href="/admin/settings/security">{_admin_settings_security}</a>
|
||||||
Безопасность
|
|
||||||
</a>
|
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="/admin/settings/integrations">
|
<a href="/admin/settings/integrations">{_admin_settings_integrations}</a>
|
||||||
Интеграции
|
|
||||||
</a>
|
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="/admin/settings/system">
|
<a href="/admin/settings/system">{_admin_settings_system}</a>
|
||||||
Система
|
|
||||||
</a>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="aui-nav-heading">
|
<div class="aui-nav-heading">
|
||||||
<strong>Об OpenVK</strong>
|
<strong>{_admin_about}</strong>
|
||||||
</div>
|
</div>
|
||||||
<ul class="aui-nav">
|
<ul class="aui-nav">
|
||||||
<li>
|
<li>
|
||||||
<a href="/about:openvk">
|
<a href="/about:openvk">{_admin_about_version}</a>
|
||||||
Версия
|
</li>
|
||||||
</a>
|
<li>
|
||||||
|
<a href="/about">{_admin_about_instance}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -131,7 +108,7 @@
|
||||||
</div>
|
</div>
|
||||||
<section class="aui-page-panel-content">
|
<section class="aui-page-panel-content">
|
||||||
{ifset $flashMessage}
|
{ifset $flashMessage}
|
||||||
{var type = ["err" => "error", "warn" => "warning", "info" => "basic", "succ" => "success"][$flashMessage->type]}
|
{var $type = ["err" => "error", "warn" => "warning", "info" => "basic", "succ" => "success"][$flashMessage->type]}
|
||||||
<div class="aui-message aui-message-{$type}" style="margin-bottom: 15px;">
|
<div class="aui-message aui-message-{$type}" style="margin-bottom: 15px;">
|
||||||
<p class="title">
|
<p class="title">
|
||||||
<strong>{$flashMessage->title}</strong>
|
<strong>{$flashMessage->title}</strong>
|
||||||
|
|
48
Web/Presenters/templates/Admin/BannedLink.xml
Normal file
48
Web/Presenters/templates/Admin/BannedLink.xml
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
{extends "@layout.xml"}
|
||||||
|
|
||||||
|
{block title}
|
||||||
|
{_edit}
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block heading}
|
||||||
|
{_edit} #{$form->id ?? "undefined"}
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block content}
|
||||||
|
<div style="margin: 8px -8px;" class="aui-tabs horizontal-tabs">
|
||||||
|
<ul class="tabs-menu">
|
||||||
|
<li class="menu-item active-tab">
|
||||||
|
<a href="#info">{_admin_banned_link}</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="tabs-pane active-pane" id="info">
|
||||||
|
<form class="aui" method="POST">
|
||||||
|
<div class="field-group">
|
||||||
|
<label for="id">ID</label>
|
||||||
|
<input class="text long-field" type="number" id="id" name="id" disabled value="{$form->id}" />
|
||||||
|
</div>
|
||||||
|
<div class="field-group">
|
||||||
|
<label for="token">{_admin_banned_domain}</label>
|
||||||
|
<input class="text long-field" type="text" id="link" name="link" value="{$form->link}" />
|
||||||
|
<div class="description">{_admin_banned_link_description}</div>
|
||||||
|
</div>
|
||||||
|
<div class="field-group">
|
||||||
|
<label for="token">{_admin_banned_link_regexp}</label>
|
||||||
|
<input class="text long-field" type="text" id="regexp" name="regexp" value="{$form->regexp}" />
|
||||||
|
<div class="description">{_admin_banned_link_regexp_description}</div>
|
||||||
|
</div>
|
||||||
|
<div class="field-group">
|
||||||
|
<label for="coins">{_admin_banned_link_reason}</label>
|
||||||
|
<input class="text long-field" type="text" id="reason" name="reason" value="{$form->reason}" />
|
||||||
|
</div>
|
||||||
|
<div class="buttons-container">
|
||||||
|
<div class="buttons">
|
||||||
|
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||||
|
<input class="aui-button aui-button-primary submit" type="submit" value="{_save}">
|
||||||
|
<a class="aui-button aui-button-secondary" href="/admin/bannedLink/id{$form->id}/unban">{_delete}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/block}
|
46
Web/Presenters/templates/Admin/BannedLinks.xml
Normal file
46
Web/Presenters/templates/Admin/BannedLinks.xml
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
{extends "@layout.xml"}
|
||||||
|
|
||||||
|
{block title}
|
||||||
|
{_admin_banned_links}
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block heading}
|
||||||
|
<a style="float: right;" class="aui-button aui-button-primary" href="/admin/bannedLink/id0">
|
||||||
|
{_create}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{_admin_banned_links}
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block content}
|
||||||
|
<table class="aui aui-table-list">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>{_admin_banned_domain}</th>
|
||||||
|
<th>REGEXP</th>
|
||||||
|
<th>{_admin_banned_link_reason}</th>
|
||||||
|
<th>{_admin_banned_link_initiator}</th>
|
||||||
|
<th>{_admin_actions}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr n:foreach="$links as $link">
|
||||||
|
<td>{$link->getId()}</td>
|
||||||
|
<td>{$link->getDomain()}</td>
|
||||||
|
<td>{$link->getRegexpRule()}</td>
|
||||||
|
<td>{$link->getReason() ?? "-"}</td>
|
||||||
|
<td>{$link->getInitiator()->getCanonicalName()}</td>
|
||||||
|
<td>
|
||||||
|
<a class="aui-button aui-button-primary" href="/admin/bannedLink/id{$link->getId()}">
|
||||||
|
<span class="aui-icon aui-icon-small aui-iconfont-new-edit">{_edit}</span>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div align="right">
|
||||||
|
<a n:if="($_GET['p'] ?? 1) > 1" class="aui-button" href="?p={($_GET['p'] ?? 1) - 1}">«</a>
|
||||||
|
<a class="aui-button" href="?p={($_GET['p'] ?? 1) + 1}">»</a>
|
||||||
|
</div>
|
||||||
|
{/block}
|
|
@ -1,41 +1,35 @@
|
||||||
{extends "@layout.xml"}
|
{extends "@layout.xml"}
|
||||||
|
|
||||||
{block title}
|
{block title}
|
||||||
Редактировать {$club->getCanonicalName()}
|
{_edit} {$club->getCanonicalName()}
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
{block heading}
|
{block heading}
|
||||||
{$club->getCanonicalName()}
|
{$club->getCanonicalName()}
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
|
|
||||||
{block content}
|
{block content}
|
||||||
|
|
||||||
{var isMain = $mode === 'main'}
|
{var $isMain = $mode === 'main'}
|
||||||
{var isBan = $mode === 'ban'}
|
{var $isBan = $mode === 'ban'}
|
||||||
{var isFollowers = $mode === 'followers'}
|
{var $isFollowers = $mode === 'followers'}
|
||||||
|
|
||||||
{if $isMain}
|
{if $isMain}
|
||||||
|
|
||||||
<!-- This main block -->
|
|
||||||
|
|
||||||
<div class="aui-tabs horizontal-tabs">
|
<div class="aui-tabs horizontal-tabs">
|
||||||
<nav class="aui-navgroup aui-navgroup-horizontal">
|
<nav class="aui-navgroup aui-navgroup-horizontal">
|
||||||
<div class="aui-navgroup-inner">
|
<div class="aui-navgroup-inner">
|
||||||
<div class="aui-navgroup-primary">
|
<div class="aui-navgroup-primary">
|
||||||
<ul class="aui-nav">
|
<ul class="aui-nav">
|
||||||
<li class="aui-nav-selected"><a href="?act=main">Главное</a></li>
|
<li class="aui-nav-selected"><a href="?act=main">{_admin_tab_main}</a></li>
|
||||||
<li><a href="?act=ban">Бан</a></li>
|
<li><a href="?act=ban">{_admin_tab_ban}</a></li>
|
||||||
<li><a href="?act=followers">Участники</a></li>
|
<li><a href="?act=followers">{_admin_tab_followers}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<form class="aui" method="POST">
|
<form class="aui" method="POST">
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="avatar">
|
<label for="avatar">{_avatar}</label>
|
||||||
Аватарка
|
|
||||||
</label>
|
|
||||||
<span id="avatar" class="aui-avatar aui-avatar-project aui-avatar-xlarge">
|
<span id="avatar" class="aui-avatar aui-avatar-project aui-avatar-xlarge">
|
||||||
<span class="aui-avatar-inner">
|
<span class="aui-avatar-inner">
|
||||||
<img src="{$club->getAvatarUrl('tiny')}" style="object-fit: cover;"></img>
|
<img src="{$club->getAvatarUrl('tiny')}" style="object-fit: cover;"></img>
|
||||||
|
@ -43,53 +37,39 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="id">
|
<label for="id">ID</label>
|
||||||
ID
|
|
||||||
</label>
|
|
||||||
<input class="text medium-field" type="number" id="id" disabled value="{$club->getId()}" />
|
<input class="text medium-field" type="number" id="id" disabled value="{$club->getId()}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="id_owner">
|
<label for="id_owner">{_admin_ownerid}</label>
|
||||||
ID владельца
|
|
||||||
</label>
|
|
||||||
<input class="text medium-field" type="text" id="id_owner" name="id_owner" value="{$club->getOwner()->getId()}" />
|
<input class="text medium-field" type="text" id="id_owner" name="id_owner" value="{$club->getOwner()->getId()}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="name">
|
<label for="name">{_admin_title}</label>
|
||||||
Название
|
|
||||||
</label>
|
|
||||||
<input class="text medium-field" type="text" id="name" name="name" value="{$club->getName()}" />
|
<input class="text medium-field" type="text" id="name" name="name" value="{$club->getName()}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="about">
|
<label for="about">{_admin_description}</label>
|
||||||
Описание
|
|
||||||
</label>
|
|
||||||
<input class="text medium-field" type="text" id="about" name="about" value="{$club->getDescription()}" />
|
<input class="text medium-field" type="text" id="about" name="about" value="{$club->getDescription()}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="shortcode">
|
<label for="shortcode">{_admin_shortcode}</label>
|
||||||
Адрес
|
|
||||||
</label>
|
|
||||||
<input class="text medium-field" type="text" id="shortcode" name="shortcode" value="{$club->getShortCode()}" />
|
<input class="text medium-field" type="text" id="shortcode" name="shortcode" value="{$club->getShortCode()}" />
|
||||||
</div>
|
</div>
|
||||||
<br/>
|
<br/>
|
||||||
<div class="group">
|
<div class="group">
|
||||||
<input class="toggle-large" type="checkbox" id="verify" name="verify" value="1" {if $club->isVerified()} checked {/if} />
|
<input class="toggle-large" type="checkbox" id="verify" name="verify" value="1" {if $club->isVerified()} checked {/if} />
|
||||||
<label for="verify">
|
<label for="verify">{_admin_verification}</label>
|
||||||
Верификация
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="group">
|
<div class="group">
|
||||||
<input class="toggle-large" type="checkbox" id="hide_from_global_feed" name="hide_from_global_feed" value="1" {if $club->isHideFromGlobalFeedEnabled()} checked {/if} />
|
<input class="toggle-large" type="checkbox" id="hide_from_global_feed" name="hide_from_global_feed" value="1" {if $club->isHideFromGlobalFeedEnabled()} checked {/if} />
|
||||||
<label for="hide_from_global_feed">
|
<label for="hide_from_global_feed">{_admin_club_excludeglobalfeed}</label>
|
||||||
Не отображать записи в глобальной ленте
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
<hr/>
|
<hr/>
|
||||||
<div class="buttons-container">
|
<div class="buttons-container">
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||||
<input class="button submit" type="submit" value="Сохранить">
|
<input class="button submit" type="submit" value="{_save}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -97,33 +77,28 @@
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{if $isBan}
|
{if $isBan}
|
||||||
|
|
||||||
<!-- This ban block -->
|
|
||||||
|
|
||||||
<div class="aui-tabs horizontal-tabs">
|
<div class="aui-tabs horizontal-tabs">
|
||||||
<nav class="aui-navgroup aui-navgroup-horizontal">
|
<nav class="aui-navgroup aui-navgroup-horizontal">
|
||||||
<div class="aui-navgroup-inner">
|
<div class="aui-navgroup-inner">
|
||||||
<div class="aui-navgroup-primary">
|
<div class="aui-navgroup-primary">
|
||||||
<ul class="aui-nav">
|
<ul class="aui-nav">
|
||||||
<li><a href="?act=main">Главное</a></li>
|
<li><a href="?act=main">{_admin_tab_main}</a></li>
|
||||||
<li class="aui-nav-selected"><a href="?act=ban">Бан</a></li>
|
<li class="aui-nav-selected"><a href="?act=ban">{_admin_tab_ban}</a></li>
|
||||||
<li><a href="?act=followers">Участники</a></li>
|
<li><a href="?act=followers">{_admin_tab_followers}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<form class="aui" method="POST">
|
<form class="aui" method="POST">
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="ban_reason">
|
<label for="ban_reason">{_admin_banreason}</label>
|
||||||
Причина бана
|
|
||||||
</label>
|
|
||||||
<input class="text" type="text" id="text-input" name="ban_reason" value="{$club->getBanReason()}" />
|
<input class="text" type="text" id="text-input" name="ban_reason" value="{$club->getBanReason()}" />
|
||||||
</div>
|
</div>
|
||||||
<hr/>
|
<hr/>
|
||||||
<div class="buttons-container">
|
<div class="buttons-container">
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||||
<input class="button submit" type="submit" value="Сохранить">
|
<input class="button submit" type="submit" value="{_save}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -131,19 +106,16 @@
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{if $isFollowers}
|
{if $isFollowers}
|
||||||
|
{var $followers = iterator_to_array($followers)}
|
||||||
<!-- This followers block -->
|
|
||||||
|
|
||||||
{var followers = iterator_to_array($followers)}
|
|
||||||
|
|
||||||
<div class="aui-tabs horizontal-tabs">
|
<div class="aui-tabs horizontal-tabs">
|
||||||
<nav class="aui-navgroup aui-navgroup-horizontal">
|
<nav class="aui-navgroup aui-navgroup-horizontal">
|
||||||
<div class="aui-navgroup-inner">
|
<div class="aui-navgroup-inner">
|
||||||
<div class="aui-navgroup-primary">
|
<div class="aui-navgroup-primary">
|
||||||
<ul class="aui-nav">
|
<ul class="aui-nav">
|
||||||
<li><a href="?act=main">Главное</a></li>
|
<li><a href="?act=main">{_admin_tab_main}</a></li>
|
||||||
<li><a href="?act=ban">Бан</a></li>
|
<li><a href="?act=ban">{_admin_tab_ban}</a></li>
|
||||||
<li class="aui-nav-selected"><a href="?act=followers">Участники</a></li>
|
<li class="aui-nav-selected"><a href="?act=followers">{_admin_tab_followers}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -155,36 +127,30 @@
|
||||||
<td>
|
<td>
|
||||||
<span class="aui-avatar aui-avatar-xsmall">
|
<span class="aui-avatar aui-avatar-xsmall">
|
||||||
<span class="aui-avatar-inner">
|
<span class="aui-avatar-inner">
|
||||||
<img src="{$follower->getAvatarUrl('miniscule')}" alt="{$follower->getCanonicalName()}" role="presentation" />
|
<img src="{$follower->getAvatarUrl()}" alt="{$follower->getCanonicalName()}" role="presentation" />
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<a href="{$follower->getURL()}">{$follower->getCanonicalName()}</a>
|
<a href="{$follower->getURL()}">{$follower->getCanonicalName()}</a>
|
||||||
|
|
||||||
<span n:if="$follower->isBanned()" class="aui-lozenge aui-lozenge-subtle aui-lozenge-removed">
|
<span n:if="$follower->isBanned()" class="aui-lozenge aui-lozenge-subtle aui-lozenge-removed">{_admin_banned}</span>
|
||||||
заблокирован
|
|
||||||
</span>
|
|
||||||
</td>
|
</td>
|
||||||
<td>{$follower->isFemale() ? "Женский" : "Мужской"}</td>
|
<td>{$follower->isFemale() ? tr("female") : tr("male")}</td>
|
||||||
<td>{$follower->getShortCode() ?? "(отсутствует)"}</td>
|
<td>{$follower->getShortCode() ?? "(" . tr("none") . ")"}</td>
|
||||||
<td>{$follower->getRegistrationTime()}</td>
|
<td>{$follower->getRegistrationTime()}</td>
|
||||||
<td>
|
<td>
|
||||||
<a class="aui-button aui-button-primary" href="/admin/users/id{$follower->getId()}">
|
<a class="aui-button aui-button-primary" href="/admin/users/id{$follower->getId()}">
|
||||||
<span class="aui-icon aui-icon-small aui-iconfont-new-edit">Редактировать</span>
|
<span class="aui-icon aui-icon-small aui-iconfont-new-edit">{_edit}</span>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div align="right">
|
<div align="right">
|
||||||
{var isLast = ((20 * (($_GET['p'] ?? 1) - 1)) + $amount) < $count}
|
{var $isLast = ((20 * (($_GET['p'] ?? 1) - 1)) + $amount) < $count}
|
||||||
|
|
||||||
<a n:if="($_GET['p'] ?? 1) > 1" class="aui-button" href="?p={($_GET['p'] ?? 1) - 1}">
|
<a n:if="($_GET['p'] ?? 1) > 1" class="aui-button" href="?p={($_GET['p'] ?? 1) - 1}">«</a>
|
||||||
⭁ туда
|
<a n:if="$isLast" class="aui-button" href="?p={($_GET['p'] ?? 1) + 1}">»</a>
|
||||||
</a>
|
|
||||||
<a n:if="$isLast" class="aui-button" href="?p={($_GET['p'] ?? 1) + 1}">
|
|
||||||
⭇ сюда
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -1,29 +1,31 @@
|
||||||
{extends "@layout.xml"}
|
{extends "@layout.xml"}
|
||||||
{var search = true}
|
{var $search = true}
|
||||||
|
|
||||||
{block title}
|
{block title}
|
||||||
Группы
|
{_admin_club_search}
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
{block heading}
|
{block heading}
|
||||||
Бутылки
|
{_groups}
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
{block searchTitle}Поиск бутылок{/block}
|
{block searchTitle}
|
||||||
|
{include title}
|
||||||
|
{/block}
|
||||||
|
|
||||||
{block content}
|
{block content}
|
||||||
{var clubs = iterator_to_array($clubs)}
|
{var $clubs = iterator_to_array($clubs)}
|
||||||
{var amount = sizeof($clubs)}
|
{var $amount = sizeof($clubs)}
|
||||||
|
|
||||||
<table class="aui aui-table-list">
|
<table class="aui aui-table-list">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>#</th>
|
<th>ID</th>
|
||||||
<th>Имя</th>
|
<th>{_admin_title}</th>
|
||||||
<th>Автор</th>
|
<th>{_admin_author}</th>
|
||||||
<th>Описание</th>
|
<th>{_admin_description}</th>
|
||||||
<th>Короткий адрес</th>
|
<th>{_admin_shortcode}</th>
|
||||||
<th>Действия</th>
|
<th>{_admin_actions}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -39,7 +41,7 @@
|
||||||
<a href="{$club->getURL()}">{$club->getCanonicalName()}</a>
|
<a href="{$club->getURL()}">{$club->getCanonicalName()}</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{var user = $club->getOwner()}
|
{var $user = $club->getOwner()}
|
||||||
|
|
||||||
<span class="aui-avatar aui-avatar-xsmall">
|
<span class="aui-avatar aui-avatar-xsmall">
|
||||||
<span class="aui-avatar-inner">
|
<span class="aui-avatar-inner">
|
||||||
|
@ -49,11 +51,11 @@
|
||||||
|
|
||||||
<a href="{$user->getURL()}">{$user->getCanonicalName()}</a>
|
<a href="{$user->getURL()}">{$user->getCanonicalName()}</a>
|
||||||
</td>
|
</td>
|
||||||
<td>{$club->getDescription() ?? "(не указано)"}</td>
|
<td>{$club->getDescription() ?? "(" . tr("none") . ")"}</td>
|
||||||
<td>{$club->getShortCode()}</td>
|
<td>{$club->getShortCode()}</td>
|
||||||
<td>
|
<td>
|
||||||
<a class="aui-button aui-button-primary" href="/admin/clubs/id{$club->getId()}">
|
<a class="aui-button aui-button-primary" href="/admin/clubs/id{$club->getId()}">
|
||||||
<span class="aui-icon aui-icon-small aui-iconfont-new-edit">Редактировать</span>
|
<span class="aui-icon aui-icon-small aui-iconfont-new-edit">{_edit}</span>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -61,13 +63,9 @@
|
||||||
</table>
|
</table>
|
||||||
<br/>
|
<br/>
|
||||||
<div align="right">
|
<div align="right">
|
||||||
{var isLast = ((10 * (($_GET['p'] ?? 1) - 1)) + $amount) < $count}
|
{var $isLast = ((10 * (($_GET['p'] ?? 1) - 1)) + $amount) < $count}
|
||||||
|
|
||||||
<a n:if="($_GET['p'] ?? 1) > 1" class="aui-button" href="?p={($_GET['p'] ?? 1) - 1}">
|
<a n:if="($_GET['p'] ?? 1) > 1" class="aui-button" href="?p={($_GET['p'] ?? 1) - 1}">«</a>
|
||||||
⭁ туда
|
<a n:if="$isLast" class="aui-button" href="?p={($_GET['p'] ?? 1) + 1}">»</a>
|
||||||
</a>
|
|
||||||
<a n:if="$isLast" class="aui-button" href="?p={($_GET['p'] ?? 1) + 1}">
|
|
||||||
⭇ сюда
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
{/block}
|
{/block}
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
{block title}
|
{block title}
|
||||||
{if $form->id === 0}
|
{if $form->id === 0}
|
||||||
Новый подарок
|
{_admin_newgift}
|
||||||
{else}
|
{else}
|
||||||
Подарок "{$form->name}"
|
{_gift} "{$form->name}"
|
||||||
{/if}
|
{/if}
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
<form class="aui" method="POST" enctype="multipart/form-data">
|
<form class="aui" method="POST" enctype="multipart/form-data">
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="avatar">
|
<label for="avatar">
|
||||||
Изображение
|
{_admin_image}
|
||||||
<span n:if="$form->id === 0" class="aui-icon icon-required"></span>
|
<span n:if="$form->id === 0" class="aui-icon icon-required"></span>
|
||||||
</label>
|
</label>
|
||||||
{if $form->id === 0}
|
{if $form->id === 0}
|
||||||
|
@ -29,43 +29,39 @@
|
||||||
</span>
|
</span>
|
||||||
<input style="display: none;" id="picInput" type="file" name="pic" accept="image/jpeg,image/png,image/gif,image/webp" />
|
<input style="display: none;" id="picInput" type="file" name="pic" accept="image/jpeg,image/png,image/gif,image/webp" />
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<a id="picChange" href="javascript:false">Заменить изображение?</a>
|
<a id="picChange" href="javascript:false">{_admin_image_replace}</a>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="id">
|
<label for="id">ID</label>
|
||||||
ID
|
|
||||||
</label>
|
|
||||||
<input class="text long-field" type="number" id="id" disabled="disabled" value="{$form->id}" />
|
<input class="text long-field" type="number" id="id" disabled="disabled" value="{$form->id}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="putin">
|
<label for="usages">{_admin_uses}</label>
|
||||||
Использований
|
<input class="text long-field" type="number" id="usages" disabled="disabled" value="{$form->usages}" />
|
||||||
</label>
|
|
||||||
<input class="text long-field" type="number" id="putin" disabled="disabled" value="{$form->usages}" />
|
|
||||||
<div n:if="$form->usages > 0" class="description">
|
<div n:if="$form->usages > 0" class="description">
|
||||||
<a href="javascript:$('#putin').value(0);">Обнулить?</a>
|
<a href="javascript:$('#usages').value(0);">{_admin_uses_reset}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="name">
|
<label for="name">
|
||||||
Внутренее имя
|
{_admin_name}
|
||||||
<span class="aui-icon icon-required"></span>
|
<span class="aui-icon icon-required"></span>
|
||||||
</label>
|
</label>
|
||||||
<input class="text long-field" type="text" id="name" name="name" value="{$form->name}" />
|
<input class="text long-field" type="text" id="name" name="name" value="{$form->name}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="price">
|
<label for="price">
|
||||||
Цена
|
{_admin_price}
|
||||||
<span class="aui-icon icon-required"></span>
|
<span class="aui-icon icon-required"></span>
|
||||||
</label>
|
</label>
|
||||||
<input class="text long-field" type="number" id="price" name="price" min="0" value="{$form->price}" />
|
<input class="text long-field" type="number" id="price" name="price" min="0" value="{$form->price}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="limit">
|
<label for="limit">
|
||||||
Ограничение
|
{_admin_limits}
|
||||||
<span class="aui-icon icon-required"></span>
|
<span class="aui-icon icon-required"></span>
|
||||||
</label>
|
</label>
|
||||||
<input class="text long-field" type="number" min="-1" id="limit" name="limit" value="{$form->limit}" />
|
<input class="text long-field" type="number" min="-1" id="limit" name="limit" value="{$form->limit}" />
|
||||||
|
@ -76,7 +72,7 @@
|
||||||
<input n:attr="disabled => $form->id === 0, checked => $form->id === 0" class="checkbox" type="checkbox" name="reset_limit" id="reset_limit" />
|
<input n:attr="disabled => $form->id === 0, checked => $form->id === 0" class="checkbox" type="checkbox" name="reset_limit" id="reset_limit" />
|
||||||
<span class="aui-form-glyph"></span>
|
<span class="aui-form-glyph"></span>
|
||||||
|
|
||||||
<label for="reset_limit">Сбросить счётчик ограничений</label>
|
<label for="reset_limit">{_admin_limits_reset}</label>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{extends "@layout.xml"}
|
{extends "@layout.xml"}
|
||||||
|
|
||||||
{block title}
|
{block title}
|
||||||
Наборы подарков
|
{_admin_giftsets}
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
{block headingWrap}
|
{block headingWrap}
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
{_create}
|
{_create}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<h1>Наборы подарков</h1>
|
<h1>{_admin_giftsets}</h1>
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
{block content}
|
{block content}
|
||||||
|
@ -27,12 +27,11 @@
|
||||||
</td>
|
</td>
|
||||||
<td style="vertical-align: middle; text-align: right;">
|
<td style="vertical-align: middle; text-align: right;">
|
||||||
<a class="aui-button aui-button-primary" href="/admin/gifts/{$cat->getSlug()}.{$cat->getId()}.meta">
|
<a class="aui-button aui-button-primary" href="/admin/gifts/{$cat->getSlug()}.{$cat->getId()}.meta">
|
||||||
<span class="aui-icon aui-icon-small aui-iconfont-new-edit">Редактировать</span>
|
<span class="aui-icon aui-icon-small aui-iconfont-new-edit">{_edit}</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a class="aui-button" href="/admin/gifts/{$cat->getSlug()}.{$cat->getId()}/">
|
<a class="aui-button" href="/admin/gifts/{$cat->getSlug()}.{$cat->getId()}/">
|
||||||
<span class="aui-icon aui-icon-small aui-iconfont-gallery">Открыть</span>
|
<span class="aui-icon aui-icon-small aui-iconfont-gallery">{_admin_open}</span>
|
||||||
Открыть
|
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -40,17 +39,13 @@
|
||||||
</table>
|
</table>
|
||||||
{else}
|
{else}
|
||||||
<center>
|
<center>
|
||||||
<p>Наборов подарков нету. Чтобы создать подарок, создайте набор.</p>
|
<p>{_admin_giftsets_none}</p>
|
||||||
</center>
|
</center>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div align="right">
|
<div align="right">
|
||||||
{var isLast = ((20 * (($_GET['p'] ?? 1) - 1)) + sizeof($categories)) < $count}
|
{var $isLast = ((20 * (($_GET['p'] ?? 1) - 1)) + sizeof($categories)) < $count}
|
||||||
<a n:if="($_GET['p'] ?? 1) > 1" class="aui-button" href="?act={$act}&p={($_GET['p'] ?? 1) - 1}">
|
<a n:if="($_GET['p'] ?? 1) > 1" class="aui-button" href="?act={$act}&p={($_GET['p'] ?? 1) - 1}">«</a>
|
||||||
⭁ туда
|
<a n:if="$isLast" class="aui-button" href="?act={$act}&p={($_GET['p'] ?? 1) + 1}">»</a>
|
||||||
</a>
|
|
||||||
<a n:if="$isLast" class="aui-button" href="?act={$act}&p={($_GET['p'] ?? 1) + 1}">
|
|
||||||
⭇ сюда
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
{/block}
|
{/block}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
{block title}
|
{block title}
|
||||||
{if $form->id === 0}
|
{if $form->id === 0}
|
||||||
Создать набор подарков
|
{_admin_giftsets_create}
|
||||||
{else}
|
{else}
|
||||||
{$form->languages["master"]->name}
|
{$form->languages["master"]->name}
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
{block content}
|
{block content}
|
||||||
<form class="aui" method="POST">
|
<form class="aui" method="POST">
|
||||||
<h3>Общие настройки</h3>
|
<h3>{_admin_commonsettings}</h3>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="id">
|
<label for="id">
|
||||||
|
@ -24,37 +24,37 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="name_master">
|
<label for="name_master">
|
||||||
Наименование
|
{_admin_name}
|
||||||
<span class="aui-icon icon-required"></span>
|
<span class="aui-icon icon-required"></span>
|
||||||
</label>
|
</label>
|
||||||
<input class="text long-field" type="text" id="name_master" name="name_master" value="{$form->languages['master']->name}" />
|
<input class="text long-field" type="text" id="name_master" name="name_master" value="{$form->languages['master']->name}" />
|
||||||
<div class="description">Внутреннее название набора, которое будет использоваться, если не удаётся найти название на языке пользователя.</div>
|
<div class="description">{_admin_giftsets_title}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="description_master">
|
<label for="description_master">
|
||||||
Описание
|
{_admin_description}
|
||||||
<span class="aui-icon icon-required"></span>
|
<span class="aui-icon icon-required"></span>
|
||||||
</label>
|
</label>
|
||||||
<input class="text long-field" type="text" id="description_master" name="description_master" value="{$form->languages['master']->description}" />
|
<input class="text long-field" type="text" id="description_master" name="description_master" value="{$form->languages['master']->description}" />
|
||||||
<div class="description">Внутреннее описание набора, которое будет использоваться, если не удаётся найти название на языке пользователя.</div>
|
<div class="description">{_admin_giftsets_description}</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<h3>Языко-зависимые настройки</h3>
|
<h3>{_admin_langsettings}</h3>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
{foreach $form->languages as $locale => $data}
|
{foreach $form->languages as $locale => $data}
|
||||||
{continueIf $locale === "master"}
|
{continueIf $locale === "master"}
|
||||||
|
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="name_{$locale}">
|
<label for="name_{$locale}">
|
||||||
Наименование
|
{_admin_name}
|
||||||
<img src="/assets/packages/static/openvk/img/flags/{$locale}.gif" alt="{$locale}" />
|
<img src="/assets/packages/static/openvk/img/flags/{$locale}.gif" alt="{$locale}" />
|
||||||
</label>
|
</label>
|
||||||
<input class="text long-field" type="text" id="name_{$locale}" name="name_{$locale}" value="{$data->name}" />
|
<input class="text long-field" type="text" id="name_{$locale}" name="name_{$locale}" value="{$data->name}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="description_{$locale}">
|
<label for="description_{$locale}">
|
||||||
Описание
|
{_admin_description}
|
||||||
<img src="/assets/packages/static/openvk/img/flags/{$locale}.gif" alt="{$locale}" />
|
<img src="/assets/packages/static/openvk/img/flags/{$locale}.gif" alt="{$locale}" />
|
||||||
</label>
|
</label>
|
||||||
<input class="text long-field" type="text" id="description_{$locale}" name="description_{$locale}" value="{$data->description}" />
|
<input class="text long-field" type="text" id="description_{$locale}" name="description_{$locale}" value="{$data->description}" />
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
{_create}
|
{_create}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<h1>Набор "{$cat->getName()}"</h1>
|
<h1>{_admin_giftset} "{$cat->getName()}"</h1>
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
{block content}
|
{block content}
|
||||||
|
@ -32,11 +32,11 @@
|
||||||
<td style="vertical-align: middle;">
|
<td style="vertical-align: middle;">
|
||||||
{$gift->getName()}
|
{$gift->getName()}
|
||||||
<span n:if="$gift->isFree()" class="aui-lozenge aui-lozenge-subtle aui-lozenge-success">
|
<span n:if="$gift->isFree()" class="aui-lozenge aui-lozenge-subtle aui-lozenge-success">
|
||||||
бесплатный
|
{_admin_price_free}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td style="vertical-align: middle;">
|
<td style="vertical-align: middle;">
|
||||||
{$gift->getPrice()} голосов
|
{tr("points_amount", $gift->getPrice())}
|
||||||
</td>
|
</td>
|
||||||
<td style="vertical-align: middle;">
|
<td style="vertical-align: middle;">
|
||||||
{$gift->getUsages()} раз
|
{$gift->getUsages()} раз
|
||||||
|
@ -71,12 +71,9 @@
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div align="right">
|
<div align="right">
|
||||||
{var isLast = ((20 * (($_GET['p'] ?? 1) - 1)) + sizeof($gifts)) < $count}
|
{var $isLast = ((20 * (($_GET['p'] ?? 1) - 1)) + sizeof($gifts)) < $count}
|
||||||
<a n:if="($_GET['p'] ?? 1) > 1" class="aui-button" href="?p={($_GET['p'] ?? 1) - 1}">
|
|
||||||
⭁ туда
|
<a n:if="($_GET['p'] ?? 1) > 1" class="aui-button" href="?p={($_GET['p'] ?? 1) - 1}">«</a>
|
||||||
</a>
|
<a n:if="$isLast" class="aui-button" href="?p={($_GET['p'] ?? 1) + 1}">»</a>
|
||||||
<a n:if="$isLast" class="aui-button" href="?p={($_GET['p'] ?? 1) + 1}">
|
|
||||||
⭇ сюда
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
{/block}
|
{/block}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
{extends "@layout.xml"}
|
{extends "@layout.xml"}
|
||||||
|
|
||||||
{block title}
|
{block title}
|
||||||
Сводка
|
{_admin_overview_summary}
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
{block heading}
|
{block heading}
|
||||||
Сводка
|
{_admin_overview_summary}
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
{block content}
|
{block content}
|
||||||
Да!
|
┬─┬︵/(.□.)╯
|
||||||
{/block}
|
{/block}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{extends "@layout.xml"}
|
{extends "@layout.xml"}
|
||||||
|
|
||||||
{block title}
|
{block title}
|
||||||
Редактировать {$user->getCanonicalName()}
|
{_edit} {$user->getCanonicalName()}
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
{block heading}
|
{block heading}
|
||||||
|
@ -12,9 +12,7 @@
|
||||||
<div class="aui-tabs horizontal-tabs">
|
<div class="aui-tabs horizontal-tabs">
|
||||||
<form class="aui" method="POST">
|
<form class="aui" method="POST">
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="avatar">
|
<label for="avatar">{_avatar}</label>
|
||||||
Аватарка
|
|
||||||
</label>
|
|
||||||
<span id="avatar" class="aui-avatar aui-avatar-project aui-avatar-xlarge">
|
<span id="avatar" class="aui-avatar aui-avatar-project aui-avatar-xlarge">
|
||||||
<span class="aui-avatar-inner">
|
<span class="aui-avatar-inner">
|
||||||
<img src="{$user->getAvatarUrl('tiny')}" style="object-fit: cover;"></img>
|
<img src="{$user->getAvatarUrl('tiny')}" style="object-fit: cover;"></img>
|
||||||
|
@ -22,83 +20,60 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="id">
|
<label for="id">ID</label>
|
||||||
ID
|
|
||||||
</label>
|
|
||||||
<input class="text medium-field" type="number" id="id" disabled value="{$user->getId()}" />
|
<input class="text medium-field" type="number" id="id" disabled value="{$user->getId()}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="guid">
|
<label for="guid">GUID</label>
|
||||||
GUID
|
|
||||||
</label>
|
|
||||||
<input class="text medium-field" id="guid" disabled value="{$user->getChandlerUser()->getId()}" />
|
<input class="text medium-field" id="guid" disabled value="{$user->getChandlerUser()->getId()}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="registration_ip">
|
<label for="registration_ip">{_admin_first_known_ip}</label>
|
||||||
Первый IP
|
<input class="text medium-field" id="guid" disabled value="{$user->getRegistrationIP()}" />
|
||||||
</label>
|
|
||||||
<input class="text medium-field" id="registration_ip" disabled value="{$user->getRegistrationIP()}" />
|
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="first_name">
|
<label for="first_name">{_name}</label>
|
||||||
Имя
|
|
||||||
</label>
|
|
||||||
<input class="text medium-field" type="text" id="first_name" name="first_name" value="{$user->getFirstName()}" />
|
<input class="text medium-field" type="text" id="first_name" name="first_name" value="{$user->getFirstName()}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="last_name">
|
<label for="last_name">{_surname}</label>
|
||||||
Фамилия
|
|
||||||
</label>
|
|
||||||
<input class="text medium-field" type="text" id="last_name" name="last_name" value="{$user->getLastName()}" />
|
<input class="text medium-field" type="text" id="last_name" name="last_name" value="{$user->getLastName()}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="nickname">
|
<label for="nickname">{_nickname}</label>
|
||||||
Никнейм
|
|
||||||
</label>
|
|
||||||
<input class="text medium-field" type="text" id="nickname" name="nickname" value="{$user->getPseudo()}" />
|
<input class="text medium-field" type="text" id="nickname" name="nickname" value="{$user->getPseudo()}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="status">
|
<label for="status">{_status}</label>
|
||||||
Статус
|
|
||||||
</label>
|
|
||||||
<input class="text medium-field" type="text" id="status" name="status" value="{$user->getStatus()}" />
|
<input class="text medium-field" type="text" id="status" name="status" value="{$user->getStatus()}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="email">
|
<label for="email">E-Mail</label>
|
||||||
E-Mail
|
|
||||||
</label>
|
|
||||||
<input class="text medium-field" type="email" id="email" name="email" value="{$user->getEmail()}" />
|
<input class="text medium-field" type="email" id="email" name="email" value="{$user->getEmail()}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="shortcode">
|
<label for="shortcode">{_admin_shortcode}</label>
|
||||||
Адрес страницы
|
|
||||||
</label>
|
|
||||||
<input class="text medium-field" type="text" id="shortcode" name="shortcode" value="{$user->getShortCode()}" />
|
<input class="text medium-field" type="text" id="shortcode" name="shortcode" value="{$user->getShortCode()}" />
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="city">
|
<label for="city">{_admin_verification}</label>
|
||||||
Верификация
|
|
||||||
</label>
|
|
||||||
<input class="toggle-large" type="checkbox" id="verify" name="verify" value="1" {if $user->isVerified()} checked {/if} />
|
<input class="toggle-large" type="checkbox" id="verify" name="verify" value="1" {if $user->isVerified()} checked {/if} />
|
||||||
</div>
|
</div>
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="city">
|
<label for="city">{_admin_user_online}</label>
|
||||||
Онлайн статус
|
|
||||||
</label>
|
|
||||||
<select name="online" class="select">
|
<select name="online" class="select">
|
||||||
<option value="0" {if $user->onlineStatus() > 2}selected{/if}>По-умолчанию</option>
|
<option value="0" {if $user->onlineStatus() > 2}selected{/if}>{_admin_user_online_default}</option>
|
||||||
<option value="1" {if $user->onlineStatus() == 1}selected{/if}>Инкогнито</option>
|
<option value="1" {if $user->onlineStatus() == 1}selected{/if}>{_admin_user_online_incognite}</option>
|
||||||
<option value="2" {if $user->onlineStatus() == 2}selected{/if}>Юзер умер</option>
|
<option value="2" {if $user->onlineStatus() == 2}selected{/if}>{_admin_user_online_deceased}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons-container">
|
<div class="buttons-container">
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||||
<input class="button submit" type="submit" value="Сохранить">
|
<input class="button submit" type="submit" value="{_save}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{/block}
|
{/block}
|
||||||
|
|
|
@ -1,29 +1,31 @@
|
||||||
{extends "@layout.xml"}
|
{extends "@layout.xml"}
|
||||||
{var search = true}
|
{var $search = true}
|
||||||
|
|
||||||
{block title}
|
{block title}
|
||||||
Пользователи
|
{_admin_user_search}
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
{block heading}
|
{block heading}
|
||||||
Пиздюки
|
{_users}
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
{block searchTitle}Поиск пиздюков{/block}
|
{block searchTitle}
|
||||||
|
{include title}
|
||||||
|
{/block}
|
||||||
|
|
||||||
{block content}
|
{block content}
|
||||||
{var users = iterator_to_array($users)}
|
{var $users = iterator_to_array($users)}
|
||||||
{var amount = sizeof($users)}
|
{var $amount = sizeof($users)}
|
||||||
|
|
||||||
<table class="aui aui-table-list">
|
<table class="aui aui-table-list">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>#</th>
|
<th>ID</th>
|
||||||
<th>Имя</th>
|
<th>{_admin_name}</th>
|
||||||
<th>Пол</th>
|
<th>{_gender}</th>
|
||||||
<th>Короткий адрес</th>
|
<th>{_admin_shortcode}</th>
|
||||||
<th>Дата регистрации</th>
|
<th>{_registration_date}</th>
|
||||||
<th>Действия</th>
|
<th>{_admin_actions}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -38,20 +40,18 @@
|
||||||
|
|
||||||
<a href="{$user->getURL()}">{$user->getCanonicalName()}</a>
|
<a href="{$user->getURL()}">{$user->getCanonicalName()}</a>
|
||||||
|
|
||||||
<span n:if="$user->isBanned()" class="aui-lozenge aui-lozenge-subtle aui-lozenge-removed">
|
<span n:if="$user->isBanned()" class="aui-lozenge aui-lozenge-subtle aui-lozenge-removed">{_admin_banned}</span>
|
||||||
заблокирован
|
|
||||||
</span>
|
|
||||||
</td>
|
</td>
|
||||||
<td>{$user->isFemale() ? "Женский" : "Мужской"}</td>
|
<td>{$user->isFemale() ? tr("female") : tr("male")}</td>
|
||||||
<td>{$user->getShortCode() ?? "(отсутствует)"}</td>
|
<td>{$user->getShortCode() ?? "(" . tr("none") . ")"}</td>
|
||||||
<td>{$user->getRegistrationTime()}</td>
|
<td>{$user->getRegistrationTime()}</td>
|
||||||
<td>
|
<td>
|
||||||
<a class="aui-button aui-button-primary" href="/admin/users/id{$user->getId()}">
|
<a class="aui-button aui-button-primary" href="/admin/users/id{$user->getId()}">
|
||||||
<span class="aui-icon aui-icon-small aui-iconfont-new-edit">Редактировать</span>
|
<span class="aui-icon aui-icon-small aui-iconfont-new-edit">{_edit}</span>
|
||||||
</a>
|
</a>
|
||||||
{if $thisUser->getChandlerUser()->can("substitute")->model('openvk\Web\Models\Entities\User')->whichBelongsTo(0)}
|
{if $thisUser->getChandlerUser()->can("substitute")->model('openvk\Web\Models\Entities\User')->whichBelongsTo(0)}
|
||||||
<a class="aui-button" href="/setSID/{$user->getChandlerUser()->getId()}?hash={rawurlencode($csrfToken)}">
|
<a class="aui-button" href="/setSID/{$user->getChandlerUser()->getId()}?hash={rawurlencode($csrfToken)}">
|
||||||
<span class="aui-icon aui-icon-small aui-iconfont-sign-in">Войти как</span>
|
<span class="aui-icon aui-icon-small aui-iconfont-sign-in">{_admin_loginas}</span>
|
||||||
</a>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
</td>
|
</td>
|
||||||
|
@ -60,13 +60,9 @@
|
||||||
</table>
|
</table>
|
||||||
<br/>
|
<br/>
|
||||||
<div align="right">
|
<div align="right">
|
||||||
{var isLast = ((20 * (($_GET['p'] ?? 1) - 1)) + $amount) < $count}
|
{var $isLast = ((20 * (($_GET['p'] ?? 1) - 1)) + $amount) < $count}
|
||||||
|
|
||||||
<a n:if="($_GET['p'] ?? 1) > 1" class="aui-button" href="?p={($_GET['p'] ?? 1) - 1}">
|
<a n:if="($_GET['p'] ?? 1) > 1" class="aui-button" href="?p={($_GET['p'] ?? 1) - 1}">«</a>
|
||||||
⭁ туда
|
<a n:if="$isLast" class="aui-button" href="?p={($_GET['p'] ?? 1) + 1}">»</a>
|
||||||
</a>
|
|
||||||
<a n:if="$isLast" class="aui-button" href="?p={($_GET['p'] ?? 1) + 1}">
|
|
||||||
⭇ сюда
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
{/block}
|
{/block}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue