diff --git a/Web/Models/Entities/Post.php b/Web/Models/Entities/Post.php index 9e74c2c0..fd15c8c0 100644 --- a/Web/Models/Entities/Post.php +++ b/Web/Models/Entities/Post.php @@ -1,5 +1,6 @@ getRecord()->pinned; + } + function isAd(): bool { return (bool) $this->getRecord()->ad; @@ -72,6 +78,27 @@ class Post extends Postable 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 { if($this->getTargetWall() < 0) diff --git a/Web/Models/Repositories/Posts.php b/Web/Models/Repositories/Posts.php index 12dc24ee..2c1a7f61 100644 --- a/Web/Models/Repositories/Posts.php +++ b/Web/Models/Repositories/Posts.php @@ -26,9 +26,38 @@ class Posts 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 { - $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) yield new Post($post); diff --git a/Web/Presenters/WallPresenter.php b/Web/Presenters/WallPresenter.php index fc908ad0..e500a25d 100644 --- a/Web/Presenters/WallPresenter.php +++ b/Web/Presenters/WallPresenter.php @@ -338,4 +338,26 @@ final class WallPresenter extends OpenVKPresenter $this->redirect($wall < 0 ? "/club".($wall*-1) : "/id".$wall, static::REDIRECT_TEMPORARY); 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", "Операция успешна", "Операция успешна."); + } } diff --git a/Web/Presenters/templates/components/post/microblogpost.xml b/Web/Presenters/templates/components/post/microblogpost.xml index 6cea48b3..43849a99 100644 --- a/Web/Presenters/templates/components/post/microblogpost.xml +++ b/Web/Presenters/templates/components/post/microblogpost.xml @@ -17,11 +17,24 @@ {if $author->isVerified()}{/if} {ifset $compact}
- {$post->getPublicationTime()} + + {if $post->isPinned()} + {$post->getPublicationTime()}, + {_pinned} + {else} + {$post->getPublicationTime()} + {/if} + {/ifset} {if $post->canBeDeletedBy($thisUser) && !($forceNoDeleteLink ?? false) && !isset($compact)} + + {if $post->isPinned()} + + {else} + + {/if} {/if}
diff --git a/Web/Presenters/templates/components/post/oldpost.xml b/Web/Presenters/templates/components/post/oldpost.xml index e70c0361..a8f67f1e 100644 --- a/Web/Presenters/templates/components/post/oldpost.xml +++ b/Web/Presenters/templates/components/post/oldpost.xml @@ -34,7 +34,14 @@ {/if}
- {$post->getPublicationTime()} + + {if $post->isPinned()} + {$post->getPublicationTime()}, + {_pinned} + {else} + {$post->getPublicationTime()} + {/if} +
@@ -63,6 +70,12 @@
{if $post->canBeDeletedBy($thisUser) && !($forceNoDeleteLink ?? false)} {_"delete"} |  + + {if $post->isPinned()} + {_unpin} |  + {else} + {_pin} |  + {/if} {/if} {if !($forceNoCommentsLink ?? false)} diff --git a/Web/routes.yml b/Web/routes.yml index 31952b24..5298b16f 100644 --- a/Web/routes.yml +++ b/Web/routes.yml @@ -93,6 +93,8 @@ routes: handler: "Wall->share" - url: "/wall{num}_{num}/delete" handler: "Wall->delete" + - url: "/wall{num}_{num}/pin" + handler: "Wall->pin" - url: "/blob_{text}/{text}.{text}" handler: "Blob->file" - url: "/themepack/{text}/{?version}/{?resClass}/{?any}" diff --git a/locales/ru.strings b/locales/ru.strings index 5cc4fce9..a28af638 100644 --- a/locales/ru.strings +++ b/locales/ru.strings @@ -104,6 +104,9 @@ "delete" = "Удалить"; "comments" = "Комментарии"; "share" = "Поделиться"; +"pin" = "Закрепить"; +"unpin" = "Открепить"; +"pinned" = "закреплено"; "comments_tip" = "Будьте первым, кто оставит комментарий!"; "your_comment" = "Ваш комментарий"; "comments" = "Комментарии";