Add pinning feature

This commit is contained in:
Celestora 2021-09-20 12:19:15 +00:00 committed by Celestora
parent fd555d3d61
commit 839594cd70
7 changed files with 112 additions and 3 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 Chandler\Database\DatabaseConnection as DB;
use openvk\Web\Models\Repositories\Clubs; use openvk\Web\Models\Repositories\Clubs;
use openvk\Web\Models\RowModel; use openvk\Web\Models\RowModel;
@ -42,6 +43,11 @@ class Post extends Postable
); );
} }
function isPinned(): bool
{
return (bool) $this->getRecord()->pinned;
}
function isAd(): bool function isAd(): bool
{ {
return (bool) $this->getRecord()->ad; return (bool) $this->getRecord()->ad;
@ -72,6 +78,27 @@ class Post extends Postable
return $this->getRecord()->owner; return $this->getRecord()->owner;
} }
function pin(): void
{
DB::i()
->getContext()
->table("posts")
->where([
"wall" => $this->getTargetWall(),
"pinned" => true,
])
->update(["pinned" => false]);
$this->stateChanges("pinned", true);
$this->save();
}
function unpin(): void
{
$this->stateChanges("pinned", false);
$this->save();
}
function canBeDeletedBy(User $user): bool function canBeDeletedBy(User $user): bool
{ {
if($this->getTargetWall() < 0) if($this->getTargetWall() < 0)

View file

@ -26,9 +26,38 @@ class Posts
return $this->toPost($this->posts->get($id)); return $this->toPost($this->posts->get($id));
} }
function getPinnedPost(int $user): ?Post
{
$post = (clone $this->posts)->where([
"wall" => $user,
"pinned" => true,
"deleted" => false,
])->fetch();
return $this->toPost($post);
}
function getPostsFromUsersWall(int $user, int $page = 1, ?int $perPage = NULL): \Traversable function getPostsFromUsersWall(int $user, int $page = 1, ?int $perPage = NULL): \Traversable
{ {
$sel = $this->posts->where(["wall" => $user, "deleted" => 0])->order("created DESC")->page($page, $perPage ?? OPENVK_DEFAULT_PER_PAGE); $perPage ??= OPENVK_DEFAULT_PER_PAGE;
$offset = $perPage * ($page - 1);
$pinPost = $this->getPinnedPost($user);
if(!is_null($pinPost)) {
if($page === 1) {
$perPage--;
yield $pinPost;
} else {
$offset--;
}
}
$sel = $this->posts->where([
"wall" => $user,
"pinned" => false,
"deleted" => false,
])->order("created DESC")->limit($perPage, $offset);
foreach($sel as $post) foreach($sel as $post)
yield new Post($post); yield new Post($post);

View file

@ -338,4 +338,26 @@ final class WallPresenter extends OpenVKPresenter
$this->redirect($wall < 0 ? "/club".($wall*-1) : "/id".$wall, static::REDIRECT_TEMPORARY); $this->redirect($wall < 0 ? "/club".($wall*-1) : "/id".$wall, static::REDIRECT_TEMPORARY);
exit; exit;
} }
function renderPin(int $wall, int $post_id): void
{
$this->assertUserLoggedIn();
$this->willExecuteWriteAction();
$post = $this->posts->getPostById($wall, $post_id);
if(!$post)
$this->notFound();
if(!$post->canBeDeletedBy($this->user->identity))
$this->flashFail("err", "Ошибка доступа", "Вам нельзя закреплять этот пост.");
if(($this->queryParam("act") ?? "pin") === "pin") {
$post->pin();
} else {
$post->unpin();
}
// TODO localize message based on language and ?act=(un)pin
$this->flashFail("succ", "Операция успешна", "Операция успешна.");
}
} }

View file

