[Wall] Список лайкнувших и поделившихся записью/комментарием

This commit is contained in:
n1rwana 2023-08-15 11:52:54 +03:00
parent c2b6db1b8a
commit 4c9061827c
No known key found for this signature in database
GPG key ID: 184A60085ABF17D8
7 changed files with 132 additions and 7 deletions

View file

@ -1,5 +1,6 @@
<?php declare(strict_types=1); <?php declare(strict_types=1);
namespace openvk\Web\Models\Entities; namespace openvk\Web\Models\Entities;
use openvk\Web\Models\Repositories\Posts;
use openvk\Web\Util\DateTime; use openvk\Web\Util\DateTime;
use openvk\Web\Models\RowModel; use openvk\Web\Models\RowModel;
use openvk\Web\Models\Entities\User; use openvk\Web\Models\Entities\User;
@ -99,6 +100,24 @@ abstract class Postable extends Attachable
foreach($sel as $like) foreach($sel as $like)
yield (new Users)->get($like->origin); yield (new Users)->get($like->origin);
} }
function getReposters(): \Traversable
{
$sel = $this->getRecord()
->related("attachments.attachable_id")
->where([
"attachable_type" => get_class($this),
"attachable_id" => $this->getId(),
"target_type" => get_class(new Post),
]);
foreach ($sel as $repost) {
$post = (new Posts)->get($repost->target_id);
if ($post && !$post->isDeleted()) {
yield $post->getOwner();
}
}
}
function isAnonymous(): bool function isAnonymous(): bool
{ {

View file

@ -3,7 +3,7 @@ namespace openvk\Web\Presenters;
use openvk\Web\Models\Exceptions\TooMuchOptionsException; use openvk\Web\Models\Exceptions\TooMuchOptionsException;
use openvk\Web\Models\Entities\{Poll, Post, Photo, Video, Club, User}; use openvk\Web\Models\Entities\{Poll, Post, Photo, Video, Club, User};
use openvk\Web\Models\Entities\Notifications\{MentionNotification, RepostNotification, WallPostNotification}; use openvk\Web\Models\Entities\Notifications\{MentionNotification, RepostNotification, WallPostNotification};
use openvk\Web\Models\Repositories\{Posts, Users, Clubs, Albums, Notes}; use openvk\Web\Models\Repositories\{Comments, Posts, Users, Clubs, Albums, Notes};
use Chandler\Database\DatabaseConnection; use Chandler\Database\DatabaseConnection;
use Nette\InvalidStateException as ISE; use Nette\InvalidStateException as ISE;
use Bhaktaraz\RSSGenerator\Item; use Bhaktaraz\RSSGenerator\Item;
@ -498,4 +498,64 @@ final class WallPresenter extends OpenVKPresenter
# TODO localize message based on language and ?act=(un)pin # TODO localize message based on language and ?act=(un)pin
$this->flashFail("succ", tr("information_-1"), tr("changes_saved_comment")); $this->flashFail("succ", tr("information_-1"), tr("changes_saved_comment"));
} }
private function fetchLikers($object): array
{
if (!$object || $object->isDeleted())
return ["success" => false, "error" => "Объект не найден"];
$response = [];
foreach ($object->getLikers() as $liker) {
$liker = [
"url" => $liker->getURL(),
"fname" => $liker->getFirstName(),
"lname" => $liker->getLastName(),
"avatar" => $liker->getAvatarURL()
];
if (!in_array($liker, $response)) {
$response[] = $liker;
}
}
return ["success" => true, "payload" => [count($response), $response]];
}
function renderLikers(int $wall, int $post_id): void
{
$this->returnJson($this->fetchLikers($this->posts->getPostById($wall, $post_id)));
}
function renderReposters(int $wall, int $post_id): void
{
$post = $this->posts->getPostById($wall, $post_id);
if (!$post || $post->isDeleted()) {
$this->returnJson(["success" => false, "error" => "Запись не найдена"]);
}
$response = [];
foreach ($post->getReposters() as $reposter) {
$_reposter = $reposter instanceof User ? [
"fname" => $reposter->getFirstName(),
"lname" => $reposter->getLastName()
] : [
"fname" => $reposter->getCanonicalName(),
"lname" => ""
];
$_reposter["url"] = $reposter->getURL();
$_reposter["avatar"] = $reposter->getAvatarURL();
if (!in_array($_reposter, $response)) {
$response[] = $_reposter;
}
}
$this->returnJson(["success" => true, "payload" => [count($response), $response]]);
}
function renderCommentLikers(int $comment_id): void
{
$this->returnJson($this->fetchLikers((new Comments)->get($comment_id)));
}
} }

