From 71c59023cf8b951e456371cc89926c970ac96c8d Mon Sep 17 00:00:00 2001 From: lalka2018 <99399973+lalka2016@users.noreply.github.com> Date: Tue, 14 Nov 2023 22:44:39 +0300 Subject: [PATCH] Improve API (#975) * Add API for notifications * Add editing methods * Add apis for likes and polls * Add attaching polls * can_edit * Fix getting voters in anonymous posts and use c... ...anBeEditedBy instead of checking user's id --- VKAPI/Handlers/Groups.php | 6 +- VKAPI/Handlers/Likes.php | 49 ++++++- VKAPI/Handlers/Messages.php | 66 ++++++++- VKAPI/Handlers/Notes.php | 6 +- VKAPI/Handlers/Notifications.php | 83 +++++++++++ VKAPI/Handlers/Polls.php | 63 ++++++++ VKAPI/Handlers/Users.php | 25 +++- VKAPI/Handlers/VKAPIRequestHandler.php | 2 +- VKAPI/Handlers/Video.php | 4 +- VKAPI/Handlers/Wall.php | 109 +++++++++++++- Web/Models/Entities/Club.php | 2 +- Web/Models/Entities/Comment.php | 13 ++ Web/Models/Entities/Message.php | 6 +- Web/Models/Entities/Note.php | 2 +- .../Entities/Notifications/Notification.php | 134 ++++++++++++++++++ Web/Models/Entities/Photo.php | 16 +++ Web/Models/Entities/Post.php | 17 +++ Web/Models/Entities/Postable.php | 7 +- Web/Models/Entities/Video.php | 19 +++ bootstrap.php | 38 +++++ 20 files changed, 645 insertions(+), 22 deletions(-) create mode 100644 VKAPI/Handlers/Notifications.php diff --git a/VKAPI/Handlers/Groups.php b/VKAPI/Handlers/Groups.php index 85a251da..007b68ea 100644 --- a/VKAPI/Handlers/Groups.php +++ b/VKAPI/Handlers/Groups.php @@ -6,12 +6,12 @@ use openvk\Web\Models\Entities\Club; final class Groups extends VKAPIRequestHandler { - function get(int $user_id = 0, string $fields = "", int $offset = 0, int $count = 6, bool $online = false): object + function get(int $user_id = 0, string $fields = "", int $offset = 0, int $count = 6, bool $online = false, string $filter = "groups"): object { $this->requireUser(); if($user_id == 0) { - foreach($this->getUser()->getClubs($offset, false, $count, true) as $club) + foreach($this->getUser()->getClubs($offset, $filter == "admin", $count, true) as $club) $clbs[] = $club; $clbsCount = $this->getUser()->getClubCount(); } else { @@ -21,7 +21,7 @@ final class Groups extends VKAPIRequestHandler if(is_null($user)) $this->fail(15, "Access denied"); - foreach($user->getClubs($offset, false, $count, true) as $club) + foreach($user->getClubs($offset, $filter == "admin", $count, true) as $club) $clbs[] = $club; $clbsCount = $user->getClubCount(); diff --git a/VKAPI/Handlers/Likes.php b/VKAPI/Handlers/Likes.php index 9501b433..08c4e6e4 100644 --- a/VKAPI/Handlers/Likes.php +++ b/VKAPI/Handlers/Likes.php @@ -1,7 +1,7 @@ fail(100, "One of the parameters specified was missing or invalid: incorrect type"); } } + + function getList(string $type, int $owner_id, int $item_id, bool $extended = false, int $offset = 0, int $count = 10, bool $skip_own = false) + { + $this->requireUser(); + + $object = NULL; + + switch($type) { + case "post": + $object = (new PostsRepo)->getPostById($owner_id, $item_id); + break; + case "comment": + $object = (new CommentsRepo)->get($item_id); + break; + case "photo": + $object = (new PhotosRepo)->getByOwnerAndVID($owner_id, $item_id); + break; + case "video": + $object = (new VideosRepo)->getByOwnerAndVID($owner_id, $item_id); + break; + default: + $this->fail(58, "Invalid type"); + break; + } + + if(!$object || $object->isDeleted()) + $this->fail(56, "Invalid postable"); + + $res = (object)[ + "count" => $object->getLikesCount(), + "items" => [] + ]; + + $likers = array_slice(iterator_to_array($object->getLikers(1, $offset + $count)), $offset); + + foreach($likers as $liker) { + if($skip_own && $liker->getId() == $this->getUser()->getId()) + continue; + + if(!$extended) + $res->items[] = $liker->getId(); + else + $res->items[] = $liker->toVkApiStruct(); + } + + return $res; + } } diff --git a/VKAPI/Handlers/Messages.php b/VKAPI/Handlers/Messages.php index bc9035f5..6fc057e0 100644 --- a/VKAPI/Handlers/Messages.php +++ b/VKAPI/Handlers/Messages.php @@ -65,7 +65,8 @@ final class Messages extends VKAPIRequestHandler ]; } - function send(int $user_id = -1, int $peer_id = -1, string $domain = "", int $chat_id = -1, string $user_ids = "", string $message = "", int $sticker_id = -1, int $forGodSakePleaseDoNotReportAboutMyOnlineActivity = 0) + function send(int $user_id = -1, int $peer_id = -1, string $domain = "", int $chat_id = -1, string $user_ids = "", string $message = "", int $sticker_id = -1, int $forGodSakePleaseDoNotReportAboutMyOnlineActivity = 0, + string $attachment = "") # интересно почему не attachments { $this->requireUser(); $this->willExecuteWriteAction(); @@ -79,7 +80,8 @@ final class Messages extends VKAPIRequestHandler $this->fail(946, "Chats are not implemented"); else if($sticker_id !== -1) $this->fail(-151, "Stickers are not implemented"); - else if(empty($message)) + + if(empty($message) && empty($attachment)) $this->fail(100, "Message text is empty or invalid"); # lol recursion @@ -117,6 +119,21 @@ final class Messages extends VKAPIRequestHandler if(!$msg) $this->fail(950, "Internal error"); else + if(!empty($attachment)) { + $attachs = parseAttachments($attachment); + + # Работают только фотки, остальное просто не будет отображаться. + if(sizeof($attachs) >= 10) + $this->fail(15, "Too many attachments"); + + foreach($attachs as $attach) { + if($attach && !$attach->isDeleted() && $attach->getOwner()->getId() == $this->getUser()->getId()) + $msg->attach($attach); + else + $this->fail(52, "One of the attachments is invalid"); + } + } + return $msg->getId(); } @@ -393,4 +410,49 @@ final class Messages extends VKAPIRequestHandler return $res; } + + function edit(int $message_id, string $message = "", string $attachment = "", int $peer_id = 0) + { + $this->requireUser(); + $this->willExecuteWriteAction(); + + $msg = (new MSGRepo)->get($message_id); + + if(empty($message) && empty($attachment)) + $this->fail(100, "Required parameter 'message' missing."); + + if(!$msg || $msg->isDeleted()) + $this->fail(102, "Invalid message"); + + if($msg->getSender()->getId() != $this->getUser()->getId()) + $this->fail(15, "Access to message denied"); + + if(!empty($message)) + $msg->setContent($message); + + $msg->setEdited(time()); + $msg->save(true); + + if(!empty($attachment)) { + $attachs = parseAttachments($attachment); + $newAttachmentsCount = sizeof($attachs); + + $postsAttachments = iterator_to_array($msg->getChildren()); + + if(sizeof($postsAttachments) >= 10) + $this->fail(15, "Message have too many attachments"); + + if(($newAttachmentsCount + sizeof($postsAttachments)) > 10) + $this->fail(158, "Message will have too many attachments"); + + foreach($attachs as $attach) { + if($attach && !$attach->isDeleted() && $attach->getOwner()->getId() == $this->getUser()->getId()) + $msg->attach($attach); + else + $this->fail(52, "One of the attachments is invalid"); + } + } + + return 1; + } } diff --git a/VKAPI/Handlers/Notes.php b/VKAPI/Handlers/Notes.php index 7c9c9fec..ef8cd071 100644 --- a/VKAPI/Handlers/Notes.php +++ b/VKAPI/Handlers/Notes.php @@ -161,19 +161,17 @@ final class Notes extends VKAPIRequestHandler function editComment(int $comment_id, string $message, int $owner_id = NULL) { - /* $this->requireUser(); $this->willExecuteWriteAction(); $comment = (new CommentsRepo)->get($comment_id); - if($comment->getOwner() != $this->getUser()->getId()) + if($comment->getOwner()->getId() != $this->getUser()->getId()) $this->fail(15, "Access to comment denied"); $comment->setContent($message); $comment->setEdited(time()); - $comment->save(); - */ + $comment->save(true); return 1; } diff --git a/VKAPI/Handlers/Notifications.php b/VKAPI/Handlers/Notifications.php new file mode 100644 index 00000000..8a047f80 --- /dev/null +++ b/VKAPI/Handlers/Notifications.php @@ -0,0 +1,83 @@ +requireUser(); + + $res = (object)[ + "items" => [], + "profiles" => [], + "groups" => [], + "last_viewed" => $this->getUser()->getNotificationOffset() + ]; + + if($count > 100) + $this->fail(125, "Count is too big"); + + if(!eventdb()) + $this->fail(1289, "EventDB is disabled on this instance"); + + $notifs = array_slice(iterator_to_array((new Notifs)->getNotificationsByUser($this->getUser(), $this->getUser()->getNotificationOffset(), (bool)$archived, 1, $offset + $count)), $offset); + $tmpProfiles = []; + foreach($notifs as $notif) { + $sxModel = $notif->getModel(1); + + if(!method_exists($sxModel, "getAvatarUrl")) + $sxModel = $notif->getModel(0); + + + $tmpProfiles[] = $sxModel instanceof Club ? $sxModel->getId() * -1 : $sxModel->getId(); + $res->items[] = $notif->toVkApiStruct(); + } + + foreach(array_unique($tmpProfiles) as $id) { + if($id > 0) { + $sxModel = (new Users)->get($id); + $result = (object)[ + "uid" => $sxModel->getId(), + "first_name" => $sxModel->getFirstName(), + "last_name" => $sxModel->getLastName(), + "photo" => $sxModel->getAvatarUrl(), + "photo_medium_rec" => $sxModel->getAvatarUrl("tiny"), + "screen_name" => $sxModel->getShortCode() + ]; + + $res->profiles[] = $result; + } else { + $sxModel = (new Clubs)->get(abs($id)); + $result = $sxModel->toVkApiStruct($this->getUser()); + + $res->groups[] = $result; + } + } + + return $res; + } + + function markAsViewed() + { + $this->requireUser(); + $this->willExecuteWriteAction(); + + try { + $this->getUser()->updateNotificationOffset(); + $this->getUser()->save(); + } catch(\Throwable $e) { + return 0; + } + + return 1; + } +} diff --git a/VKAPI/Handlers/Polls.php b/VKAPI/Handlers/Polls.php index be947a44..c84f8283 100755 --- a/VKAPI/Handlers/Polls.php +++ b/VKAPI/Handlers/Polls.php @@ -104,4 +104,67 @@ final class Polls extends VKAPIRequestHandler $this->fail(8, "how.to. ook.bacon.in.microwova."); } } + + function getVoters(int $poll_id, int $answer_ids, int $offset = 0, int $count = 6) + { + $this->requireUser(); + + $poll = (new PollsRepo)->get($poll_id); + + if(!$poll) + $this->fail(251, "Invalid poll"); + + if($poll->isAnonymous()) + $this->fail(251, "Access denied: poll is anonymous."); + + $voters = array_slice($poll->getVoters($answer_ids, 1, $offset + $count), $offset); + $res = (object)[ + "answer_id" => $answer_ids, + "users" => [] + ]; + + foreach($voters as $voter) + $res->users[] = $voter->toVkApiStruct(); + + return $res; + } + + function create(string $question, string $add_answers, bool $disable_unvote = false, bool $is_anonymous = false, bool $is_multiple = false, int $end_date = 0) + { + $this->requireUser(); + $this->willExecuteWriteAction(); + + $options = json_decode($add_answers); + + if(!$options || empty($options)) + $this->fail(62, "Invalid options"); + + if(sizeof($options) > ovkGetQuirk("polls.max-opts")) + $this->fail(51, "Too many options"); + + $poll = new Poll; + $poll->setOwner($this->getUser()); + $poll->setTitle($question); + $poll->setMultipleChoice($is_multiple); + $poll->setAnonymity($is_anonymous); + $poll->setRevotability(!$disable_unvote); + $poll->setOptions($options); + + if($end_date > time()) { + if($end_date > time() + (DAY * 365)) + $this->fail(89, "End date is too big"); + + $poll->setEndDate($end_date); + } + + $poll->save(); + + return $this->getById($poll->getId()); + } + + function edit() + { + #todo + return 1; + } } diff --git a/VKAPI/Handlers/Users.php b/VKAPI/Handlers/Users.php index 088613ef..d1c29705 100644 --- a/VKAPI/Handlers/Users.php +++ b/VKAPI/Handlers/Users.php @@ -1,7 +1,8 @@ $this->get(implode(',', $array), $nfilds, $offset, $count) ]; } + + function report(int $user_id, string $type = "spam", string $comment = "") + { + $this->requireUser(); + $this->willExecuteWriteAction(); + + if($user_id == $this->getUser()->getId()) + $this->fail(12, "Can't report yourself."); + + if(sizeof(iterator_to_array((new Reports)->getDuplicates("user", $user_id, NULL, $this->getUser()->getId()))) > 0) + return 1; + + $report = new Report; + $report->setUser_id($this->getUser()->getId()); + $report->setTarget_id($user_id); + $report->setType("user"); + $report->setReason($comment); + $report->setCreated(time()); + $report->save(); + + return 1; + } } diff --git a/VKAPI/Handlers/VKAPIRequestHandler.php b/VKAPI/Handlers/VKAPIRequestHandler.php index d2fcfc74..4953dbe1 100644 --- a/VKAPI/Handlers/VKAPIRequestHandler.php +++ b/VKAPI/Handlers/VKAPIRequestHandler.php @@ -28,7 +28,7 @@ abstract class VKAPIRequestHandler protected function getPlatform(): ?string { - return $this->platform; + return $this->platform ?? ""; } protected function userAuthorized(): bool diff --git a/VKAPI/Handlers/Video.php b/VKAPI/Handlers/Video.php index 740ccd54..c51fff3f 100755 --- a/VKAPI/Handlers/Video.php +++ b/VKAPI/Handlers/Video.php @@ -11,11 +11,11 @@ use openvk\Web\Models\Repositories\Comments as CommentsRepo; final class Video extends VKAPIRequestHandler { - function get(int $owner_id, string $videos, int $offset = 0, int $count = 30, int $extended = 0): object + function get(int $owner_id, string $videos = "", int $offset = 0, int $count = 30, int $extended = 0): object { $this->requireUser(); - if ($videos) { + if(!empty($videos)) { $vids = explode(',', $videos); foreach($vids as $vid) diff --git a/VKAPI/Handlers/Wall.php b/VKAPI/Handlers/Wall.php index 179d5e0e..907f06fa 100644 --- a/VKAPI/Handlers/Wall.php +++ b/VKAPI/Handlers/Wall.php @@ -15,6 +15,7 @@ use openvk\Web\Models\Entities\Video; use openvk\Web\Models\Repositories\Videos as VideosRepo; use openvk\Web\Models\Entities\Note; use openvk\Web\Models\Repositories\Notes as NotesRepo; +use openvk\Web\Models\Repositories\Polls as PollsRepo; use openvk\Web\Models\Repositories\Audios as AudiosRepo; final class Wall extends VKAPIRequestHandler @@ -125,7 +126,7 @@ final class Wall extends VKAPIRequestHandler "post_type" => "post", "text" => $post->getText(false), "copy_history" => $repost, - "can_edit" => 0, # TODO + "can_edit" => $post->canBeEditedBy($this->getUser()), "can_delete" => $post->canBeDeletedBy($this->getUser()), "can_pin" => $post->canBePinnedBy($this->getUser()), "can_archive" => false, # TODO MAYBE @@ -305,7 +306,7 @@ final class Wall extends VKAPIRequestHandler "post_type" => "post", "text" => $post->getText(false), "copy_history" => $repost, - "can_edit" => 0, # TODO + "can_edit" => $post->canBeEditedBy($this->getUser()), "can_delete" => $post->canBeDeletedBy($user), "can_pin" => $post->canBePinnedBy($user), "can_archive" => false, # TODO MAYBE @@ -444,6 +445,7 @@ final class Wall extends VKAPIRequestHandler $this->fail(100, "One of the parameters specified was missing or invalid"); } + # TODO use parseAttachments if(!empty($attachments)) { $attachmentsArr = explode(",", $attachments); # Аттачи такого вида: [тип][id владельца]_[id вложения] @@ -451,6 +453,10 @@ final class Wall extends VKAPIRequestHandler if(sizeof($attachmentsArr) > 10) $this->fail(50, "Error: too many attachments"); + + preg_match_all("/poll/m", $attachments, $matches, PREG_SET_ORDER, 0); + if(sizeof($matches) > 1) + $this->fail(85, "Error: too many polls"); foreach($attachmentsArr as $attac) { $attachmentType = NULL; @@ -461,8 +467,11 @@ final class Wall extends VKAPIRequestHandler $attachmentType = "video"; elseif(str_contains($attac, "note")) $attachmentType = "note"; + elseif(str_contains($attac, "poll")) + $attachmentType = "poll"; elseif(str_contains($attac, "audio")) $attachmentType = "audio"; + else $this->fail(205, "Unknown attachment type"); @@ -497,6 +506,13 @@ final class Wall extends VKAPIRequestHandler $this->fail(11, "Access to note denied"); $post->attach($attacc); + } elseif($attachmentType == "poll") { + $attacc = (new PollsRepo)->get($attachmentId); + + if(!$attacc || $attacc->isDeleted()) + $this->fail(100, "Poll does not exist"); + if($attacc->getOwner()->getId() != $this->getUser()->getId()) + $this->fail(43, "You do not have access to this poll"); } elseif($attachmentType == "audio") { $attacc = (new AudiosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId); if(!$attacc || $attacc->isDeleted()) @@ -813,6 +829,95 @@ final class Wall extends VKAPIRequestHandler return 1; } + function edit(int $owner_id, int $post_id, string $message = "", string $attachments = "") { + $this->requireUser(); + $this->willExecuteWriteAction(); + + $post = (new PostsRepo)->getPostById($owner_id, $post_id); + + if(!$post || $post->isDeleted()) + $this->fail(102, "Invalid post"); + + if(empty($message) && empty($attachments)) + $this->fail(100, "Required parameter 'message' missing."); + + if(!$post->canBeEditedBy($this->getUser())) + $this->fail(7, "Access to editing denied"); + + if(!empty($message)) + $post->setContent($message); + + $post->setEdited(time()); + $post->save(true); + + # todo добавить такое в веб версию + if(!empty($attachments)) { + $attachs = parseAttachments($attachments); + $newAttachmentsCount = sizeof($attachs); + + $postsAttachments = iterator_to_array($post->getChildren()); + + if(sizeof($postsAttachments) >= 10) + $this->fail(15, "Post have too many attachments"); + + if(($newAttachmentsCount + sizeof($postsAttachments)) > 10) + $this->fail(158, "Post will have too many attachments"); + + foreach($attachs as $attach) { + if($attach && !$attach->isDeleted() && $attach->getOwner()->getId() == $this->getUser()->getId()) + $post->attach($attach); + else + $this->fail(52, "One of the attachments is invalid"); + } + } + + return ["post_id" => $post->getVirtualId()]; + } + + function editComment(int $comment_id, int $owner_id = 0, string $message = "", string $attachments = "") { + $this->requireUser(); + $this->willExecuteWriteAction(); + + $comment = (new CommentsRepo)->get($comment_id); + + if(empty($message) && empty($attachments)) + $this->fail(100, "Required parameter 'message' missing."); + + if(!$comment || $comment->isDeleted()) + $this->fail(102, "Invalid comment"); + + if(!$comment->canBeEditedBy($this->getUser())) + $this->fail(15, "Access to editing comment denied"); + + if(!empty($message)) + $comment->setContent($message); + + $comment->setEdited(time()); + $comment->save(true); + + if(!empty($attachments)) { + $attachs = parseAttachments($attachments); + $newAttachmentsCount = sizeof($attachs); + + $postsAttachments = iterator_to_array($comment->getChildren()); + + if(sizeof($postsAttachments) >= 10) + $this->fail(15, "Post have too many attachments"); + + if(($newAttachmentsCount + sizeof($postsAttachments)) > 10) + $this->fail(158, "Post will have too many attachments"); + + foreach($attachs as $attach) { + if($attach && !$attach->isDeleted() && $attach->getOwner()->getId() == $this->getUser()->getId()) + $comment->attach($attach); + else + $this->fail(52, "One of the attachments is invalid"); + } + } + + return 1; + } + private function getApiPhoto($attachment) { return [ "type" => "photo", diff --git a/Web/Models/Entities/Club.php b/Web/Models/Entities/Club.php index b8b8838a..319678f3 100644 --- a/Web/Models/Entities/Club.php +++ b/Web/Models/Entities/Club.php @@ -397,7 +397,7 @@ class Club extends RowModel function toVkApiStruct(?User $user = NULL): object { - $res = (object)[]; + $res = (object) []; $res->id = $this->getId(); $res->name = $this->getName(); diff --git a/Web/Models/Entities/Comment.php b/Web/Models/Entities/Comment.php index 37b06dda..90057bdd 100644 --- a/Web/Models/Entities/Comment.php +++ b/Web/Models/Entities/Comment.php @@ -90,7 +90,20 @@ class Comment extends Post { return "/wall" . $this->getTarget()->getPrettyId() . "#_comment" . $this->getId(); } + + function toNotifApiStruct() + { + $res = (object)[]; + + $res->id = $this->getId(); + $res->owner_id = $this->getOwner()->getId(); + $res->date = $this->getPublicationTime()->timestamp(); + $res->text = $this->getText(false); + $res->post = NULL; # todo + return $res; + } + function canBeEditedBy(?User $user = NULL): bool { if(!$user) diff --git a/Web/Models/Entities/Message.php b/Web/Models/Entities/Message.php index 97f3cf69..00de6e98 100644 --- a/Web/Models/Entities/Message.php +++ b/Web/Models/Entities/Message.php @@ -123,7 +123,11 @@ class Message extends RowModel ], ]; } else { - throw new \Exception("Unknown attachment type: " . get_class($attachment)); + $attachments[] = [ + "type" => "unknown" + ]; + + # throw new \Exception("Unknown attachment type: " . get_class($attachment)); } } diff --git a/Web/Models/Entities/Note.php b/Web/Models/Entities/Note.php index 83082bf3..bdc34307 100644 --- a/Web/Models/Entities/Note.php +++ b/Web/Models/Entities/Note.php @@ -131,7 +131,7 @@ class Note extends Postable $res->date = $this->getPublicationTime()->timestamp(); $res->comments = $this->getCommentsCount(); $res->read_comments = $this->getCommentsCount(); - $res->view_url = "/note".$this->getOwner()->getId()."_".$this->getId(); + $res->view_url = "/note".$this->getOwner()->getId()."_".$this->getVirtualId(); $res->privacy_view = 1; $res->can_comment = 1; $res->text_wiki = "r"; diff --git a/Web/Models/Entities/Notifications/Notification.php b/Web/Models/Entities/Notifications/Notification.php index cad6e74b..8d7ab873 100644 --- a/Web/Models/Entities/Notifications/Notification.php +++ b/Web/Models/Entities/Notifications/Notification.php @@ -132,4 +132,138 @@ QUERY; return true; } + + function getVkApiInfo() + { + $origin_m = $this->encodeType($this->originModel); + $target_m = $this->encodeType($this->targetModel); + + $info = [ + "type" => "", + "parent" => NULL, + "feedback" => NULL, + ]; + + switch($this->getActionCode()) { + case 0: + $info["type"] = "like_post"; + $info["parent"] = $this->getModel(0)->toNotifApiStruct(); + $info["feedback"] = $this->getModel(1)->toVkApiStruct(); + break; + case 1: + $info["type"] = "copy_post"; + $info["parent"] = $this->getModel(0)->toNotifApiStruct(); + $info["feedback"] = NULL; # todo + break; + case 2: + switch($origin_m) { + case 19: + $info["type"] = "comment_video"; + $info["parent"] = $this->getModel(0)->toNotifApiStruct(); + $info["feedback"] = NULL; # айди коммента не сохраняется в бд( ну пиздец блять + break; + case 13: + $info["type"] = "comment_photo"; + $info["parent"] = $this->getModel(0)->toNotifApiStruct(); + $info["feedback"] = NULL; + break; + # unstandart (vk forgor about notes) + case 10: + $info["type"] = "comment_note"; + $info["parent"] = $this->getModel(0)->toVkApiStruct(); + $info["feedback"] = NULL; + break; + case 14: + $info["type"] = "comment_post"; + $info["parent"] = $this->getModel(0)->toNotifApiStruct(); + $info["feedback"] = NULL; + break; + # unused (users don't have topics bruh) + case 21: + $info["type"] = "comment_topic"; + $info["parent"] = $this->getModel(0)->toVkApiStruct(0, 90); + break; + default: + $info["type"] = "comment_unknown"; + break; + } + + break; + case 3: + $info["type"] = "wall"; + $info["feedback"] = $this->getModel(0)->toNotifApiStruct(); + break; + case 4: + switch($target_m) { + case 14: + $info["type"] = "mention"; + $info["feedback"] = $this->getModel(1)->toNotifApiStruct(); + break; + case 19: + $info["type"] = "mention_comment_video"; + $info["parent"] = $this->getModel(1)->toNotifApiStruct(); + break; + case 13: + $info["type"] = "mention_comment_photo"; + $info["parent"] = $this->getModel(1)->toNotifApiStruct(); + break; + # unstandart + case 10: + $info["type"] = "mention_comment_note"; + $info["parent"] = $this->getModel(1)->toVkApiStruct(); + break; + case 21: + $info["type"] = "mention_comments"; + break; + default: + $info["type"] = "mention_comment_unknown"; + break; + } + break; + case 5: + $info["type"] = "make_you_admin"; + $info["parent"] = $this->getModel(0)->toVkApiStruct($this->getModel(1)); + break; + # Нужно доделать после мержа #935 + case 6: + $info["type"] = "wall_publish"; + break; + # В вк не было такого уведомления, так что unstandart + case 7: + $info["type"] = "new_posts_in_club"; + break; + # В вк при передаче подарков приходит сообщение, а не уведомление, так что unstandart + case 9601: + $info["type"] = "sent_gift"; + $info["parent"] = $this->getModel(1)->toVkApiStruct($this->getModel(1)); + break; + case 9602: + $info["type"] = "voices_transfer"; + $info["parent"] = $this->getModel(1)->toVkApiStruct($this->getModel(1)); + break; + case 9603: + $info["type"] = "up_rating"; + $info["parent"] = $this->getModel(1)->toVkApiStruct($this->getModel(1)); + $info["parent"]->count = $this->getData(); + break; + default: + $info["type"] = NULL; + break; + } + + return $info; + } + + function toVkApiStruct() + { + $res = (object)[]; + + $info = $this->getVkApiInfo(); + $res->type = $info["type"]; + $res->date = $this->getDateTime()->timestamp(); + $res->parent = $info["parent"]; + $res->feedback = $info["feedback"]; + $res->reply = NULL; # Ответы на комментарии не реализованы + return $res; + } } diff --git a/Web/Models/Entities/Photo.php b/Web/Models/Entities/Photo.php index c1825b3a..72d371ad 100644 --- a/Web/Models/Entities/Photo.php +++ b/Web/Models/Entities/Photo.php @@ -347,4 +347,20 @@ class Photo extends Media return $photo; } + + function toNotifApiStruct() + { + $res = (object)[]; + + $res->id = $this->getVirtualId(); + $res->owner_id = $this->getOwner()->getId(); + $res->aid = 0; + $res->src = $this->getURLBySizeId("tiny"); + $res->src_big = $this->getURLBySizeId("normal"); + $res->src_small = $this->getURLBySizeId("miniscule"); + $res->text = $this->getDescription(); + $res->created = $this->getPublicationTime()->timestamp(); + + return $res; + } } diff --git a/Web/Models/Entities/Post.php b/Web/Models/Entities/Post.php index 6d0fe8cf..a8d444eb 100644 --- a/Web/Models/Entities/Post.php +++ b/Web/Models/Entities/Post.php @@ -245,7 +245,24 @@ class Post extends Postable $this->unwire(); $this->save(); } + + function toNotifApiStruct() + { + $res = (object)[]; + + $res->id = $this->getVirtualId(); + $res->to_id = $this->getOwner() instanceof Club ? $this->getOwner()->getId() * -1 : $this->getOwner()->getId(); + $res->from_id = $res->to_id; + $res->date = $this->getPublicationTime()->timestamp(); + $res->text = $this->getText(false); + $res->attachments = []; # todo + $res->copy_owner_id = NULL; # todo + $res->copy_post_id = NULL; # todo + + return $res; + } + function canBeEditedBy(?User $user = NULL): bool { if(!$user) diff --git a/Web/Models/Entities/Postable.php b/Web/Models/Entities/Postable.php index 8f783238..365c0f26 100644 --- a/Web/Models/Entities/Postable.php +++ b/Web/Models/Entities/Postable.php @@ -88,13 +88,14 @@ abstract class Postable extends Attachable ])->group("origin")); } - # TODO add pagination - function getLikers(): \Traversable + function getLikers(int $page = 1, ?int $perPage = NULL): \Traversable { + $perPage ??= OPENVK_DEFAULT_PER_PAGE; + $sel = DB::i()->getContext()->table("likes")->where([ "model" => static::class, "target" => $this->getRecord()->id, - ]); + ])->page($page, $perPage); foreach($sel as $like) yield (new Users)->get($like->origin); diff --git a/Web/Models/Entities/Video.php b/Web/Models/Entities/Video.php index db520ee1..a9d565c5 100644 --- a/Web/Models/Entities/Video.php +++ b/Web/Models/Entities/Video.php @@ -219,4 +219,23 @@ class Video extends Media return $video; } + + function toNotifApiStruct() + { + $fromYoutube = $this->getType() == Video::TYPE_EMBED; + $res = (object)[]; + + $res->id = $this->getVirtualId(); + $res->owner_id = $this->getOwner()->getId(); + $res->title = $this->getName(); + $res->description = $this->getDescription(); + $res->duration = "22"; + $res->link = "/video".$this->getOwner()->getId()."_".$this->getVirtualId(); + $res->image = $this->getThumbnailURL(); + $res->date = $this->getPublicationTime()->timestamp(); + $res->views = 0; + $res->player = !$fromYoutube ? $this->getURL() : $this->getVideoDriver()->getURL(); + + return $res; + } } diff --git a/bootstrap.php b/bootstrap.php index 4b67a0b7..96136116 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -230,6 +230,44 @@ function ovk_is_ssl(): bool return $GLOBALS["requestIsSSL"]; } +function parseAttachments(string $attachments) +{ + $attachmentsArr = explode(",", $attachments); + $returnArr = []; + + foreach($attachmentsArr as $attachment) { + $attachmentType = NULL; + + if(str_contains($attachment, "photo")) + $attachmentType = "photo"; + elseif(str_contains($attachment, "video")) + $attachmentType = "video"; + elseif(str_contains($attachment, "note")) + $attachmentType = "note"; + + $attachmentIds = str_replace($attachmentType, "", $attachment); + $attachmentOwner = (int)explode("_", $attachmentIds)[0]; + $attachmentId = (int)end(explode("_", $attachmentIds)); + + switch($attachmentType) { + case "photo": + $attachmentObj = (new openvk\Web\Models\Repositories\Photos)->getByOwnerAndVID($attachmentOwner, $attachmentId); + $returnArr[] = $attachmentObj; + break; + case "video": + $attachmentObj = (new openvk\Web\Models\Repositories\Videos)->getByOwnerAndVID($attachmentOwner, $attachmentId); + $returnArr[] = $attachmentObj; + break; + case "note": + $attachmentObj = (new openvk\Web\Models\Repositories\Notes)->getNoteById($attachmentOwner, $attachmentId); + $returnArr[] = $attachmentObj; + break; + } + } + + return $returnArr; +} + function ovk_scheme(bool $with_slashes = false): string { $scheme = ovk_is_ssl() ? "https" : "http";