@ -17,11 +17,24 @@
</a> </a>
{if $author->isVerified()}<img class="name-checkmark" src="/assets/packages/static/openvk/img/checkmark.png">{/if} {if $author->isVerified()}<img class="name-checkmark" src="/assets/packages/static/openvk/img/checkmark.png">{/if}
{ifset $compact}<br> {ifset $compact}<br>
<a href="/wall{$post->getPrettyId()}" class="date">{$post->getPublicationTime()}</a> <a href="/wall{$post->getPrettyId()}" class="date">
{if $post->isPinned()}
{$post->getPublicationTime()},
{_pinned}
{else}
{$post->getPublicationTime()}
{/if}
</a>
{/ifset} {/ifset}
{if $post->canBeDeletedBy($thisUser) && !($forceNoDeleteLink ?? false) && !isset($compact)} {if $post->canBeDeletedBy($thisUser) && !($forceNoDeleteLink ?? false) && !isset($compact)}
<a class="delete" href="/wall{$post->getPrettyId()}/delete"></a> <a class="delete" href="/wall{$post->getPrettyId()}/delete"></a>
{if $post->isPinned()}
<a class="delete" href="/wall{$post->getPrettyId()}/pin?act=unpin&hash={rawurlencode($csrfToken)}"></a>
{else}
<a class="delete" href="/wall{$post->getPrettyId()}/pin?act=pin&hash={rawurlencode($csrfToken)}"></a>
{/if}
{/if} {/if}
</div> </div>
<div class="post-content" id="{$post->getPrettyId()}"> <div class="post-content" id="{$post->getPrettyId()}">

View file

@ -34,7 +34,14 @@
</a> </a>
{/if} {/if}
<br/> <br/>
<a href="/wall{$post->getPrettyId()}" class="date">{$post->getPublicationTime()}</a> <a href="/wall{$post->getPrettyId()}" class="date">
{if $post->isPinned()}
{$post->getPublicationTime()},
{_pinned}
{else}
{$post->getPublicationTime()}
{/if}
</a>
</div> </div>
<div class="post-content" id="{$post->getPrettyId()}"> <div class="post-content" id="{$post->getPrettyId()}">
<div class="text" id="text{$post->getPrettyId()}"> <div class="text" id="text{$post->getPrettyId()}">
@ -63,6 +70,12 @@
<div n:if="isset($thisUser) &&! ($compact ?? false)" class="post-menu"> <div n:if="isset($thisUser) &&! ($compact ?? false)" class="post-menu">
{if $post->canBeDeletedBy($thisUser) && !($forceNoDeleteLink ?? false)} {if $post->canBeDeletedBy($thisUser) && !($forceNoDeleteLink ?? false)}
<a href="/wall{$post->getPrettyId()}/delete">{_"delete"}</a>&nbsp;|&nbsp; <a href="/wall{$post->getPrettyId()}/delete">{_"delete"}</a>&nbsp;|&nbsp;
{if $post->isPinned()}
<a href="/wall{$post->getPrettyId()}/pin?act=unpin&hash={rawurlencode($csrfToken)}">{_unpin}</a>&nbsp;|&nbsp;
{else}
<a href="/wall{$post->getPrettyId()}/pin?act=pin&hash={rawurlencode($csrfToken)}">{_pin}</a>&nbsp;|&nbsp;
{/if}
{/if} {/if}
{if !($forceNoCommentsLink ?? false)} {if !($forceNoCommentsLink ?? false)}

View file

@ -93,6 +93,8 @@ routes:
handler: "Wall->share" handler: "Wall->share"
- url: "/wall{num}_{num}/delete" - url: "/wall{num}_{num}/delete"
handler: "Wall->delete" handler: "Wall->delete"
- url: "/wall{num}_{num}/pin"
handler: "Wall->pin"
- url: "/blob_{text}/{text}.{text}" - url: "/blob_{text}/{text}.{text}"
handler: "Blob->file" handler: "Blob->file"
- url: "/themepack/{text}/{?version}/{?resClass}/{?any}" - url: "/themepack/{text}/{?version}/{?resClass}/{?any}"

View file

@ -104,6 +104,9 @@
"delete" = "Удалить"; "delete" = "Удалить";
"comments" = "Комментарии"; "comments" = "Комментарии";
"share" = "Поделиться"; "share" = "Поделиться";
"pin" = "Закрепить";
"unpin" = "Открепить";
"pinned" = "закреплено";
"comments_tip" = "Будьте первым, кто оставит комментарий!"; "comments_tip" = "Будьте первым, кто оставит комментарий!";
"your_comment" = "Ваш комментарий"; "your_comment" = "Ваш комментарий";
"comments" = "Комментарии"; "comments" = "Комментарии";