diff --git a/CLI/FetchToncoinTransactions.php b/CLI/FetchToncoinTransactions.php
new file mode 100755
index 00000000..b4e66dcb
--- /dev/null
+++ b/CLI/FetchToncoinTransactions.php
@@ -0,0 +1,103 @@
+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;
+ }
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index e67043d7..24a893cd 100644
--- a/README.md
+++ b/README.md
@@ -17,8 +17,8 @@ We will release OpenVK as soon as it's ready. As for now you can:
## Instances
* **[openvk.su](https://openvk.su/)**
-* **[openvk.uk](https://openvk.uk)** - official mirror of openvk.su ()
-* **[openvk.co](http://openvk.co)** - yet another official mirror of openvk.su without TLS ()
+* **[openvk.uk](https://openvk.uk)** - official mirror of openvk.su ()
+* **[openvk.co](http://openvk.co)** - yet another official mirror of openvk.su without TLS ()
* [social.fetbuk.ru](http://social.fetbuk.ru/)
* [vepurovk.xyz](http://vepurovk.xyz/)
@@ -34,7 +34,7 @@ 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)
-* 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 MySQL-compatible database.
diff --git a/README_RU.md b/README_RU.md
index 6bf29502..2b06d593 100644
--- a/README_RU.md
+++ b/README_RU.md
@@ -17,8 +17,8 @@ _[English](README.md)_
## Инстанции
* **[openvk.su](https://openvk.su/)**
-* **[openvk.uk](https://openvk.uk)** - официальное зеркало openvk.su ()
-* **[openvk.co](http://openvk.co)** - ещё одно официальное зеркало openvk.su без TLS ()
+* **[openvk.uk](https://openvk.uk)** - официальное зеркало openvk.su ()
+* **[openvk.co](http://openvk.co)** - ещё одно официальное зеркало openvk.su без TLS ()
* [social.fetbuk.ru](http://social.fetbuk.ru/)
* [vepurovk.xyz](http://vepurovk.xyz/)
@@ -82,7 +82,7 @@ ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions
* [Баг-трекер](https://github.com/openvk/openvk/projects/1)
* [Помощь в OVK](https://openvk.su/support?act=new)
-* Telegram-чат: Перейдите на [наш канал](https://t.me/openvkch) и откройте обсуждение в меню нашего канала.
+* Telegram-чат: Перейдите на [наш канал](https://t.me/openvk) и откройте обсуждение в меню нашего канала.
* [Reddit](https://www.reddit.com/r/openvk/)
* [Обсуждения](https://github.com/openvk/openvk/discussions)
* Чат в Matrix: #ovk:matrix.org
diff --git a/ServiceAPI/Apps.php b/ServiceAPI/Apps.php
new file mode 100644
index 00000000..521b117e
--- /dev/null
+++ b/ServiceAPI/Apps.php
@@ -0,0 +1,87 @@
+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);
+ }
+}
\ No newline at end of file
diff --git a/ServiceAPI/Wall.php b/ServiceAPI/Wall.php
index af74464f..628ceb22 100644
--- a/ServiceAPI/Wall.php
+++ b/ServiceAPI/Wall.php
@@ -1,5 +1,6 @@
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());
+ }
}
diff --git a/VKAPI/Handlers/Account.php b/VKAPI/Handlers/Account.php
index d1722b29..6f4ad0e6 100644
--- a/VKAPI/Handlers/Account.php
+++ b/VKAPI/Handlers/Account.php
@@ -8,16 +8,16 @@ final class Account extends VKAPIRequestHandler
$this->requireUser();
return (object) [
- "first_name" => $this->getUser()->getFirstName(),
- "id" => $this->getUser()->getId(),
- "last_name" => $this->getUser()->getLastName(),
- "home_town" => $this->getUser()->getHometown(),
- "status" => $this->getUser()->getStatus(),
- "bdate" => "1.1.1970", # TODO
- "bdate_visibility" => 0, # TODO
- "phone" => "+420 ** *** 228", # TODO
- "relation" => $this->getUser()->getMaritalStatus(),
- "sex" => $this->getUser()->isFemale() ? 1 : 2
+ "first_name" => $this->getUser()->getFirstName(),
+ "id" => $this->getUser()->getId(),
+ "last_name" => $this->getUser()->getLastName(),
+ "home_town" => $this->getUser()->getHometown(),
+ "status" => $this->getUser()->getStatus(),
+ "bdate" => $this->getUser()->getBirthday()->format('%e.%m.%Y'),
+ "bdate_visibility" => $this->getUser()->getBirthdayPrivacy(),
+ "phone" => "+420 ** *** 228", # TODO
+ "relation" => $this->getUser()->getMaritalStatus(),
+ "sex" => $this->getUser()->isFemale() ? 1 : 2
];
}
@@ -25,20 +25,18 @@ final class Account extends VKAPIRequestHandler
{
$this->requireUser();
- # Цiй метод є заглушка
-
return (object) [
- "2fa_required" => 0,
- "country" => "CZ", # TODO
- "eu_user" => false, # TODO
- "https_required" => 1,
- "intro" => 0,
- "community_comments" => false,
- "is_live_streaming_enabled" => false,
+ "2fa_required" => $this->getUser()->is2faEnabled() ? 1 : 0,
+ "country" => "CZ", # TODO
+ "eu_user" => false, # TODO
+ "https_required" => 1,
+ "intro" => 0,
+ "community_comments" => false,
+ "is_live_streaming_enabled" => false,
"is_new_live_streaming_enabled" => false,
- "lang" => 1,
- "no_wall_replies" => 0,
- "own_posts_default" => 0
+ "lang" => 1,
+ "no_wall_replies" => 0,
+ "own_posts_default" => 0
];
}
@@ -47,7 +45,8 @@ final class Account extends VKAPIRequestHandler
$this->requireUser();
$this->getUser()->setOnline(time());
-
+ $this->getUser()->save();
+
return 1;
}
@@ -68,9 +67,9 @@ final class Account extends VKAPIRequestHandler
function getCounters(string $filter = ""): object
{
return (object) [
- "friends" => $this->getUser()->getFollowersCount(),
+ "friends" => $this->getUser()->getFollowersCount(),
"notifications" => $this->getUser()->getNotificationsCount(),
- "messages" => $this->getUser()->getUnreadMessagesCount()
+ "messages" => $this->getUser()->getUnreadMessagesCount()
];
# TODO: Filter
diff --git a/VKAPI/Handlers/Audio.php b/VKAPI/Handlers/Audio.php
index 9fc4a535..3fa68e72 100644
--- a/VKAPI/Handlers/Audio.php
+++ b/VKAPI/Handlers/Audio.php
@@ -10,12 +10,12 @@ final class Audio extends VKAPIRequestHandler
return (object) [
"count" => 1,
"items" => [(object) [
- "id" => 1,
+ "id" => 1,
"owner_id" => 1,
- "artist" => "В ОВК ПОКА НЕТ МУЗЫКИ",
- "title" => "ЖДИТЕ :)))",
+ "artist" => "В ОВК ПОКА НЕТ МУЗЫКИ",
+ "title" => "ЖДИТЕ :)))",
"duration" => 22,
- "url" => $serverUrl . "/assets/packages/static/openvk/audio/nomusic.mp3"
+ "url" => $serverUrl . "/assets/packages/static/openvk/audio/nomusic.mp3"
]]
];
}
diff --git a/VKAPI/Handlers/Friends.php b/VKAPI/Handlers/Friends.php
index 760cef21..ca9b7573 100644
--- a/VKAPI/Handlers/Friends.php
+++ b/VKAPI/Handlers/Friends.php
@@ -1,6 +1,5 @@
requireUser();
- foreach ($users->get($user_id)->getFriends($offset, $count) as $friend) {
+ foreach($users->get($user_id)->getFriends($offset, $count) as $friend) {
$friends[$i] = $friend->getId();
$i++;
}
@@ -24,9 +23,8 @@ final class Friends extends VKAPIRequestHandler
$usersApi = new Users($this->getUser());
- if (!is_null($fields)) {
+ if(!is_null($fields))
$response = $usersApi->get(implode(',', $friends), $fields, 0, $count); # FIXME
- }
return (object) [
"count" => $users->get($user_id)->getFriendsCount(),
@@ -70,33 +68,28 @@ final class Friends extends VKAPIRequestHandler
$this->requireUser();
$users = new UsersRepo;
-
- $user = $users->get(intval($user_id));
+ $user = $users->get(intval($user_id));
- if(is_null($user)){
+ if(is_null($user)) {
$this->fail(177, "Cannot add this user to friends as user not found");
} else if($user->getId() == $this->getUser()->getId()) {
$this->fail(174, "Cannot add user himself as friend");
}
- switch ($user->getSubscriptionStatus($this->getUser())) {
+ switch($user->getSubscriptionStatus($this->getUser())) {
case 0:
$user->toggleSubscription($this->getUser());
return 1;
- break;
case 1:
$user->toggleSubscription($this->getUser());
return 2;
- break;
case 3:
return 2;
- break;
default:
return 1;
- break;
}
}
@@ -108,15 +101,13 @@ final class Friends extends VKAPIRequestHandler
$user = $users->get(intval($user_id));
- switch ($user->getSubscriptionStatus($this->getUser())) {
+ switch($user->getSubscriptionStatus($this->getUser())) {
case 3:
$user->toggleSubscription($this->getUser());
return 1;
- break;
default:
fail(15, "Access denied: No friend or friend request found.");
- break;
}
}
@@ -130,31 +121,43 @@ final class Friends extends VKAPIRequestHandler
$response = [];
- for ($i=0; $i < sizeof($friends); $i++) {
+ for($i=0; $i < sizeof($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)[
"friend_status" => $friend->getSubscriptionStatus($this->getUser()),
- "user_id" => $friend->getId()
+ "user_id" => $friend->getId()
];
}
return $response;
}
-}
\ No newline at end of file
+
+ 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
+ ];
+ }
+}
diff --git a/VKAPI/Handlers/Groups.php b/VKAPI/Handlers/Groups.php
index ff34d562..59b19fa4 100644
--- a/VKAPI/Handlers/Groups.php
+++ b/VKAPI/Handlers/Groups.php
@@ -1,12 +1,7 @@
requireUser();
- if ($user_id == 0) {
- foreach($this->getUser()->getClubs($offset+1) as $club) {
+ if($user_id == 0) {
+ foreach($this->getUser()->getClubs($offset+1) as $club)
$clbs[] = $club;
- }
$clbsCount = $this->getUser()->getClubCount();
} else {
$users = new UsersRepo;
- $user = $users->get($user_id);
- if (is_null($user)) {
+ $user = $users->get($user_id);
+
+ if(is_null($user))
$this->fail(15, "Access denied");
- }
- foreach($user->getClubs($offset+1) as $club) {
+
+ foreach($user->getClubs($offset+1) as $club)
$clbs[] = $club;
- }
+
$clbsCount = $user->getClubCount();
}
$rClubs;
$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++) {
+ $usr = $clbs[$i];
+ if(is_null($usr)) {
+ $rClubs[$i] = (object)[
+ "id" => $clbs[$i],
+ "name" => "DELETED",
+ "deactivated" => "deleted"
+ ];
+ } else if($clbs[$i] == NULL) {
- for ($i=0; $i < $ic; $i++) {
- $usr = $clbs[$i];
- if(is_null($usr))
- {
- $rClubs[$i] = (object)[
- "id" => $clbs[$i],
- "name" => "DELETED",
- "deactivated" => "deleted"
- ];
- }else if($clbs[$i] == NULL){
+ } else {
+ $rClubs[$i] = (object) [
+ "id" => $usr->getId(),
+ "name" => $usr->getName(),
+ "screen_name" => $usr->getShortCode(),
+ "is_closed" => false,
+ "can_access_closed" => true,
+ ];
- }else{
- $rClubs[$i] = (object)[
- "id" => $usr->getId(),
- "name" => $usr->getName(),
- "screen_name" => $usr->getShortCode(),
- "is_closed" => false,
- "can_access_closed" => true,
- ];
+ $flds = explode(',', $fields);
- $flds = explode(',', $fields);
-
- foreach($flds as $field) {
- switch ($field) {
- case 'verified':
- $rClubs[$i]->verified = intval($usr->isVerified());
- break;
- case 'has_photo':
- $rClubs[$i]->has_photo = is_null($usr->getAvatarPhoto()) ? 0 : 1;
- break;
- case 'photo_max_orig':
- $rClubs[$i]->photo_max_orig = $usr->getAvatarURL();
- break;
- case 'photo_max':
- $rClubs[$i]->photo_max = $usr->getAvatarURL();
- break;
- case 'members_count':
- $rClubs[$i]->members_count = $usr->getFollowersCount();
- break;
+ foreach($flds as $field) {
+ switch($field) {
+ case "verified":
+ $rClubs[$i]->verified = intval($usr->isVerified());
+ break;
+ case "has_photo":
+ $rClubs[$i]->has_photo = is_null($usr->getAvatarPhoto()) ? 0 : 1;
+ break;
+ case "photo_max_orig":
+ $rClubs[$i]->photo_max_orig = $usr->getAvatarURL();
+ break;
+ case "photo_max":
+ $rClubs[$i]->photo_max = $usr->getAvatarURL("original"); // ORIGINAL ANDREI CHINITEL 🥵🥵🥵🥵
+ break;
+ 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();
+ break;
+ }
}
}
}
+ } else {
+ $rClubs = [];
}
return (object) [
@@ -91,14 +104,12 @@ final class Groups extends VKAPIRequestHandler
function getById(string $group_ids = "", string $group_id = "", string $fields = ""): ?array
{
- $this->requireUser();
-
$clubs = new ClubsRepo;
- if ($group_ids == NULL && $group_id != NULL)
+ if($group_ids == NULL && $group_id != NULL)
$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");
$clbs = explode(',', $group_ids);
@@ -106,7 +117,7 @@ final class Groups extends VKAPIRequestHandler
$ic = sizeof($clbs);
- for ($i=0; $i < $ic; $i++) {
+ for($i=0; $i < $ic; $i++) {
if($i > 500)
break;
@@ -114,68 +125,88 @@ final class Groups extends VKAPIRequestHandler
$this->fail(100, "ты ошибся чутка, у айди группы убери минус");
$clb = $clubs->get((int) $clbs[$i]);
- if(is_null($clb))
- {
+ if(is_null($clb)) {
$response[$i] = (object)[
- "id" => intval($clbs[$i]),
- "name" => "DELETED",
+ "id" => intval($clbs[$i]),
+ "name" => "DELETED",
"screen_name" => "club".intval($clbs[$i]),
- "type" => "group",
+ "type" => "group",
"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)[
- "id" => $clb->getId(),
- "name" => $clb->getName(),
- "screen_name" => $clb->getShortCode() ?? "club".$clb->getId(),
- "is_closed" => false,
- "type" => "group",
+ "id" => $clb->getId(),
+ "name" => $clb->getName(),
+ "screen_name" => $clb->getShortCode() ?? "club".$clb->getId(),
+ "is_closed" => false,
+ "type" => "group",
"can_access_closed" => true,
];
$flds = explode(',', $fields);
foreach($flds as $field) {
- switch ($field) {
- case 'verified':
+ switch($field) {
+ case "verified":
$response[$i]->verified = intval($clb->isVerified());
break;
- case 'has_photo':
+ case "has_photo":
$response[$i]->has_photo = is_null($clb->getAvatarPhoto()) ? 0 : 1;
break;
- case 'photo_max_orig':
+ case "photo_max_orig":
$response[$i]->photo_max_orig = $clb->getAvatarURL();
break;
- case 'photo_max':
+ case "photo_max":
$response[$i]->photo_max = $clb->getAvatarURL();
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();
break;
- case 'site':
+ case "site":
$response[$i]->site = $clb->getWebsite();
break;
- case 'description':
+ case "description":
$response[$i]->desctiption = $clb->getDescription();
break;
- case 'contacts':
+ case "contacts":
$contacts;
$contactTmp = $clb->getManagers(1, true);
- foreach($contactTmp as $contact) {
+
+ foreach($contactTmp as $contact)
$contacts[] = array(
- 'user_id' => $contact->getUser()->getId(),
- 'desc' => $contact->getComment()
+ "user_id" => $contact->getUser()->getId(),
+ "desc" => $contact->getComment()
);
- }
+
$response[$i]->contacts = $contacts;
break;
- case 'can_post':
- if($clb->canBeModifiedBy($this->getUser()))
- $response[$i]->can_post = true;
- else
- $response[$i]->can_post = $clb->canPost();
+ case "can_post":
+ if(!is_null($this->getUser()))
+ if($clb->canBeModifiedBy($this->getUser()))
+ $response[$i]->can_post = true;
+ else
+ $response[$i]->can_post = $clb->canPost();
+ break;
+ case "is_member":
+ if(!is_null($this->getUser()))
+ $response[$i]->is_member = (int) $clb->getSubscriptionStatus($this->getUser());
break;
}
}
diff --git a/VKAPI/Handlers/Likes.php b/VKAPI/Handlers/Likes.php
index a9f184b6..38a76893 100644
--- a/VKAPI/Handlers/Likes.php
+++ b/VKAPI/Handlers/Likes.php
@@ -9,39 +9,38 @@ final class Likes extends VKAPIRequestHandler
{
$this->requireUser();
- switch ($type) {
- case 'post':
+ switch($type) {
+ case "post":
$post = (new PostsRepo)->getPostById($owner_id, $item_id);
- if (is_null($post)) $this->fail(100, 'One of the parameters specified was missing or invalid: object not found');
+ if(is_null($post))
+ $this->fail(100, "One of the parameters specified was missing or invalid: object not found");
$post->setLike(true, $this->getUser());
- return (object)[
+
+ return (object) [
"likes" => $post->getLikesCount()
];
- break;
default:
- $this->fail(100, 'One of the parameters specified was missing or invalid: incorrect type');
- break;
+ $this->fail(100, "One of the parameters specified was missing or invalid: incorrect type");
}
}
- function remove(string $type, int $owner_id, int $item_id): object
+ function delete(string $type, int $owner_id, int $item_id): object
{
$this->requireUser();
- switch ($type) {
- case 'post':
+ switch($type) {
+ case "post":
$post = (new PostsRepo)->getPostById($owner_id, $item_id);
- if (is_null($post)) $this->fail(100, 'One of the parameters specified was missing or invalid: object not found');
+ if (is_null($post))
+ $this->fail(100, "One of the parameters specified was missing or invalid: object not found");
$post->setLike(false, $this->getUser());
- return (object)[
+ return (object) [
"likes" => $post->getLikesCount()
];
- break;
default:
- $this->fail(100, 'One of the parameters specified was missing or invalid: incorrect type');
- break;
+ $this->fail(100, "One of the parameters specified was missing or invalid: incorrect type");
}
}
@@ -49,26 +48,26 @@ final class Likes extends VKAPIRequestHandler
{
$this->requireUser();
- switch ($type) {
- case 'post':
+ switch($type) {
+ case "post":
$user = (new UsersRepo)->get($user_id);
- if (is_null($user)) return (object)[
- "liked" => 0,
- "copied" => 0,
- "sex" => 0
- ];
+ if (is_null($user))
+ return (object) [
+ "liked" => 0,
+ "copied" => 0,
+ "sex" => 0
+ ];
$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)[
- "liked" => (int) $post->hasLikeFrom($user),
+ return (object) [
+ "liked" => (int) $post->hasLikeFrom($user),
"copied" => 0 # TODO: handle this
];
- break;
default:
- $this->fail(100, 'One of the parameters specified was missing or invalid: incorrect type');
- break;
+ $this->fail(100, "One of the parameters specified was missing or invalid: incorrect type");
}
}
}
diff --git a/VKAPI/Handlers/Messages.php b/VKAPI/Handlers/Messages.php
index 456e31df..c1a85a0a 100644
--- a/VKAPI/Handlers/Messages.php
+++ b/VKAPI/Handlers/Messages.php
@@ -40,7 +40,7 @@ final class Messages extends VKAPIRequestHandler
continue;
$author = $message->getSender()->getId() === $this->getUser()->getId() ? $message->getRecipient()->getId() : $message->getSender()->getId();
- $rMsg = new APIMsg;
+ $rMsg = new APIMsg;
$rMsg->id = $message->getId();
$rMsg->user_id = $author;
@@ -99,7 +99,7 @@ final class Messages extends VKAPIRequestHandler
if(!$peer)
$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");
# Finally we get to send a message!
@@ -123,9 +123,8 @@ final class Messages extends VKAPIRequestHandler
$items = [];
foreach($ids as $id) {
$message = $msgs->get((int) $id);
- if(!$message || $message->getSender()->getId() !== $this->getUser()->getId() && $message->getRecipient()->getId() !== $this->getUser()->getId()) {
+ if(!$message || $message->getSender()->getId() !== $this->getUser()->getId() && $message->getRecipient()->getId() !== $this->getUser()->getId())
$items[$id] = 0;
- }
$message->delete();
$items[$id] = 1;
@@ -153,6 +152,7 @@ final class Messages extends VKAPIRequestHandler
$this->requireUser();
$convos = (new MSGRepo)->getCorrespondencies($this->getUser(), -1, $count, $offset);
+ $convosCount = (new MSGRepo)->getCorrespondenciesCount($this->getUser());
$list = [];
$users = [];
@@ -186,7 +186,7 @@ final class Messages extends VKAPIRequestHandler
else
$author = $lastMessage->getSender()->getId();
- $lastMessagePreview = new APIMsg;
+ $lastMessagePreview = new APIMsg;
$lastMessagePreview->id = $lastMessage->getId();
$lastMessagePreview->user_id = $author;
$lastMessagePreview->from_id = $lastMessage->getSender()->getId();
@@ -196,9 +196,8 @@ final class Messages extends VKAPIRequestHandler
$lastMessagePreview->body = $lastMessage->getText(false);
$lastMessagePreview->text = $lastMessage->getText(false);
$lastMessagePreview->emoji = true;
-
+
if($extended == 1) {
- $users[] = $lastMessage->getSender()->getId();
$users[] = $author;
}
}
@@ -211,21 +210,81 @@ final class Messages extends VKAPIRequestHandler
if($extended == 0){
return (object) [
- "count" => sizeof($list),
+ "count" => $convosCount,
"items" => $list,
];
} else {
+ $users[] = $this->getUser()->getId();
$users = array_unique($users);
return (object) [
- "count" => sizeof($list),
- "items" => $list,
- "profiles" => (new APIUsers)->get(implode(',', $users), $fields, $offset, $count)
+ "count" => $convosCount,
+ "items" => $list,
+ "profiles" => (!empty($users) ? (new APIUsers)->get(implode(',', $users), $fields, 0, $count+1) : [])
];
}
}
+
+ 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): object
+ 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();
@@ -257,10 +316,18 @@ final class Messages extends VKAPIRequestHandler
$results[] = $rMsg;
}
- return (object) [
+ $output = [
"count" => sizeof($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
diff --git a/VKAPI/Handlers/Newsfeed.php b/VKAPI/Handlers/Newsfeed.php
index dd4fd436..06474220 100644
--- a/VKAPI/Handlers/Newsfeed.php
+++ b/VKAPI/Handlers/Newsfeed.php
@@ -1,8 +1,5 @@
requireUser();
- if($offset != 0) $start_from = $offset;
-
$id = $this->getUser()->getId();
$subs = DatabaseConnection::i()
->getContext()
@@ -26,17 +21,20 @@ final class Newsfeed extends VKAPIRequestHandler
$ids[] = $this->getUser()->getId();
$posts = DatabaseConnection::i()
- ->getContext()
- ->table("posts")
- ->select("id")
- ->where("wall IN (?)", $ids)
- ->where("deleted", 0)
- ->order("created DESC");
+ ->getContext()
+ ->table("posts")
+ ->select("id")
+ ->where("wall IN (?)", $ids)
+ ->where("deleted", 0)
+ ->where("id < (?)", empty($start_from) ? time()+1 : $start_from)
+ ->order("created DESC");
$rposts = [];
foreach($posts->page((int) ($offset + 1), $count) as $post)
$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;
}
}
diff --git a/VKAPI/Handlers/Ovk.php b/VKAPI/Handlers/Ovk.php
index 42243cf1..a260f1c4 100644
--- a/VKAPI/Handlers/Ovk.php
+++ b/VKAPI/Handlers/Ovk.php
@@ -1,5 +1,6 @@
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;
+ }
}
diff --git a/VKAPI/Handlers/Pay.php b/VKAPI/Handlers/Pay.php
new file mode 100644
index 00000000..e5fb93a7
--- /dev/null
+++ b/VKAPI/Handlers/Pay.php
@@ -0,0 +1,42 @@
+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;
+ }
+}
\ No newline at end of file
diff --git a/VKAPI/Handlers/Users.php b/VKAPI/Handlers/Users.php
index 8aa25b69..6185a250 100644
--- a/VKAPI/Handlers/Users.php
+++ b/VKAPI/Handlers/Users.php
@@ -7,8 +7,6 @@ final class Users extends VKAPIRequestHandler
{
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();
$users = new UsersRepo;
@@ -16,138 +14,137 @@ final class Users extends VKAPIRequestHandler
$user_ids = (string) $authuser->getId();
$usrs = explode(',', $user_ids);
- $response;
+ $response = array();
$ic = sizeof($usrs);
- if(sizeof($usrs) > $count) $ic = $count;
+ if(sizeof($usrs) > $count)
+ $ic = $count;
$usrs = array_slice($usrs, $offset * $count);
- for ($i=0; $i < $ic; $i++) {
- $usr = $users->get((int) $usrs[$i]);
- if(is_null($usr))
- {
- $response[$i] = (object)[
- "id" => $usrs[$i],
- "first_name" => "DELETED",
- "last_name" => "",
- "deactivated" => "deleted"
- ];
- }else if($usrs[$i] == NULL){
+ for($i=0; $i < $ic; $i++) {
+ if($usrs[$i] != 0) {
+ $usr = $users->get((int) $usrs[$i]);
+ if(is_null($usr) || $usr->isDeleted()) {
+ $response[$i] = (object)[
+ "id" => (int) $usrs[$i],
+ "first_name" => "DELETED",
+ "last_name" => "",
+ "deactivated" => "deleted"
+ ];
+ } else if($usrs[$i] == NULL) {
- }else{
- $response[$i] = (object)[
- "id" => $usr->getId(),
- "first_name" => $usr->getFirstName(),
- "last_name" => $usr->getLastName(),
- "is_closed" => false,
- "can_access_closed" => true,
- ];
+ } else {
+ $response[$i] = (object)[
+ "id" => $usr->getId(),
+ "first_name" => $usr->getFirstName(),
+ "last_name" => $usr->getLastName(),
+ "is_closed" => false,
+ "can_access_closed" => true,
+ ];
- $flds = explode(',', $fields);
+ $flds = explode(',', $fields);
- foreach($flds as $field) {
- switch ($field) {
- case 'verified':
- $response[$i]->verified = intval($usr->isVerified());
- break;
- case 'sex':
- $response[$i]->sex = $usr->isFemale() ? 1 : 2;
- break;
- case 'has_photo':
- $response[$i]->has_photo = is_null($usr->getAvatarPhoto()) ? 0 : 1;
- break;
- case 'photo_max_orig':
- $response[$i]->photo_max_orig = $usr->getAvatarURL();
- break;
- case 'photo_max':
- $response[$i]->photo_max = $usr->getAvatarURL("original");
- break;
- case 'photo_50':
- $response[$i]->photo_50 = $usr->getAvatarURL();
- break;
- case 'photo_100':
- $response[$i]->photo_50 = $usr->getAvatarURL("tiny");
- break;
- case 'photo_200':
- $response[$i]->photo_50 = $usr->getAvatarURL("normal");
- break;
- case 'photo_200_orig': # вообще не ебу к чему эта строка ну пусть будет кек
- $response[$i]->photo_50 = $usr->getAvatarURL("normal");
- break;
- case 'photo_400_orig':
- $response[$i]->photo_50 = $usr->getAvatarURL("normal");
- break;
-
- # Она хочет быть выебанной видя матан
- # Покайфу когда ты Виет а вокруг лишь дискриминант
- case 'status':
- if($usr->getStatus() != NULL)
- $response[$i]->status = $usr->getStatus();
- break;
- case 'screen_name':
- if($usr->getShortCode() != NULL)
- $response[$i]->screen_name = $usr->getShortCode();
- break;
- case 'friend_status':
- switch($usr->getSubscriptionStatus($authuser)) {
- case 3:
- case 0:
- $response[$i]->friend_status = $usr->getSubscriptionStatus($authuser);
- break;
- case 1:
- $response[$i]->friend_status = 2;
- break;
- case 2:
- $response[$i]->friend_status = 1;
- break;
- }
- break;
- case 'last_seen':
- if ($usr->onlineStatus() == 0) {
- $response[$i]->last_seen = (object) [
- "platform" => 1,
- "time" => $usr->getOnline()->timestamp()
- ];
- }
- case 'music':
- $response[$i]->music = $usr->getFavoriteMusic();
- break;
- case 'movies':
- $response[$i]->movies = $usr->getFavoriteFilms();
- break;
- case 'tv':
- $response[$i]->tv = $usr->getFavoriteShows();
- break;
- case 'books':
- $response[$i]->books = $usr->getFavoriteBooks();
- break;
- case 'city':
- $response[$i]->city = $usr->getCity();
- break;
- case 'interests':
- $response[$i]->interests = $usr->getInterests();
- break;
- }
- }
+ foreach($flds as $field) {
+ switch($field) {
+ case "verified":
+ $response[$i]->verified = intval($usr->isVerified());
+ break;
+ case "sex":
+ $response[$i]->sex = $usr->isFemale() ? 1 : 2;
+ break;
+ case "has_photo":
+ $response[$i]->has_photo = is_null($usr->getAvatarPhoto()) ? 0 : 1;
+ break;
+ case "photo_max_orig":
+ $response[$i]->photo_max_orig = $usr->getAvatarURL();
+ break;
+ case "photo_max":
+ $response[$i]->photo_max = $usr->getAvatarURL("original");
+ break;
+ case "photo_50":
+ $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;
+
+ # Она хочет быть выебанной видя матан
+ # Покайфу когда ты Виет а вокруг лишь дискриминант
- if($usr->getOnline()->timestamp() + 300 > time()) {
- $response[$i]->online = 1;
- }else{
- $response[$i]->online = 0;
+ # ору а когда я это успел написать
+ # вова кстати не матерись в коде мамка же спалит азщазаззазщазазаззазазазх
+ case "status":
+ if($usr->getStatus() != NULL)
+ $response[$i]->status = $usr->getStatus();
+ break;
+ case "screen_name":
+ if($usr->getShortCode() != NULL)
+ $response[$i]->screen_name = $usr->getShortCode();
+ break;
+ case "friend_status":
+ switch($usr->getSubscriptionStatus($authuser)) {
+ case 3:
+ # NOTICE falling through
+ case 0:
+ $response[$i]->friend_status = $usr->getSubscriptionStatus($authuser);
+ break;
+ case 1:
+ $response[$i]->friend_status = 2;
+ break;
+ case 2:
+ $response[$i]->friend_status = 1;
+ break;
+ }
+ break;
+ case "last_seen":
+ if ($usr->onlineStatus() == 0)
+ $response[$i]->last_seen = (object) [
+ "platform" => 1,
+ "time" => $usr->getOnline()->timestamp()
+ ];
+ case "music":
+ $response[$i]->music = $usr->getFavoriteMusic();
+ break;
+ case "movies":
+ $response[$i]->movies = $usr->getFavoriteFilms();
+ break;
+ case "tv":
+ $response[$i]->tv = $usr->getFavoriteShows();
+ break;
+ case "books":
+ $response[$i]->books = $usr->getFavoriteBooks();
+ break;
+ case "city":
+ $response[$i]->city = $usr->getCity();
+ break;
+ case "interests":
+ $response[$i]->interests = $usr->getInterests();
+ break;
+ }
+ }
+
+ if($usr->getOnline()->timestamp() + 300 > time())
+ $response[$i]->online = 1;
+ else
+ $response[$i]->online = 0;
}
-
- }
+ }
}
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
{
$offset++;
@@ -157,15 +154,13 @@ final class Users extends VKAPIRequestHandler
$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();
- }
$response = $followers;
- if (!is_null($fields)) {
+ if(!is_null($fields))
$response = $this->get(implode(',', $followers), $fields, 0, $count);
- }
return (object) [
"count" => $users->get($user_id)->getFollowersCount(),
@@ -173,18 +168,17 @@ 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;
$array = [];
- $find = $users->find($q);
+ $find = $users->find($q);
- foreach ($find as $user) {
+ foreach ($find as $user)
$array[] = $user->getId();
- }
- return (object)[
+ return (object) [
"count" => $find->size(),
"items" => $this->get(implode(',', $array), $fields, $offset, $count)
];
diff --git a/VKAPI/Handlers/Wall.php b/VKAPI/Handlers/Wall.php
index 50677435..c669cd02 100644
--- a/VKAPI/Handlers/Wall.php
+++ b/VKAPI/Handlers/Wall.php
@@ -1,76 +1,98 @@
getPostCountOnUserWall((int) $owner_id);
+ $groups = [];
+ $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();
$attachments = [];
+ $repost = [];
foreach($post->getChildren() as $attachment) {
if($attachment instanceof \openvk\Web\Models\Entities\Photo) {
if($attachment->isDeleted())
continue;
- $attachments[] = [
- "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
- ]
+ $attachments[] = $this->getApiPhoto($attachment);
+ } else if ($attachment instanceof \openvk\Web\Models\Entities\Post) {
+ $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(),
+ "owner_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(),
+ "from_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(),
+ "date" => $attachment->getPublicationTime()->timestamp(),
+ "post_type" => "post",
+ "text" => $attachment->getText(false),
+ "attachments" => $repostAttachments,
+ "post_source" => [
+ "type" => "vk"
+ ],
];
}
}
$items[] = (object)[
- "id" => $post->getVirtualId(),
- "from_id" => $from_id,
- "owner_id" => $post->getTargetWall(),
- "date" => $post->getPublicationTime()->timestamp(),
- "post_type" => "post",
- "text" => $post->getText(),
- "can_edit" => 0, # TODO
- "can_delete" => $post->canBeDeletedBy($this->getUser()),
- "can_pin" => $post->canBePinnedBy($this->getUser()),
- "can_archive" => false, # TODO MAYBE
- "is_archived" => false,
- "is_pinned" => $post->isPinned(),
- "attachments" => $attachments,
- "post_source" => (object)["type" => "vk"],
- "comments" => (object)[
- "count" => $post->getCommentsCount(),
+ "id" => $post->getVirtualId(),
+ "from_id" => $from_id,
+ "owner_id" => $post->getTargetWall(),
+ "date" => $post->getPublicationTime()->timestamp(),
+ "post_type" => "post",
+ "text" => $post->getText(false),
+ "copy_history" => $repost,
+ "can_edit" => 0, # TODO
+ "can_delete" => $post->canBeDeletedBy($this->getUser()),
+ "can_pin" => $post->canBePinnedBy($this->getUser()),
+ "can_archive" => false, # TODO MAYBE
+ "is_archived" => false,
+ "is_pinned" => $post->isPinned(),
+ "attachments" => $attachments,
+ "post_source" => (object)["type" => "vk"],
+ "comments" => (object)[
+ "count" => $post->getCommentsCount(),
"can_post" => 1
],
"likes" => (object)[
- "count" => $post->getLikesCount(),
- "user_likes" => (int) $post->hasLikeFrom($this->getUser()),
- "can_like" => 1,
+ "count" => $post->getLikesCount(),
+ "user_likes" => (int) $post->hasLikeFrom($this->getUser()),
+ "can_like" => 1,
"can_publish" => 1,
],
"reposts" => (object)[
- "count" => $post->getRepostCount(),
+ "count" => $post->getRepostCount(),
"user_reposted" => 0
]
];
@@ -78,163 +100,140 @@ final class Wall extends VKAPIRequestHandler
if ($from_id > 0)
$profiles[] = $from_id;
else
- $groups[] = $from_id * -1;
+ $groups[] = $from_id * -1;
$attachments = NULL; # free attachments so it will not clone everythingg
}
- if($extended == 1)
- {
+ if($extended == 1) {
$profiles = array_unique($profiles);
- $groups = array_unique($groups);
+ $groups = array_unique($groups);
$profilesFormatted = [];
- $groupsFormatted = [];
+ $groupsFormatted = [];
- foreach ($profiles as $prof) {
- $user = (new UsersRepo)->get($prof);
+ foreach($profiles as $prof) {
+ $user = (new UsersRepo)->get($prof);
$profilesFormatted[] = (object)[
- "first_name" => $user->getFirstName(),
- "id" => $user->getId(),
- "last_name" => $user->getLastName(),
+ "first_name" => $user->getFirstName(),
+ "id" => $user->getId(),
+ "last_name" => $user->getLastName(),
"can_access_closed" => false,
- "is_closed" => false,
- "sex" => $user->isFemale() ? 1 : 2,
- "screen_name" => $user->getShortCode(),
- "photo_50" => $user->getAvatarUrl(),
- "photo_100" => $user->getAvatarUrl(),
- "online" => $user->isOnline()
+ "is_closed" => false,
+ "sex" => $user->isFemale() ? 1 : 2,
+ "screen_name" => $user->getShortCode(),
+ "photo_50" => $user->getAvatarUrl(),
+ "photo_100" => $user->getAvatarUrl(),
+ "online" => $user->isOnline()
];
}
foreach($groups as $g) {
- $group = (new ClubsRepo)->get($g);
+ $group = (new ClubsRepo)->get($g);
$groupsFormatted[] = (object)[
- "id" => $group->getId(),
- "name" => $group->getName(),
+ "id" => $group->getId(),
+ "name" => $group->getName(),
"screen_name" => $group->getShortCode(),
- "is_closed" => 0,
- "type" => "group",
- "photo_50" => $group->getAvatarUrl(),
- "photo_100" => $group->getAvatarUrl(),
- "photo_200" => $group->getAvatarUrl(),
+ "is_closed" => 0,
+ "type" => "group",
+ "photo_50" => $group->getAvatarUrl(),
+ "photo_100" => $group->getAvatarUrl(),
+ "photo_200" => $group->getAvatarUrl(),
];
}
- return (object)[
- "count" => $count,
- "items" => (array)$items,
- "profiles" => (array)$profilesFormatted,
- "groups" => (array)$groupsFormatted
+ return (object) [
+ "count" => $cnt,
+ "items" => $items,
+ "profiles" => $profilesFormatted,
+ "groups" => $groupsFormatted
];
- }
- else
- return (object)[
- "count" => $count,
- "items" => (array)$items
+ } else
+ return (object) [
+ "count" => $cnt,
+ "items" => $items
];
}
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 = [];
- $groups = [];
- # $count = $posts->getPostCountOnUserWall((int) $owner_id);
+ $groups = [];
- $psts = explode(",", $posts);
+ $psts = explode(',', $posts);
- foreach($psts as $pst)
- {
- $id = explode("_", $pst);
+ foreach($psts as $pst) {
+ $id = explode("_", $pst);
$post = (new PostsRepo)->getPostById(intval($id[0]), intval($id[1]));
if($post) {
$from_id = get_class($post->getOwner()) == "openvk\Web\Models\Entities\Club" ? $post->getOwner()->getId() * (-1) : $post->getOwner()->getId();
- $attachments;
- foreach($post->getChildren() as $attachment)
- {
- if($attachment instanceof \openvk\Web\Models\Entities\Photo)
- {
- $attachments[] = [
- "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(
- [
- "height" => 2560,
- "url" => $attachment->getURLBySizeId("normal"),
- "type" => "m",
- "width" => 2560,
- ],
- [
- "height" => 130,
- "url" => $attachment->getURLBySizeId("tiny"),
- "type" => "o",
- "width" => 130,
- ],
- [
- "height" => 604,
- "url" => $attachment->getURLBySizeId("normal"),
- "type" => "p",
- "width" => 604,
- ],
- [
- "height" => 807,
- "url" => $attachment->getURLBySizeId("large"),
- "type" => "q",
- "width" => 807,
- ],
- [
- "height" => 1280,
- "url" => $attachment->getURLBySizeId("larger"),
- "type" => "r",
- "width" => 1280,
- ],
- [
- "height" => 75, # Для временного компросима оставляю статическое число. Если каждый раз обращаться к файлу за количеством пикселов, то наступает пuпuська полная с производительностью, так что пока так
- "url" => $attachment->getURLBySizeId("miniscule"),
- "type" => "s",
- "width" => 75,
- ]),
- "text" => "",
- "has_tags" => false
- ]
+ $attachments = [];
+ $repost = []; // чел высрал семь сигарет 😳 помянем 🕯
+ foreach($post->getChildren() as $attachment) {
+ if($attachment instanceof \openvk\Web\Models\Entities\Photo) {
+ $attachments[] = $this->getApiPhoto($attachment);
+ } else if ($attachment instanceof \openvk\Web\Models\Entities\Post) {
+ $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(),
+ "owner_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(),
+ "from_id" => $attachment->isPostedOnBehalfOfGroup() ? $attachment->getOwner()->getId() * -1 : $attachment->getOwner()->getId(),
+ "date" => $attachment->getPublicationTime()->timestamp(),
+ "post_type" => "post",
+ "text" => $attachment->getText(false),
+ "attachments" => $repostAttachments,
+ "post_source" => [
+ "type" => "vk"
+ ],
];
}
}
$items[] = (object)[
- "id" => $post->getVirtualId(),
- "from_id" => $from_id,
- "owner_id" => $post->getTargetWall(),
- "date" => $post->getPublicationTime()->timestamp(),
- "post_type" => "post",
- "text" => $post->getText(),
- "can_edit" => 0, # TODO
- "can_delete" => $post->canBeDeletedBy($user),
- "can_pin" => $post->canBePinnedBy($user),
- "can_archive" => false, # TODO MAYBE
- "is_archived" => false,
- "is_pinned" => $post->isPinned(),
- "post_source" => (object)["type" => "vk"],
- "attachments" => $attachments,
- "comments" => (object)[
- "count" => $post->getCommentsCount(),
+ "id" => $post->getVirtualId(),
+ "from_id" => $from_id,
+ "owner_id" => $post->getTargetWall(),
+ "date" => $post->getPublicationTime()->timestamp(),
+ "post_type" => "post",
+ "text" => $post->getText(false),
+ "copy_history" => $repost,
+ "can_edit" => 0, # TODO
+ "can_delete" => $post->canBeDeletedBy($user),
+ "can_pin" => $post->canBePinnedBy($user),
+ "can_archive" => false, # TODO MAYBE
+ "is_archived" => false,
+ "is_pinned" => $post->isPinned(),
+ "post_source" => (object)["type" => "vk"],
+ "attachments" => $attachments,
+ "comments" => (object)[
+ "count" => $post->getCommentsCount(),
"can_post" => 1
],
"likes" => (object)[
- "count" => $post->getLikesCount(),
- "user_likes" => (int) $post->hasLikeFrom($user),
- "can_like" => 1,
+ "count" => $post->getLikesCount(),
+ "user_likes" => (int) $post->hasLikeFrom($user),
+ "can_like" => 1,
"can_publish" => 1,
],
"reposts" => (object)[
- "count" => $post->getRepostCount(),
+ "count" => $post->getRepostCount(),
"user_reposted" => 0
]
];
@@ -242,58 +241,57 @@ final class Wall extends VKAPIRequestHandler
if ($from_id > 0)
$profiles[] = $from_id;
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);
- $groups = array_unique($groups);
+ $groups = array_unique($groups);
$profilesFormatted = [];
- $groupsFormatted = [];
+ $groupsFormatted = [];
- foreach ($profiles as $prof) {
- $user = (new UsersRepo)->get($prof);
+ foreach($profiles as $prof) {
+ $user = (new UsersRepo)->get($prof);
$profilesFormatted[] = (object)[
- "first_name" => $user->getFirstName(),
- "id" => $user->getId(),
- "last_name" => $user->getLastName(),
+ "first_name" => $user->getFirstName(),
+ "id" => $user->getId(),
+ "last_name" => $user->getLastName(),
"can_access_closed" => false,
- "is_closed" => false,
- "sex" => $user->isFemale() ? 1 : 2,
- "screen_name" => $user->getShortCode(),
- "photo_50" => $user->getAvatarUrl(),
- "photo_100" => $user->getAvatarUrl(),
- "online" => $user->isOnline()
+ "is_closed" => false,
+ "sex" => $user->isFemale() ? 1 : 2,
+ "screen_name" => $user->getShortCode(),
+ "photo_50" => $user->getAvatarUrl(),
+ "photo_100" => $user->getAvatarUrl(),
+ "online" => $user->isOnline()
];
}
foreach($groups as $g) {
- $group = (new ClubsRepo)->get($g);
+ $group = (new ClubsRepo)->get($g);
$groupsFormatted[] = (object)[
- "id" => $group->getId(),
- "name" => $group->getName(),
- "screen_name" => $group->getShortCode(),
- "is_closed" => 0,
- "type" => "group",
- "photo_50" => $group->getAvatarUrl(),
- "photo_100" => $group->getAvatarUrl(),
- "photo_200" => $group->getAvatarUrl(),
+ "id" => $group->getId(),
+ "name" => $group->getName(),
+ "screen_name" => $group->getShortCode(),
+ "is_closed" => 0,
+ "type" => "group",
+ "photo_50" => $group->getAvatarUrl(),
+ "photo_100" => $group->getAvatarUrl(),
+ "photo_200" => $group->getAvatarUrl(),
];
}
- return (object)[
- "items" => (array)$items,
+ return (object) [
+ "items" => (array)$items,
"profiles" => (array)$profilesFormatted,
- "groups" => (array)$groupsFormatted
+ "groups" => (array)$groupsFormatted
];
- }
- else
- return (object)[
+ } else
+ return (object) [
"items" => (array)$items
];
}
@@ -302,7 +300,7 @@ final class Wall extends VKAPIRequestHandler
{
$this->requireUser();
- $owner_id = intval($owner_id);
+ $owner_id = intval($owner_id);
$wallOwner = ($owner_id > 0 ? (new UsersRepo)->get($owner_id) : (new ClubsRepo)->get($owner_id * -1))
?? $this->fail(18, "User was deleted or banned");
@@ -381,4 +379,201 @@ final class Wall extends VKAPIRequestHandler
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
+ ]
+ ];
+ }
}
diff --git a/Web/Models/Entities/Application.php b/Web/Models/Entities/Application.php
new file mode 100644
index 00000000..74569485
--- /dev/null
+++ b/Web/Models/Entities/Application.php
@@ -0,0 +1,316 @@
+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);
+ }
+}
\ No newline at end of file
diff --git a/Web/Models/Entities/BannedLink.php b/Web/Models/Entities/BannedLink.php
new file mode 100644
index 00000000..09c42e39
--- /dev/null
+++ b/Web/Models/Entities/BannedLink.php
@@ -0,0 +1,49 @@
+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;
+ }
+}
diff --git a/Web/Models/Entities/Club.php b/Web/Models/Entities/Club.php
index ffe81ab4..a5a3027b 100644
--- a/Web/Models/Entities/Club.php
+++ b/Web/Models/Entities/Club.php
@@ -67,7 +67,7 @@ class Club extends RowModel
function getName(): string
{
- return ovk_proc_strtr($this->getRecord()->name, 32);
+ return $this->getRecord()->name;
}
function getCanonicalName(): string
diff --git a/Web/Models/Entities/Message.php b/Web/Models/Entities/Message.php
index de840606..97f3cf69 100644
--- a/Web/Models/Entities/Message.php
+++ b/Web/Models/Entities/Message.php
@@ -60,6 +60,17 @@ class Message extends RowModel
{
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.
@@ -125,7 +136,7 @@ class Message extends RowModel
"name" => $author->getFirstName().$unreadmsg,
],
"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(),
],
"text" => $this->getText(),
diff --git a/Web/Models/Entities/Note.php b/Web/Models/Entities/Note.php
index 762ebef8..a536602a 100644
--- a/Web/Models/Entities/Note.php
+++ b/Web/Models/Entities/Note.php
@@ -74,9 +74,19 @@ class Note extends Postable
$config->set("Attr.AllowedClasses", [
"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);
- return $purifier->purify($this->getRecord()->source);
+ return $purifier->purify($source);
}
function getName(): string
@@ -91,6 +101,9 @@ class Note extends Postable
function getText(): string
{
+ if(is_null($this->getRecord()))
+ return $this->renderHTML();
+
$cached = $this->getRecord()->cached_content;
if(!$cached) {
$cached = $this->renderHTML();
diff --git a/Web/Models/Entities/Photo.php b/Web/Models/Entities/Photo.php
index 71d5efcb..628589db 100644
--- a/Web/Models/Entities/Photo.php
+++ b/Web/Models/Entities/Photo.php
@@ -243,8 +243,11 @@ class Photo extends Media
$photo->setFile($file);
$photo->save();
- if(!is_null($album))
+ if(!is_null($album)) {
$album->addPhoto($photo);
+ $album->setEdited(time());
+ $album->save();
+ }
return $photo;
}
diff --git a/Web/Models/Entities/Post.php b/Web/Models/Entities/Post.php
index 695dde87..4afb4baa 100644
--- a/Web/Models/Entities/Post.php
+++ b/Web/Models/Entities/Post.php
@@ -84,6 +84,11 @@ class Post extends Postable
{
return ($this->getRecord()->flags & 0b01000000) > 0;
}
+
+ function isDeactivationMessage(): bool
+ {
+ return ($this->getRecord()->flags & 0b00100000) > 0;
+ }
function isExplicit(): bool
{
diff --git a/Web/Models/Entities/Traits/TRichText.php b/Web/Models/Entities/Traits/TRichText.php
index c8a85e70..f2229250 100644
--- a/Web/Models/Entities/Traits/TRichText.php
+++ b/Web/Models/Entities/Traits/TRichText.php
@@ -35,12 +35,12 @@ trait TRichText
"%(([A-z]++):\/\/(\S*?\.\S*?))([\s)\[\]{},\"\'<]|\.\s|$)%",
(function (array $matches): string {
$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]);
$rel = $this->isAd() ? "sponsored" : "ugc";
- return "$link" . htmlentities($matches[4]);
+ return "$link" . htmlentities($matches[4]);
}),
$text
);
@@ -75,6 +75,8 @@ trait TRichText
$text = $this->removeZalgo($text);
$text = nl2br($text);
+ } else {
+ $text = str_replace("\r\n","\n", $text);
}
if(OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["christian"])
diff --git a/Web/Models/Entities/User.php b/Web/Models/Entities/User.php
index 7c432561..115bf8c2 100644
--- a/Web/Models/Entities/User.php
+++ b/Web/Models/Entities/User.php
@@ -145,24 +145,32 @@ class User extends RowModel
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
{
- return $this->getRecord()->deleted ? "DELETED" : $this->getRecord()->pseudo;
+ return ($this->isDeleted() && !$this->isDeactivated() ? "DELETED" : $this->getRecord()->pseudo);
}
function getFullName(): string
{
- if($this->getRecord()->deleted)
+ if($this->isDeleted() && !$this->isDeactivated())
return "DELETED";
$pseudo = $this->getPseudo();
@@ -187,7 +195,7 @@ class User extends RowModel
function getCanonicalName(): string
{
- if($this->getRecord()->deleted)
+ if($this->isDeleted() && !$this->isDeactivated())
return "DELETED";
else
return $this->getFirstName() . " " . $this->getLastName();
@@ -285,6 +293,19 @@ class User extends RowModel
{
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
{
@@ -343,7 +364,15 @@ class User extends RowModel
function getBirthday(): ?DateTime
{
- return new DateTime($this->getRecord()->birthday);
+ if(is_null($this->getRecord()->birthday))
+ return NULL;
+ else
+ return new DateTime($this->getRecord()->birthday);
+ }
+
+ function getBirthdayPrivacy(): int
+ {
+ return $this->getRecord()->birthday_privacy;
}
function getAge(): ?int
@@ -471,6 +500,16 @@ class User extends RowModel
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
{
return $this->_abstractRelationGenerator("get-followers", $page, $limit);
@@ -729,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) {
$subs = DatabaseConnection::i()->getContext()->table("subscriptions");
@@ -743,9 +782,31 @@ class User extends RowModel
}
$this->setBlock_Reason($reason);
+ $this->setUnblock_time($unban_time);
$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
{
$ver = $this->getPendingPhoneVerification();
@@ -911,7 +972,15 @@ class User extends RowModel
function isDeleted(): bool
{
- if ($this->getRecord()->deleted == 1)
+ if($this->getRecord()->deleted == 1)
+ return TRUE;
+ else
+ return FALSE;
+ }
+
+ function isDeactivated(): bool
+ {
+ if($this->getDeactivationDate()->timestamp() > time())
return TRUE;
else
return FALSE;
@@ -949,6 +1018,22 @@ class User extends RowModel
{
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;
}
diff --git a/Web/Models/Repositories/Applications.php b/Web/Models/Repositories/Applications.php
new file mode 100644
index 00000000..3aa6e5be
--- /dev/null
+++ b/Web/Models/Repositories/Applications.php
@@ -0,0 +1,69 @@
+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()));
+ }
+}
\ No newline at end of file
diff --git a/Web/Models/Repositories/BannedLinks.php b/Web/Models/Repositories/BannedLinks.php
new file mode 100644
index 00000000..8f93e6fd
--- /dev/null
+++ b/Web/Models/Repositories/BannedLinks.php
@@ -0,0 +1,73 @@
+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));
+ }
+}
\ No newline at end of file
diff --git a/Web/Models/Repositories/Comments.php b/Web/Models/Repositories/Comments.php
index 6c922511..4774cf35 100644
--- a/Web/Models/Repositories/Comments.php
+++ b/Web/Models/Repositories/Comments.php
@@ -26,13 +26,13 @@ class Comments
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([
"model" => get_class($target),
"target" => $target->getId(),
"deleted" => false,
- ])->page($page, $perPage ?? OPENVK_DEFAULT_PER_PAGE);
+ ])->page($page, $perPage ?? OPENVK_DEFAULT_PER_PAGE)->order("created ".$sort);;
foreach($comments as $comment)
yield $this->toComment($comment);
diff --git a/Web/Models/Repositories/Messages.php b/Web/Models/Repositories/Messages.php
index ba95d6d0..4c870806 100644
--- a/Web/Models/Repositories/Messages.php
+++ b/Web/Models/Repositories/Messages.php
@@ -44,4 +44,15 @@ class Messages
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;
+ }
}
diff --git a/Web/Models/Repositories/Posts.php b/Web/Models/Repositories/Posts.php
index 6dde27c8..7aadc0bb 100644
--- a/Web/Models/Repositories/Posts.php
+++ b/Web/Models/Repositories/Posts.php
@@ -71,7 +71,7 @@ class Posts
{
$hashtag = "#$hashtag";
$sel = $this->posts
- ->where("content LIKE ?", "%$hashtag%")
+ ->where("MATCH (content) AGAINST (? IN BOOLEAN MODE)", "+$hashtag")
->where("deleted", 0)
->order("created DESC")
->page($page, $perPage ?? OPENVK_DEFAULT_PER_PAGE);
diff --git a/Web/Models/sql/get-correspondencies-count.tsql b/Web/Models/sql/get-correspondencies-count.tsql
new file mode 100644
index 00000000..b24390b9
--- /dev/null
+++ b/Web/Models/sql/get-correspondencies-count.tsql
@@ -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
\ No newline at end of file
diff --git a/Web/Models/sql/get-online-friends.tsql b/Web/Models/sql/get-online-friends.tsql
new file mode 100755
index 00000000..ad646554
--- /dev/null
+++ b/Web/Models/sql/get-online-friends.tsql
@@ -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)
\ No newline at end of file
diff --git a/Web/Presenters/AboutPresenter.php b/Web/Presenters/AboutPresenter.php
index 3caa007d..6a281d07 100644
--- a/Web/Presenters/AboutPresenter.php
+++ b/Web/Presenters/AboutPresenter.php
@@ -9,24 +9,19 @@ final class AboutPresenter extends OpenVKPresenter
{
protected $banTolerant = true;
protected $activationTolerant = true;
+ protected $deactivationTolerant = true;
function renderIndex(): void
{
if(!is_null($this->user)) {
- header("HTTP/1.1 302 Found");
-
if($this->user->identity->getMainPage())
- header("Location: /feed");
+ $this->redirect("/feed");
else
- header("Location: /id" . $this->user->id);
-
- exit;
+ $this->redirect($this->user->identity->getURL());
}
if($_SERVER['REQUEST_URI'] == "/id0") {
- header("HTTP/1.1 302 Found");
- header("Location: /");
- exit;
+ $this->redirect("/");
}
$this->template->stats = (new Users)->getStatistics();
@@ -107,6 +102,15 @@ final class AboutPresenter extends OpenVKPresenter
. "# covered from unauthorized persons (for example, due to\n"
. "# lack of rights to access the admin panel)\n\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: /language\n"
. "Disallow: /badbrowser.php\n"
@@ -126,16 +130,11 @@ final class AboutPresenter extends OpenVKPresenter
function renderHumansTxt(): void
{
# :D
-
- header("HTTP/1.1 302 Found");
- header("Location: https://github.com/openvk/openvk#readme");
- exit;
+ $this->redirect("https://github.com/openvk/openvk#readme");
}
function renderDev(): void
{
- header("HTTP/1.1 302 Found");
- header("Location: https://docs.openvk.su/");
- exit;
+ $this->redirect("https://docs.openvk.su/");
}
}
diff --git a/Web/Presenters/AdminPresenter.php b/Web/Presenters/AdminPresenter.php
index f35e1081..ceda6f6b 100644
--- a/Web/Presenters/AdminPresenter.php
+++ b/Web/Presenters/AdminPresenter.php
@@ -1,7 +1,8 @@
users = $users;
$this->clubs = $clubs;
$this->vouchers = $vouchers;
$this->gifts = $gifts;
+ $this->bannedLinks = $bannedLinks;
parent::__construct();
}
@@ -170,8 +173,7 @@ final class AdminPresenter extends OpenVKPresenter
$voucher->save();
- $this->redirect("/admin/vouchers/id" . $voucher->getId(), static::REDIRECT_TEMPORARY);
- exit;
+ $this->redirect("/admin/vouchers/id" . $voucher->getId());
}
function renderGiftCategories(): void
@@ -193,7 +195,7 @@ final class AdminPresenter extends OpenVKPresenter
if(!$cat)
$this->notFound();
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 {
$gen = true;
$cat = new GiftCategory;
@@ -234,7 +236,7 @@ final class AdminPresenter extends OpenVKPresenter
$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
@@ -245,7 +247,7 @@ final class AdminPresenter extends OpenVKPresenter
if(!$cat)
$this->notFound();
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->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();
$this->flash("succ", "Gift moved successfully", "This gift will now be in $name.");
- $this->redirect("/admin/gifts/" . $catTo->getSlug() . "." . $catTo->getId() . "/", static::REDIRECT_TEMPORARY);
+ $this->redirect("/admin/gifts/" . $catTo->getSlug() . "." . $catTo->getId() . "/");
break;
default:
case "edit":
@@ -328,7 +330,7 @@ final class AdminPresenter extends OpenVKPresenter
$cat->addGift($gift);
}
- $this->redirect("/admin/gifts/id" . $gift->getId(), static::REDIRECT_TEMPORARY);
+ $this->redirect("/admin/gifts/id" . $gift->getId());
}
}
@@ -340,12 +342,14 @@ final class AdminPresenter extends OpenVKPresenter
function renderQuickBan(int $id): void
{
$this->assertNoCSRF();
-
+
+ $unban_time = strtotime($this->queryParam("date")) ?: NULL;
+
$user = $this->users->get($id);
if(!$user)
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") ]));
}
@@ -357,7 +361,8 @@ final class AdminPresenter extends OpenVKPresenter
if(!$user)
exit(json_encode([ "error" => "User does not exist" ]));
- $user->setBlock_Reason(null);
+ $user->setBlock_Reason(NULL);
+ $user->setUnblock_time(NULL);
$user->save();
exit(json_encode([ "success" => true ]));
}
@@ -373,4 +378,73 @@ final class AdminPresenter extends OpenVKPresenter
$user->adminNotify("⚠️ " . $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");
+ }
}
diff --git a/Web/Presenters/AppsPresenter.php b/Web/Presenters/AppsPresenter.php
new file mode 100644
index 00000000..02fb8922
--- /dev/null
+++ b/Web/Presenters/AppsPresenter.php
@@ -0,0 +1,138 @@
+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;
+ }
+}
\ No newline at end of file
diff --git a/Web/Presenters/AuthPresenter.php b/Web/Presenters/AuthPresenter.php
index 8d15d3e2..f934f7fe 100644
--- a/Web/Presenters/AuthPresenter.php
+++ b/Web/Presenters/AuthPresenter.php
@@ -1,14 +1,8 @@
user))
- $this->redirect("/id" . $this->user->id, static::REDIRECT_TEMPORARY);
+ $this->redirect($this->user->identity->getURL());
if(!$this->hasPermission("user", "register", -1)) exit("Вас забанили");
@@ -97,7 +92,7 @@ final class AuthPresenter extends OpenVKPresenter
$user->setEmail($this->postParam("email"));
$user->setSince(date("Y-m-d H:i:s"));
$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']);
} catch(InvalidUserNameException $ex) {
$this->flashFail("err", tr("error"), tr("invalid_real_name"));
@@ -128,7 +123,7 @@ final class AuthPresenter extends OpenVKPresenter
}
$this->authenticator->authenticate($chUser->getId());
- $this->redirect("/id" . $user->getId(), static::REDIRECT_TEMPORARY);
+ $this->redirect("/id" . $user->getId());
}
}
@@ -137,12 +132,11 @@ final class AuthPresenter extends OpenVKPresenter
$redirUrl = $this->requestParam("jReturnTo");
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($_SERVER["REQUEST_METHOD"] === "POST") {
-
$user = $this->db->table("ChandlerUsers")->where("login", $this->postParam("login"))->fetch();
if(!$user)
$this->flashFail("err", tr("login_failed"), tr("invalid_username_or_password"));
@@ -151,7 +145,7 @@ final class AuthPresenter extends OpenVKPresenter
$this->flashFail("err", tr("login_failed"), tr("invalid_username_or_password"));
$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"));
$secret = $user->related("profiles.user")->fetch()["2fa_secret"];
@@ -171,8 +165,7 @@ final class AuthPresenter extends OpenVKPresenter
}
$this->authenticator->authenticate($user->id);
- $this->redirect($redirUrl ?? "/id" . $user->related("profiles.user")->fetch()->id, static::REDIRECT_TEMPORARY);
- exit;
+ $this->redirect($redirUrl ?? $ovkUser->getURL());
}
}
@@ -183,7 +176,7 @@ final class AuthPresenter extends OpenVKPresenter
if($uuid === "unset") {
Session::i()->set("_su", NULL);
- $this->redirect("/", static::REDIRECT_TEMPORARY);
+ $this->redirect("/");
}
if(!$this->db->table("ChandlerUsers")->where("id", $uuid))
@@ -192,8 +185,7 @@ final class AuthPresenter extends OpenVKPresenter
$this->assertPermission('openvk\Web\Models\Entities\User', 'substitute', 0);
Session::i()->set("_su", $uuid);
$this->flash("succ", tr("profile_changed"), tr("profile_changed_comment"));
- $this->redirect("/", static::REDIRECT_TEMPORARY);
- exit;
+ $this->redirect("/");
}
function renderLogout(): void
@@ -203,7 +195,7 @@ final class AuthPresenter extends OpenVKPresenter
$this->authenticator->logout();
Session::i()->set("_su", NULL);
- $this->redirect("/", static::REDIRECT_TEMPORARY_PRESISTENT);
+ $this->redirect("/");
}
function renderFinishRestoringPassword(): void
@@ -243,7 +235,7 @@ final class AuthPresenter extends OpenVKPresenter
function renderRestore(): void
{
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")
$this->pass("openvk!Auth->finishRestoringPassword");
@@ -273,7 +265,6 @@ final class AuthPresenter extends OpenVKPresenter
];
$this->sendmail($uRow->login, "password-reset", $params); #Vulnerability possible
-
$this->flashFail("succ", tr("information_-1"), tr("password_reset_email_sent"));
}
}
@@ -281,7 +272,7 @@ final class AuthPresenter extends OpenVKPresenter
function renderResendEmail(): void
{
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") {
$user = $this->user->identity;
@@ -321,4 +312,49 @@ final class AuthPresenter extends OpenVKPresenter
$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"));
+ }
}
diff --git a/Web/Presenters/AwayPresenter.php b/Web/Presenters/AwayPresenter.php
index a65ba7af..18c7cca7 100644
--- a/Web/Presenters/AwayPresenter.php
+++ b/Web/Presenters/AwayPresenter.php
@@ -1,13 +1,29 @@
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("X-Robots-Tag: noindex, nofollow, noarchive");
header("Location: " . $this->queryParam("to"));
exit;
}
+
+ function renderView(int $lid) {
+ $this->template->link = (new BannedLinks)->get($lid);
+
+ if (!$this->template->link)
+ $this->notFound();
+
+ $this->template->to = $this->queryParam("to");
+ }
}
diff --git a/Web/Presenters/BannedLinkPresenter.php b/Web/Presenters/BannedLinkPresenter.php
new file mode 100644
index 00000000..6a11b3fc
--- /dev/null
+++ b/Web/Presenters/BannedLinkPresenter.php
@@ -0,0 +1,13 @@
+template->link = (new BannedLinks)->get($lid);
+ $this->template->to = $this->queryParam("to");
+ }
+}
diff --git a/Web/Presenters/BlobPresenter.php b/Web/Presenters/BlobPresenter.php
index 21bba2da..970b8f19 100644
--- a/Web/Presenters/BlobPresenter.php
+++ b/Web/Presenters/BlobPresenter.php
@@ -25,15 +25,15 @@ final class BlobPresenter extends OpenVKPresenter
$this->notFound();
if(isset($_SERVER["HTTP_IF_NONE_MATCH"]))
- exit(header("HTTP/1.1 304 Not Modified"));
-
- header("Content-Type: " . mime_content_type($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) . "\"");
-
- readfile($path);
- exit;
+ exit(header("HTTP/1.1 304 Not Modified"));
+
+ header("Content-Type: " . mime_content_type($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) . "\"");
+
+ readfile($path);
+ exit;
}
}
diff --git a/Web/Presenters/CommentPresenter.php b/Web/Presenters/CommentPresenter.php
index 81783a2f..cbdac84e 100644
--- a/Web/Presenters/CommentPresenter.php
+++ b/Web/Presenters/CommentPresenter.php
@@ -24,7 +24,7 @@ final class CommentPresenter extends OpenVKPresenter
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
diff --git a/Web/Presenters/GiftsPresenter.php b/Web/Presenters/GiftsPresenter.php
index c4c7e9d8..b99e5ba9 100644
--- a/Web/Presenters/GiftsPresenter.php
+++ b/Web/Presenters/GiftsPresenter.php
@@ -91,7 +91,7 @@ final class GiftsPresenter extends OpenVKPresenter
$gift->used();
$this->flash("succ", "Подарок отправлен", "Вы отправили подарок " . $user->getFirstName() . " за " . $gift->getPrice() . " голосов.");
- $this->redirect($user->getURL(), static::REDIRECT_TEMPORARY);
+ $this->redirect($user->getURL());
}
function renderStub(): void
diff --git a/Web/Presenters/GroupPresenter.php b/Web/Presenters/GroupPresenter.php
index c239ff22..a83386db 100644
--- a/Web/Presenters/GroupPresenter.php
+++ b/Web/Presenters/GroupPresenter.php
@@ -22,15 +22,12 @@ final class GroupPresenter extends OpenVKPresenter
if(!$club) {
$this->notFound();
} 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->albumsCount = (new Albums)->getClubAlbumsCount($club);
$this->template->topics = (new Topics)->getLastTopics($club, 3);
$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);
- header("HTTP/1.1 302 Found");
- header("Location: /club" . $club->getId());
+ $this->redirect("/club" . $club->getId());
}else{
$this->flashFail("err", "Ошибка", "Вы не ввели название группы.");
}
@@ -77,9 +73,7 @@ final class GroupPresenter extends OpenVKPresenter
$club->toggleSubscription($this->user->identity);
- header("HTTP/1.1 302 Found");
- header("Location: /club" . $club->getId());
- exit;
+ $this->redirect($club->getURL());
}
function renderFollowers(int $id): void
@@ -202,10 +196,12 @@ final class GroupPresenter extends OpenVKPresenter
$this->template->club = $club;
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->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->setEveryone_Can_Create_Topics(empty($this->postParam("everyone_can_create_topics")) ? 0 : 1);
$club->setDisplay_Topics_Above_Wall(empty($this->postParam("display_topics_above_wall")) ? 0 : 1);
diff --git a/Web/Presenters/InternalAPIPresenter.php b/Web/Presenters/InternalAPIPresenter.php
index 60c0b550..1a107659 100644
--- a/Web/Presenters/InternalAPIPresenter.php
+++ b/Web/Presenters/InternalAPIPresenter.php
@@ -29,9 +29,10 @@ final class InternalAPIPresenter extends OpenVKPresenter
function renderRoute(): void
{
- if($_SERVER["REQUEST_METHOD"] !== "POST")
+ if($_SERVER["REQUEST_METHOD"] !== "POST") {
+ header("HTTP/1.1 405 Method Not Allowed");
exit("ты дебил это точка апи");
-
+ }
try {
$input = (object) MessagePack::unpack(file_get_contents("php://input"));
} catch (\Exception $ex) {
@@ -71,9 +72,10 @@ final class InternalAPIPresenter extends OpenVKPresenter
}
function renderTimezone() {
- if($_SERVER["REQUEST_METHOD"] !== "POST")
+ if($_SERVER["REQUEST_METHOD"] !== "POST") {
+ header("HTTP/1.1 405 Method Not Allowed");
exit("ты дебил это метод апи");
-
+ }
$sessionOffset = Session::i()->get("_timezoneOffset");
if(is_numeric($this->postParam("timezone", false))) {
$postTZ = intval($this->postParam("timezone", false));
diff --git a/Web/Presenters/MessengerPresenter.php b/Web/Presenters/MessengerPresenter.php
index 968c1936..cea440ba 100644
--- a/Web/Presenters/MessengerPresenter.php
+++ b/Web/Presenters/MessengerPresenter.php
@@ -34,10 +34,18 @@ final class MessengerPresenter extends OpenVKPresenter
if(isset($_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));
-
+
+ // #КакаоПрокакалось
+
$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
diff --git a/Web/Presenters/NotesPresenter.php b/Web/Presenters/NotesPresenter.php
index d88c6365..363d814c 100644
--- a/Web/Presenters/NotesPresenter.php
+++ b/Web/Presenters/NotesPresenter.php
@@ -1,7 +1,6 @@
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
{
$this->assertUserLoggedIn();
diff --git a/Web/Presenters/NotificationPresenter.php b/Web/Presenters/NotificationPresenter.php
index dac075f7..d12f27f0 100644
--- a/Web/Presenters/NotificationPresenter.php
+++ b/Web/Presenters/NotificationPresenter.php
@@ -6,12 +6,21 @@ final class NotificationPresenter extends OpenVKPresenter
function renderFeed(): void
{
$this->assertUserLoggedIn();
-
+
$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->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->save();
diff --git a/Web/Presenters/OpenVKPresenter.php b/Web/Presenters/OpenVKPresenter.php
index d9202a7d..a90181c6 100755
--- a/Web/Presenters/OpenVKPresenter.php
+++ b/Web/Presenters/OpenVKPresenter.php
@@ -14,6 +14,7 @@ abstract class OpenVKPresenter extends SimplePresenter
{
protected $banTolerant = false;
protected $activationTolerant = false;
+ protected $deactivationTolerant = false;
protected $errorTemplate = "@error";
protected $user = NULL;
@@ -60,9 +61,7 @@ abstract class OpenVKPresenter extends SimplePresenter
$this->flash($type, $title, $message, $code);
$referer = $_SERVER["HTTP_REFERER"] ?? "/";
- header("HTTP/1.1 302 Found");
- header("Location: $referer");
- exit;
+ $this->redirect($referer);
}
}
@@ -98,9 +97,8 @@ abstract class OpenVKPresenter extends SimplePresenter
}
$this->flash("err", tr("login_required_error"), tr("login_required_error_comment"));
- header("HTTP/1.1 302 Found");
- header("Location: $loginUrl");
- exit;
+
+ $this->redirect($loginUrl);
}
}
@@ -110,9 +108,7 @@ abstract class OpenVKPresenter extends SimplePresenter
if($model !== "user") {
$this->flash("info", tr("login_required_error"), tr("login_required_error_comment"));
- header("HTTP/1.1 302 Found");
- header("Location: /login");
- exit;
+ $this->redirect("/login");
}
return ($action === "register" || $action === "login");
@@ -214,39 +210,28 @@ abstract class OpenVKPresenter extends SimplePresenter
$this->template->thisUser = $this->user->identity;
$this->template->userTainted = $user->isTainted();
- if($this->user->identity->isDeleted()) {
- /*
- ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣴⠶⠶⣶⠶⠶⠶⠶⠶⠶⠶⠶⠶⢶⠶⠶⠶⠤⠤⠤⠤⣄⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
- ⠀⠀⠀⠀⠀⠀⠀⠀⣠⡾⠋⠀⠀⠊⠀⠀⠀⠀⠀⠀⠀⠀⠒⠒⠒⠀⠀⠀⠀⠤⢤⣤⣄⠉⠉⠛⠛⠷⣦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
- ⠀⠀⠀⠀⠀⠀⠀⣰⠟⠀⠀⠀⠀⠀⠐⠋⢑⣤⣶⣶⣤⡢⡀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣄⡂⠀⠀⠶⢄⠙⢷⣤⠀⠀⠀⠀⠀⠀⠀⠀
- ⠀⠀⠀⠀⠀⠀⣸⡿⠚⠉⡀⠀⠀⠀⠀⢰⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⢢⠀⠀⡀⣰⣿⣿⣿⣿⣦⡀⠀⠀⠡⡀⢹⡆⠀⠀⠀⠀⠀⠀⠀
- ⠀⠀⠀⠀⢀⣴⠏⠀⣀⣀⣀⡤⢤⣄⣠⣿⣿⣿⣿⣻⣿⣿⣷⠀⢋⣾⠈⠙⣶⠒⢿⣿⣿⣿⣿⡿⠟⠃⠀⡀⠡⠼⣧⡀⠀⠀⠀⠀⠀⠀
- ⠀⠀⢀⣴⣿⢃⡴⢊⢽⣶⣤⣀⠀⠊⠉⠉⡛⢿⣿⣿⣿⠿⠋⢀⡀⠁⠀⠀⢸⣁⣀⣉⣉⣉⡉⠀⠩⡡⠀⣩⣦⠀⠈⠻⣦⡀⠀⠀⠀⠀
- ⠀⢠⡟⢡⠇⡞⢀⠆⠀⢻⣿⣿⣷⣄⠀⢀⠈⠂⠈⢁⡤⠚⡟⠉⠀⣀⣀⠀⠈⠳⣍⠓⢆⢀⡠⢀⣨⣴⣿⣿⡏⢀⡆⠀⢸⡇⠀⠀⠀⠀
- ⠀⣾⠁⢸⠀⠀⢸⠀⠀⠀⠹⣿⣿⣿⣿⣶⣬⣦⣤⡈⠀⠀⠇⠀⠛⠉⣩⣤⣤⣤⣿⣤⣤⣴⣾⣿⣿⣿⣿⣿⣧⠞⠀⠀⢸⡇⠀⠀⠀⠀
- ⠀⢹⣆⠸⠀⠀⢸⠀⠀⠀⠀⠘⢿⣿⣿⣿⣿⣿⣿⣟⣛⠛⠛⣛⡛⠛⠛⣛⣋⡉⠉⣡⠶⢾⣿⣿⣿⣿⣿⣿⡇⠀⠀⢀⣾⠃⠀⠀⠀⠀
- ⠀⠀⠻⣆⡀⠀⠈⢂⠀⠀⠀⠠⡈⢻⣿⣿⣿⣿⡟⠁⠈⢧⡼⠉⠙⣆⡞⠁⠈⢹⣴⠃⠀⢸⣿⣿⣿⣿⣿⣿⠃⠀⡆⣾⠃⠀⠀⠀⠀⠀
- ⠀⠀⠀⠈⢻⣇⠀⠀⠀⠀⠀⠀⢡⠀⠹⣿⣿⣿⣷⡀⠀⣸⡇⠀⠀⣿⠁⠀⠀⠘⣿⠀⠀⠘⣿⣿⣿⣿⣿⣿⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀
- ⠀⠀⠀⠀⠀⠹⣇⠀⠠⠀⠀⠀⠀⠡⠐⢬⡻⣿⣿⣿⣿⣿⣷⣶⣶⣿⣦⣤⣤⣤⣿⣦⣶⣿⣿⣿⣿⣿⣿⣿⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀
- ⠀⠀⠀⠀⠀⠀⠹⣧⡀⠡⡀⠀⠀⠀⠑⠄⠙⢎⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⠀⢿⡇⠀⠀⠀⠀⠀⠀
- ⠀⠀⠀⠀⠀⠀⠀⠈⠳⣤⡐⡄⠀⠀⠀⠈⠂⠀⠱⣌⠻⣿⣿⣿⣿⣿⣿⣿⠿⣿⠟⢻⡏⢻⣿⣿⣿⣿⣿⣿⣿⠀⢸⡇⠀⠀⠀⠀⠀⠀
- ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⢮⣦⡀⠂⠀⢀⠀⠀⠈⠳⣈⠻⣿⣿⣿⡇⠘⡄⢸⠀⠀⣇⠀⣻⣿⣿⣿⣿⣿⡏⠀⠸⡇⠀⠀⠀⠀⠀⠀
- ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⢶⣤⣄⡑⠄⠀⠀⠈⠑⠢⠙⠻⢷⣶⣵⣞⣑⣒⣋⣉⣁⣻⣿⠿⠟⠱⠃⡸⠀⣧⠀⠀⠀⠀⠀⠀
- ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠻⣷⣄⡀⠐⠢⣄⣀⡀⠀⠉⠉⠉⠉⠛⠙⠭⠭⠄⠒⠈⠀⠐⠁⢀⣿⠀⠀⠀⠀⠀⠀
- ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠷⢦⣤⣤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣒⡠⠄⣠⡾⠃⠀⠀⠀⠀⠀⠀
- ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠙⠛⠷⠶⣦⣤⣭⣤⣬⣭⣭⣴⠶⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀
- */
- Authenticator::i()->logout();
- Session::i()->set("_su", NULL);
- $this->flashFail("err", tr("error"), tr("profile_not_found"));
- $this->redirect("/", static::REDIRECT_TEMPORARY);
+ 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();
+ Session::i()->set("_su", NULL);
+ $this->flashFail("err", tr("error"), tr("profile_not_found"));
+ $this->redirect("/");
+ }
+ exit;
}
if($this->user->identity->isBanned() && !$this->banTolerant) {
header("HTTP/1.1 403 Forbidden");
$this->getTemplatingEngine()->render(__DIR__ . "/templates/@banned.xml", [
- "thisUser" => $this->user->identity,
- "csrfToken" => $GLOBALS["csrfToken"],
+ "thisUser" => $this->user->identity,
+ "csrfToken" => $GLOBALS["csrfToken"],
"isTimezoned" => Session::i()->get("_timezoneOffset"),
]);
exit;
@@ -256,8 +241,8 @@ abstract class OpenVKPresenter extends SimplePresenter
if(!$this->user->identity->isActivated() && !$this->activationTolerant) {
header("HTTP/1.1 403 Forbidden");
$this->getTemplatingEngine()->render(__DIR__ . "/templates/@email.xml", [
- "thisUser" => $this->user->identity,
- "csrfToken" => $GLOBALS["csrfToken"],
+ "thisUser" => $this->user->identity,
+ "csrfToken" => $GLOBALS["csrfToken"],
"isTimezoned" => Session::i()->get("_timezoneOffset"),
]);
exit;
@@ -265,7 +250,7 @@ abstract class OpenVKPresenter extends SimplePresenter
$userValidated = 1;
$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->save();
}
diff --git a/Web/Presenters/PhotosPresenter.php b/Web/Presenters/PhotosPresenter.php
index aed5fbfd..eacf76d4 100644
--- a/Web/Presenters/PhotosPresenter.php
+++ b/Web/Presenters/PhotosPresenter.php
@@ -1,12 +1,7 @@
save();
if(isset($club))
- $this->redirect("/album-" . $album->getOwner()->getId() . "_" . $album->getId(), static::REDIRECT_TEMPORARY);
+ $this->redirect("/album-" . $album->getOwner()->getId() . "_" . $album->getId());
else
- $this->redirect("/album" . $album->getOwner()->getId() . "_" . $album->getId(), static::REDIRECT_TEMPORARY);
+ $this->redirect("/album" . $album->getOwner()->getId() . "_" . $album->getId());
}
}
@@ -129,6 +124,7 @@ final class PhotosPresenter extends OpenVKPresenter
$name = $album->getName();
$owner = $album->getOwner();
$album->delete();
+
$this->flash("succ", "Альбом удалён", "Альбом $name был успешно удалён.");
$this->redirect("/albums" . ($owner instanceof Club ? "-" : "") . $owner->getId());
}
@@ -203,7 +199,7 @@ final class PhotosPresenter extends OpenVKPresenter
$photo->save();
$this->flash("succ", "Изменения сохранены", "Обновлённое описание появится на странице с фоткой.");
- $this->redirect("/photo" . $photo->getPrettyId(), static::REDIRECT_TEMPORARY);
+ $this->redirect("/photo" . $photo->getPrettyId());
}
$this->template->photo = $photo;
@@ -241,7 +237,10 @@ final class PhotosPresenter extends OpenVKPresenter
}
$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 {
$this->template->album = $album;
}
@@ -262,9 +261,11 @@ final class PhotosPresenter extends OpenVKPresenter
if($_SERVER["REQUEST_METHOD"] === "POST") {
$this->assertNoCSRF();
$album->removePhoto($photo);
+ $album->setEdited(time());
+ $album->save();
$this->flash("succ", "Фотография удалена", "Эта фотография была успешно удалена.");
- $this->redirect("/album" . $album->getPrettyId(), static::REDIRECT_TEMPORARY);
+ $this->redirect("/album" . $album->getPrettyId());
}
}
@@ -283,6 +284,6 @@ final class PhotosPresenter extends OpenVKPresenter
$photo->delete();
$this->flash("succ", "Фотография удалена", "Эта фотография была успешно удалена.");
- $this->redirect("/id0", static::REDIRECT_TEMPORARY);
+ $this->redirect("/id0");
}
}
diff --git a/Web/Presenters/SearchPresenter.php b/Web/Presenters/SearchPresenter.php
index a5eaedc7..2171297c 100644
--- a/Web/Presenters/SearchPresenter.php
+++ b/Web/Presenters/SearchPresenter.php
@@ -1,9 +1,7 @@
getId());
+ $this->redirect("/support/view/" . $ticket->getId());
} else {
$this->flashFail("err", tr("error"), tr("you_have_not_entered_name_or_text"));
}
@@ -190,8 +189,7 @@ final class SupportPresenter extends OpenVKPresenter
$comment->setCreated(time());
$comment->save();
- header("HTTP/1.1 302 Found");
- header("Location: /support/view/" . $id);
+ $this->redirect("/support/view/" . $id);
} else {
$this->flashFail("err", tr("error"), tr("you_have_not_entered_text"));
}
@@ -322,6 +320,10 @@ final class SupportPresenter extends OpenVKPresenter
$user->setBlock_In_Support_Reason($this->queryParam("reason"));
$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") ]);
}
diff --git a/Web/Presenters/TopicsPresenter.php b/Web/Presenters/TopicsPresenter.php
index 16dd1795..6dd1ec6c 100644
--- a/Web/Presenters/TopicsPresenter.php
+++ b/Web/Presenters/TopicsPresenter.php
@@ -108,7 +108,7 @@ final class TopicsPresenter extends OpenVKPresenter
}
} catch(ISE $ex) {
$this->flash("err", "Не удалось опубликовать комментарий", "Файл медиаконтента повреждён или слишком велик.");
- $this->redirect("/topic" . $topic->getPrettyId(), static::REDIRECT_TEMPORARY);
+ $this->redirect("/topic" . $topic->getPrettyId());
}
if(!empty($this->postParam("text")) || $photo || $video) {
@@ -123,7 +123,7 @@ final class TopicsPresenter extends OpenVKPresenter
$comment->save();
} catch (\LengthException $ex) {
$this->flash("err", "Не удалось опубликовать комментарий", "Комментарий слишком большой.");
- $this->redirect("/topic" . $topic->getPrettyId(), static::REDIRECT_TEMPORARY);
+ $this->redirect("/topic" . $topic->getPrettyId());
}
if(!is_null($photo))
@@ -133,7 +133,7 @@ final class TopicsPresenter extends OpenVKPresenter
$comment->attach($video);
}
- $this->redirect("/topic" . $topic->getPrettyId(), static::REDIRECT_TEMPORARY);
+ $this->redirect("/topic" . $topic->getPrettyId());
}
$this->template->club = $club;
@@ -167,7 +167,7 @@ final class TopicsPresenter extends OpenVKPresenter
$topic->save();
$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;
@@ -189,6 +189,6 @@ final class TopicsPresenter extends OpenVKPresenter
$this->willExecuteWriteAction();
$topic->deleteTopic();
- $this->redirect("/board" . $topic->getClub()->getId(), static::REDIRECT_TEMPORARY);
+ $this->redirect("/board" . $topic->getClub()->getId());
}
}
diff --git a/Web/Presenters/UnknownTextRouteStrategyPresenter.php b/Web/Presenters/UnknownTextRouteStrategyPresenter.php
index 6032a4a0..004da043 100644
--- a/Web/Presenters/UnknownTextRouteStrategyPresenter.php
+++ b/Web/Presenters/UnknownTextRouteStrategyPresenter.php
@@ -1,7 +1,6 @@
users = $users;
@@ -33,13 +27,15 @@ final class UserPresenter extends OpenVKPresenter
function renderView(int $id): void
{
$user = $this->users->get($id);
- if(!$user || $user->isDeleted())
- $this->template->_template = "User/deleted.xml";
- else {
- if($user->getShortCode())
- if(parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH) !== "/" . $user->getShortCode())
- $this->redirect("/" . $user->getShortCode(), static::REDIRECT_TEMPORARY_PRESISTENT);
-
+ if(!$user || $user->isDeleted()) {
+ if($user->isDeactivated()) {
+ $this->template->_template = "User/deactivated.xml";
+
+ $this->template->user = $user;
+ } else {
+ $this->template->_template = "User/deleted.xml";
+ }
+ } else {
$this->template->albums = (new Albums)->getUserAlbums($user);
$this->template->albumsCount = (new Albums)->getUserAlbumsCount($user);
$this->template->videos = (new Videos)->getByUser($user, 1, 2);
@@ -75,7 +71,7 @@ final class UserPresenter extends OpenVKPresenter
$name = $user->getFullName();
$this->flash("err", "Ошибка доступа", "Вы не можете просматривать полный список подписок $name.");
- $this->redirect("/id$id", static::REDIRECT_TEMPORARY_PRESISTENT);
+ $this->redirect($user->getURL());
}
}
}
@@ -90,6 +86,9 @@ final class UserPresenter extends OpenVKPresenter
elseif (!$user->getPrivacyPermission('groups.read', $this->user->identity ?? NULL))
$this->flashFail("err", tr("forbidden"), tr("forbidden_comment"));
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->page = (int) ($this->queryParam("p") ?? 1);
$this->template->admin = $this->queryParam("act") == "managed";
@@ -154,7 +153,10 @@ final class UserPresenter extends OpenVKPresenter
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)
$user->setMarital_Status($this->postParam("marialstatus"));
@@ -270,9 +272,7 @@ final class UserPresenter extends OpenVKPresenter
$user->toggleSubscription($this->user->identity);
- header("HTTP/1.1 302 Found");
- header("Location: /id" . $user->getId());
- exit;
+ $this->redirect($user->getURL());
}
function renderSetAvatar(): void
@@ -291,7 +291,11 @@ final class UserPresenter extends OpenVKPresenter
$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"));
}
@@ -449,13 +453,51 @@ final class UserPresenter extends OpenVKPresenter
$this->flash("succ", tr("changes_saved"), tr("changes_saved_comment"));
}
$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")
: "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->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
{
$this->assertUserLoggedIn();
@@ -536,7 +578,7 @@ final class UserPresenter extends OpenVKPresenter
$this->user->identity->save();
}
- $this->redirect("/", static::REDIRECT_TEMPORARY_PRESISTENT);
+ $this->redirect("/");
}
function renderCoinsTransfer(): void
diff --git a/Web/Presenters/VKAPIPresenter.php b/Web/Presenters/VKAPIPresenter.php
index 5e1959e5..a26a25b9 100644
--- a/Web/Presenters/VKAPIPresenter.php
+++ b/Web/Presenters/VKAPIPresenter.php
@@ -42,6 +42,24 @@ final class VKAPIPresenter extends OpenVKPresenter
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
{
@@ -249,8 +267,12 @@ final class VKAPIPresenter extends OpenVKPresenter
$user = (new Users)->get($uId);
$code = $this->requestParam("code");
- if($user->is2faEnabled() && !($code === (new Totp)->GenerateToken(Base32::decode($user->get2faSecret())) || $user->use2faBackupCode((int) $code)))
- $this->fail(28, "Invalid 2FA code", "internal", "acquireToken");
+ 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");
+ }
$token = new APIToken;
$token->setUser($user);
diff --git a/Web/Presenters/VideosPresenter.php b/Web/Presenters/VideosPresenter.php
index 0e20a91b..e7b24344 100644
--- a/Web/Presenters/VideosPresenter.php
+++ b/Web/Presenters/VideosPresenter.php
@@ -1,8 +1,7 @@
save();
- $this->redirect("/video" . $video->getPrettyId(), static::REDIRECT_TEMPORARY);
+ $this->redirect("/video" . $video->getPrettyId());
} else {
$this->flashFail("err", "Произошла ошибка", "Видео не может быть опубликовано без названия.");
}
@@ -104,7 +103,7 @@ final class VideosPresenter extends OpenVKPresenter
$video->save();
$this->flash("succ", "Изменения сохранены", "Обновлённое описание появится на странице с видосиком.");
- $this->redirect("/video" . $video->getPrettyId(), static::REDIRECT_TEMPORARY);
+ $this->redirect("/video" . $video->getPrettyId());
}
$this->template->video = $video;
@@ -128,7 +127,6 @@ final class VideosPresenter extends OpenVKPresenter
$this->flashFail("err", "Не удалось удалить пост", "Вы не вошли в аккаунт.");
}
- $this->redirect("/videos".$owner, static::REDIRECT_TEMPORARY);
- exit;
+ $this->redirect("/videos" . $owner);
}
}
diff --git a/Web/Presenters/WallPresenter.php b/Web/Presenters/WallPresenter.php
index 5bdac066..55c90518 100644
--- a/Web/Presenters/WallPresenter.php
+++ b/Web/Presenters/WallPresenter.php
@@ -113,14 +113,14 @@ final class WallPresenter extends OpenVKPresenter
$feed = new Feed();
$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) {
$item = new Item();
$item
->title($post->getOwner()->getCanonicalName())
->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())
->appendTo($channel);
}
@@ -294,11 +294,7 @@ final class WallPresenter extends OpenVKPresenter
if($wall > 0 && $wall !== $this->user->identity->getId())
(new WallPostNotification($wallOwner, $post, $this->user->identity))->emit();
- if($wall > 0)
- $this->redirect("/id$wall", 2); #Will exit
-
- $wall = $wall * -1;
- $this->redirect("/club$wall", 2);
+ $this->redirect($wallOwner->getURL());
}
function renderPost(int $wall, int $post_id): void
@@ -337,10 +333,7 @@ final class WallPresenter extends OpenVKPresenter
$post->toggleLike($this->user->identity);
}
- $this->redirect(
- "$_SERVER[HTTP_REFERER]#postGarter=" . $post->getId(),
- static::REDIRECT_TEMPORARY
- );
+ $this->redirect("$_SERVER[HTTP_REFERER]#postGarter=" . $post->getId());
}
function renderShare(int $wall, int $post_id): void
@@ -392,8 +385,7 @@ final class WallPresenter extends OpenVKPresenter
$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);
- exit;
+ $this->redirect($wall < 0 ? "/club" . ($wall*-1) : "/id" . $wall);
}
function renderPin(int $wall, int $post_id): void
diff --git a/Web/Presenters/templates/@MilkshakeListView.xml b/Web/Presenters/templates/@MilkshakeListView.xml
index 31e366fa..699da82b 100644
--- a/Web/Presenters/templates/@MilkshakeListView.xml
+++ b/Web/Presenters/templates/@MilkshakeListView.xml
@@ -52,9 +52,9 @@
{include actions}
diff --git a/Web/Presenters/templates/@banned.xml b/Web/Presenters/templates/@banned.xml
index f7583e82..48c29ddb 100644
--- a/Web/Presenters/templates/@banned.xml
+++ b/Web/Presenters/templates/@banned.xml
@@ -1,17 +1,27 @@
{extends "@layout.xml"}
-{block title}{_"banned_title"}{/block}
+{block title}{_banned_title}{/block}
{block header}
- {_"banned_header"}
+ {_banned_header}
{/block}
{block content}
-
+
{tr("banned_1", htmlentities($thisUser->getCanonicalName()))|noescape}
{tr("banned_2", htmlentities($thisUser->getBanReason()))|noescape}
+
+ {if !$thisUser->getUnbanTime()}
+ {_banned_perm}
+ {else}
+ {tr("banned_until_time", $thisUser->getUnbanTime())|noescape}
+ {/if}
+
+
+
+ {_banned_unban_myself}
diff --git a/Web/Presenters/templates/@deactivated.xml b/Web/Presenters/templates/@deactivated.xml
new file mode 100644
index 00000000..0be41141
--- /dev/null
+++ b/Web/Presenters/templates/@deactivated.xml
@@ -0,0 +1,34 @@
+{extends "@layout.xml"}
+{block title}{$thisUser->getCanonicalName()}{/block}
+
+{block header}
+ {$thisUser->getCanonicalName()}
+{/block}
+
+{block content}
+
+ {tr("profile_deactivated_msg", $thisUser->getDeactivationDate()->format("%e %B %G" . tr("time_at_sp") . "%R"))|noescape}
+
+
+
+
+
})
+
+
+
+
+
+
+
+
{$thisUser->getFullName()}
+
{_profile_deactivated_status}
+
+
+
+ {_profile_deactivated_info|noescape}
+
+
+
+{/block}
\ No newline at end of file
diff --git a/Web/Presenters/templates/@layout.xml b/Web/Presenters/templates/@layout.xml
index 72c61747..c4ac56e3 100644
--- a/Web/Presenters/templates/@layout.xml
+++ b/Web/Presenters/templates/@layout.xml
@@ -102,29 +102,35 @@
{if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME}{$instance_name}{/if}