View file

@ -49,7 +49,6 @@
<a href="/photo{$photo->getPrettyId()}/edit" class="profile_link" style="display:block;width:96%;">{_edit}</a> <a href="/photo{$photo->getPrettyId()}/edit" class="profile_link" style="display:block;width:96%;">{_edit}</a>
<a id="_photoDelete" href="/photo{$photo->getPrettyId()}/delete" class="profile_link" style="display:block;width:96%;">{_delete}</a> <a id="_photoDelete" href="/photo{$photo->getPrettyId()}/delete" class="profile_link" style="display:block;width:96%;">{_delete}</a>
</div> </div>
<a href="{$photo->getURL()}" class="profile_link" target="_blank" style="display:block;width:96%;">{_"open_original"}</a>
<a n:if="$canReport ?? false" class="profile_link" style="display:block;width:96%;" href="javascript:reportPhoto()">{_report}</a> <a n:if="$canReport ?? false" class="profile_link" style="display:block;width:96%;" href="javascript:reportPhoto()">{_report}</a>
<script n:if="$canReport ?? false"> <script n:if="$canReport ?? false">
function reportPhoto() { function reportPhoto() {

View file

@ -48,7 +48,7 @@
<div style="float: right; font-size: .7rem;"> <div style="float: right; font-size: .7rem;">
<a class="post-like-button" href="/comment{$comment->getId()}/like?hash={rawurlencode($csrfToken)}"> <a class="post-like-button" href="/comment{$comment->getId()}/like?hash={rawurlencode($csrfToken)}">
<div class="heart" style="{if $comment->hasLikeFrom($thisUser)}opacity: 1;{else}opacity: 0.4;{/if}"></div> <div class="heart" style="{if $comment->hasLikeFrom($thisUser)}opacity: 1;{else}opacity: 0.4;{/if}"></div>
<span class="likeCnt">{if $comment->getLikesCount() > 0}{$comment->getLikesCount()}{/if}</span> <span class="likeCnt" onClick="openCounter({$comment->getId()}, 'likers', true); event.preventDefault(); event.stopPropagation();">{if $comment->getLikesCount() > 0}{$comment->getLikesCount()}{/if}</span>
</a> </a>
</div> </div>
{/if} {/if}

View file

@ -114,7 +114,7 @@
<a n:if="!($forceNoShareLink ?? false)" id="reposts{$post->getPrettyId()}" class="post-share-button" {ifset $thisUser} href="javascript:repostPost('{$post->getPrettyId()}', '{rawurlencode($csrfToken)}')"{/ifset}> <a n:if="!($forceNoShareLink ?? false)" id="reposts{$post->getPrettyId()}" class="post-share-button" {ifset $thisUser} href="javascript:repostPost('{$post->getPrettyId()}', '{rawurlencode($csrfToken)}')"{/ifset}>
{_share} {_share}
{if $post->getRepostCount() > 0} {if $post->getRepostCount() > 0}
(<b id="repostsCount{$post->getPrettyId()}">{$post->getRepostCount()}</b>) (<b id="repostsCount{$post->getPrettyId()}" onClick="openCounter({$post->getPrettyId()}, 'reposts'); event.preventDefault(); event.stopPropagation();">{$post->getRepostCount()}</b>)
{/if} {/if}
</a> </a>
@ -123,12 +123,12 @@
{var $liked = $post->hasLikeFrom($thisUser)} {var $liked = $post->hasLikeFrom($thisUser)}
<a href="/wall{$post->getPrettyId()}/like?hash={rawurlencode($csrfToken)}" class="post-like-button" data-liked="{(int) $liked}" data-likes="{$post->getLikesCount()}"> <a href="/wall{$post->getPrettyId()}/like?hash={rawurlencode($csrfToken)}" class="post-like-button" data-liked="{(int) $liked}" data-likes="{$post->getLikesCount()}">
<div class="heart" id="{if $liked}liked{/if}"></div> <div class="heart" id="{if $liked}liked{/if}"></div>
<span class="likeCnt">{if $post->getLikesCount() > 0}{$post->getLikesCount()}{/if}</span> <span class="likeCnt" onClick="openCounter({$post->getPrettyId()}, 'likers'); event.preventDefault(); event.stopPropagation();">{if $post->getLikesCount() > 0}{$post->getLikesCount()}{/if}</span>
</a> </a>
{else} {else}
<a n:if="$post->getLikesCount() > 0" class="post-like-button"> <a n:if="$post->getLikesCount() > 0" class="post-like-button">
<div class="heart"></div> <div class="heart"></div>
<span class="likeCnt">{$post->getLikesCount()}</span> <span class="likeCnt" onClick="openCounter({$post->getPrettyId()}, 'likers'); event.preventDefault(); event.stopPropagation();">{$post->getLikesCount()}</span>
</a> </a>
{/ifset} {/ifset}
</div> </div>

View file

@ -139,6 +139,12 @@ routes:
handler: "Wall->delete" handler: "Wall->delete"
- url: "/wall{num}_{num}/pin" - url: "/wall{num}_{num}/pin"
handler: "Wall->pin" handler: "Wall->pin"
- url: "/wall{num}_{num}/likers"
handler: "Wall->likers"
- url: "/wall{num}_{num}/reposts"
handler: "Wall->reposters"
- url: "/comment{num}/likers"
handler: "Wall->commentLikers"
- url: "/blob_{text}/{?path}.{text}" - url: "/blob_{text}/{?path}.{text}"
handler: "Blob->file" handler: "Blob->file"
placeholders: placeholders:

View file

@ -262,4 +262,45 @@ async function showArticle(note_id) {
u("#articleText").html(`<h1 class="articleView_nameHeading">${note.title}</h1>` + note.html); u("#articleText").html(`<h1 class="articleView_nameHeading">${note.title}</h1>` + note.html);
u("body").removeClass("dimmed"); u("body").removeClass("dimmed");
u("body").addClass("article"); u("body").addClass("article");
} }
function getUserDiv(url, fname, lname, avatar) {
return `
<div class="cl_element" style="width: 20%">
<div class="cl_avatar">
<a href="${url}">
<img class="ava" src="${avatar}"/>
</a>
</div>
<a href="${url}" class="cl_name">
<text class="cl_fname">${fname}</text>
<text class="cl_lname">${lname}</text>
</a>
</div>
`;
}
function openCounter(id, type, is_comment = false) {
$.ajax({
type: "POST",
url: `/${is_comment ? "comment" : "wall"}${id}/${type}`,
success: (response) => {
if (response.success) {
let html = "";
response.payload[1].forEach((user) => {
html += getUserDiv(user.url, user.fname, user.lname, user.avatar);
});
MessageBox(
(type === "likers" ? "Оценили" : "Поделились") + " (" + response.payload[0] + ")",
"<div class='content_list' style='width: inherit;'>" + html + "</div>",
["ОК"],
[Function.noop]
);
} else {
NewNotification(tr("error"), (response?.error ?? "Неизвестная ошибка"), "/assets/packages/static/openvk/img/error.png");
}
}
});
}