diff --git a/ServiceAPI/Groups.php b/ServiceAPI/Groups.php new file mode 100644 index 00000000..9eed0e8d --- /dev/null +++ b/ServiceAPI/Groups.php @@ -0,0 +1,39 @@ +user = $user; + $this->groups = new Clubs; + } + + function getWriteableClubs(callable $resolve, callable $reject) + { + $clubs = []; + $wclubs = $this->groups->getWriteableClubs($this->user->getId()); + $count = $this->groups->getWriteableClubsCount($this->user->getId()); + + if(!$count) { + $reject("You don't have any groups with write access"); + + return; + } + + foreach($wclubs as $club) { + $clubs[] = [ + "name" => $club->getName(), + "id" => $club->getId(), + "avatar" => $club->getAvatarUrl() # если в овк когда-нибудь появится крутой список с аватарками, то можно использовать это поле + ]; + } + + $resolve($clubs); + } +} diff --git a/VKAPI/Handlers/Wall.php b/VKAPI/Handlers/Wall.php index c39a3316..41af5c0d 100644 --- a/VKAPI/Handlers/Wall.php +++ b/VKAPI/Handlers/Wall.php @@ -453,25 +453,38 @@ final class Wall extends VKAPIRequestHandler return (object)["post_id" => $post->getVirtualId()]; } - function repost(string $object, string $message = "") { + function repost(string $object, string $message = "", int $group_id = 0) { $this->requireUser(); $this->willExecuteWriteAction(); $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()); + + if($group_id > 0) { + $club = (new ClubsRepo)->get($group_id); + if(!$club) + $this->fail(42, "Invalid group"); + + if(!$club->canBeModifiedBy($this->user)) + $this->fail(16, "Access to group denied"); + + $nPost->setWall($group_id * -1); + } else { + $nPost->setWall($this->user->getId()); + } + $nPost->setContent($message); $nPost->setApi_Source_Name($this->getPlatform()); $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(); @@ -483,6 +496,7 @@ final class Wall extends VKAPIRequestHandler ]; } + 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(); diff --git a/Web/Models/Repositories/Clubs.php b/Web/Models/Repositories/Clubs.php index edbe75c6..8e97f3eb 100644 --- a/Web/Models/Repositories/Clubs.php +++ b/Web/Models/Repositories/Clubs.php @@ -1,7 +1,7 @@ context = DatabaseConnection::i()->getContext(); - $this->clubs = $this->context->table("groups"); + $this->context = DatabaseConnection::i()->getContext(); + $this->clubs = $this->context->table("groups"); + $this->coadmins = $this->context->table("group_coadmins"); } private function toClub(?ActiveRow $ar): ?Club @@ -70,6 +72,26 @@ class Clubs ]; */ } - + + function getWriteableClubs(int $id): \Traversable + { + $result = $this->clubs->where("owner", $id); + $coadmins = $this->coadmins->where("user", $id); + + foreach($result as $entry) { + yield new Club($entry); + } + + foreach($coadmins as $coadmin) { + $cl = new Manager($coadmin); + yield $cl->getClub(); + } + } + + function getWriteableClubsCount(int $id): int + { + return sizeof($this->clubs->where("owner", $id)) + sizeof($this->coadmins->where("user", $id)); + } + use \Nette\SmartObject; } diff --git a/Web/Presenters/WallPresenter.php b/Web/Presenters/WallPresenter.php index ffcec2a7..928026f8 100644 --- a/Web/Presenters/WallPresenter.php +++ b/Web/Presenters/WallPresenter.php @@ -363,21 +363,52 @@ final class WallPresenter extends OpenVKPresenter $this->assertNoCSRF(); $post = $this->posts->getPostById($wall, $post_id); - if(!$post || $post->isDeleted()) $this->notFound(); + + if(!$post || $post->isDeleted()) + $this->notFound(); + $where = $this->postParam("type") ?? "wall"; + $groupId = NULL; + $flags = 0; + + if($where == "group") + $groupId = $this->postParam("groupId"); + if(!is_null($this->user)) { $nPost = new Post; - $nPost->setOwner($this->user->id); - $nPost->setWall($this->user->id); + + if($where == "wall") { + $nPost->setOwner($this->user->id); + $nPost->setWall($this->user->id); + } elseif($where == "group") { + $nPost->setOwner($this->user->id); + $club = (new Clubs)->get((int)$groupId); + + if(!$club || !$club->canBeModifiedBy($this->user->identity)) + $this->notFound(); + + if($this->postParam("asGroup") == 1) + $flags |= 0b10000000; + + if($this->postParam("signed") == 1) + $flags |= 0b01000000; + + $nPost->setWall($groupId * -1); + } + $nPost->setContent($this->postParam("text")); + $nPost->setFlags($flags); $nPost->save(); + $nPost->attach($post); if($post->getOwner(false)->getId() !== $this->user->identity->getId() && !($post->getOwner() instanceof Club)) (new RepostNotification($post->getOwner(false), $post, $this->user->identity))->emit(); }; - - $this->returnJson(["wall_owner" => $this->user->identity->getId()]); + + $this->returnJson([ + "wall_owner" => $where == "wall" ? $this->user->identity->getId() : $groupId * -1 + ]); } function renderDelete(int $wall, int $post_id): void diff --git a/Web/Presenters/templates/components/post/microblogpost.xml b/Web/Presenters/templates/components/post/microblogpost.xml index 4c383d12..98a41d72 100644 --- a/Web/Presenters/templates/components/post/microblogpost.xml +++ b/Web/Presenters/templates/components/post/microblogpost.xml @@ -98,9 +98,9 @@ {_comment}
- +
- {if $post->getRepostCount() > 0}{$post->getRepostCount()}{/if} + {if $post->getRepostCount() > 0}{$post->getRepostCount()}{/if}
{if !($forceNoLike ?? false)} diff --git a/Web/Presenters/templates/components/post/oldpost.xml b/Web/Presenters/templates/components/post/oldpost.xml index 66903cca..c893e289 100644 --- a/Web/Presenters/templates/components/post/oldpost.xml +++ b/Web/Presenters/templates/components/post/oldpost.xml @@ -111,10 +111,10 @@  |  {/if} - + {_share} {if $post->getRepostCount() > 0} - ({$post->getRepostCount()}) + ({$post->getRepostCount()}) {/if} diff --git a/Web/static/js/openvk.cls.js b/Web/static/js/openvk.cls.js index 8cb6ecb5..ded00fbb 100644 --- a/Web/static/js/openvk.cls.js +++ b/Web/static/js/openvk.cls.js @@ -1,3 +1,4 @@ + function expand_wall_textarea(id) { var el = document.getElementById('post-buttons'+id); var wi = document.getElementById('wall-post-input'+id); @@ -65,7 +66,6 @@ function toggleMenu(id) { }); } } - document.addEventListener("DOMContentLoaded", function() { //BEGIN u("#_photoDelete").on("click", function(e) { @@ -88,7 +88,6 @@ document.addEventListener("DOMContentLoaded", function() { //BEGIN return e.preventDefault(); }); - /* @rem-pai why this func wasn't named as "#_deleteDialog"? It looks universal IMO */ u("#_noteDelete").on("click", function(e) { @@ -170,28 +169,72 @@ document.addEventListener("DOMContentLoaded", function() { //BEGIN }); //END ONREADY DECLS -function repostPost(id, hash) { - uRepostMsgTxt = tr('your_comment') + ":

"; - - MessageBox(tr('share'), uRepostMsgTxt, [tr('send'), tr('cancel')], [ - (function() { - text = document.querySelector("#uRepostMsgInput_"+id).value; - hash = encodeURIComponent(hash); - xhr = new XMLHttpRequest(); - xhr.open("POST", "/wall"+id+"/repost?hash="+hash, true); - xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); - xhr.onload = (function() { +async function repostPost(id, hash) { + uRepostMsgTxt = ` + ${tr('auditory')}:
+ ${tr("in_wall")}
+ ${tr("in_group")}
+
+ ${tr('your_comment')}: + + +

`; + let clubs = []; + repostsCount = document.getElementById("repostsCount"+id) + prevVal = repostsCount != null ? Number(repostsCount.innerHTML) : 0; + + MessageBox(tr('share'), uRepostMsgTxt, [tr('send'), tr('cancel')], [ + (function() { + text = document.querySelector("#uRepostMsgInput_"+id).value; + type = "user"; + radios = document.querySelectorAll('input[name="type"]') + for(const r of radios) + { + if(r.checked) + { + type = r.value; + break; + } + } + groupId = document.querySelector("#groupId").value; + asGroup = asgroup.checked == true ? 1 : 0; + signed = signed.checked == true ? 1 : 0; + hash = encodeURIComponent(hash); + + xhr = new XMLHttpRequest(); + xhr.open("POST", "/wall"+id+"/repost?hash="+hash, true); + xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); + xhr.onload = (function() { if(xhr.responseText.indexOf("wall_owner") === -1) - MessageBox(tr('error'), tr('error_repost_fail'), [tr('ok')], [Function.noop]); - else { - let jsonR = JSON.parse(xhr.responseText); + MessageBox(tr('error'), tr('error_repost_fail'), [tr('ok')], [Function.noop]); + else { + let jsonR = JSON.parse(xhr.responseText); NewNotification(tr('information_-1'), tr('shared_succ'), null, () => {window.location.href = "/wall" + jsonR.wall_owner}); - } - }); - xhr.send('text=' + encodeURI(text)); - }), - Function.noop - ]); + repostsCount != null ? + repostsCount.innerHTML = prevVal+1 : + document.getElementById("reposts"+id).insertAdjacentHTML("beforeend", "(1)") //для старого вида постов + } + }); + xhr.send('text='+encodeURI(text) + '&type='+type + '&groupId='+groupId + "&asGroup="+asGroup + "&signed="+signed); + }), + Function.noop + ]); + + try + { + clubs = await API.Groups.getWriteableClubs(); + for(const el of clubs) { + document.getElementById("groupId").insertAdjacentHTML("beforeend", ``) + } + + } catch(rejection) { + console.error(rejection) + document.getElementById("group").setAttribute("disabled", "disabled") + } } function setClubAdminComment(clubId, adminId, hash) { @@ -535,4 +578,4 @@ $(document).on("scroll", () => { $(".floating_sidebar")[0].classList.remove("hide_anim"); }, 250); } -}) +}) \ No newline at end of file diff --git a/locales/en.strings b/locales/en.strings index 8e32ea66..c70bc259 100644 --- a/locales/en.strings +++ b/locales/en.strings @@ -175,6 +175,9 @@ "pinned" = "pinned"; "comments_tip" = "Be first, who leaves a comment at this post!"; "your_comment" = "Your comment"; +"auditory" = "Auditory"; +"in_wall" = "to user's wall"; +"in_group" = "to group"; "shown" = "Shown"; "x_out_of" = "$1 of"; "wall_zero" = "no posts"; diff --git a/locales/ru.strings b/locales/ru.strings index 567cdc2f..6c62de66 100644 --- a/locales/ru.strings +++ b/locales/ru.strings @@ -157,6 +157,9 @@ "pinned" = "закреплено"; "comments_tip" = "Будьте первым, кто оставит комментарий!"; "your_comment" = "Ваш комментарий"; +"auditory" = "Аудитория"; +"in_wall" = "на стену"; +"in_group" = "в группу"; "shown" = "Показано"; "x_out_of" = "$1 из"; "wall_zero" = "нет записей";