Wall: Add an initial closing of the posts

This commit is contained in:
Ilya Prokopenko 2022-08-12 15:11:08 +07:00
parent bbdfb04c01
commit 2949ed8afb
No known key found for this signature in database
GPG key ID: 7736BBBB05F14A56
17 changed files with 146 additions and 19 deletions

View file

@ -416,6 +416,9 @@ final class Wall extends VKAPIRequestHandler
$comments = (new CommentsRepo)->getCommentsByTarget($post, $offset+1, $count, $sort == "desc" ? "DESC" : "ASC"); $comments = (new CommentsRepo)->getCommentsByTarget($post, $offset+1, $count, $sort == "desc" ? "DESC" : "ASC");
if(!$post->getPrivacyPermission('comments.read', $this->user->identity))
$this->fail(15, "Access denied");
$items = []; $items = [];
$profiles = []; $profiles = [];
@ -519,6 +522,9 @@ final class Wall extends VKAPIRequestHandler
$post = (new PostsRepo)->getPostById($owner_id, $post_id); $post = (new PostsRepo)->getPostById($owner_id, $post_id);
if(!$post || $post->isDeleted()) $this->fail(100, "One of the parameters specified was missing or invalid"); if(!$post || $post->isDeleted()) $this->fail(100, "One of the parameters specified was missing or invalid");
if($post->isClosed() || !$post->getPrivacyPermission('comments.write', $this->user->identity))
$this->fail(15, "Access denied");
if($post->getTargetWall() < 0) if($post->getTargetWall() < 0)
$club = (new ClubsRepo)->get(abs($post->getTargetWall())); $club = (new ClubsRepo)->get(abs($post->getTargetWall()));
@ -555,7 +561,7 @@ final class Wall extends VKAPIRequestHandler
$comment = (new CommentsRepo)->get($comment_id); $comment = (new CommentsRepo)->get($comment_id);
if(!$comment) $this->fail(100, "One of the parameters specified was missing or invalid");; if(!$comment) $this->fail(100, "One of the parameters specified was missing or invalid");;
if(!$comment->canBeDeletedBy($this->user)) if(!$comment->canBeDeletedBy($this->user))
$this->fail(7, "Access denied"); $this->fail(15, "Access denied");
$comment->delete(); $comment->delete();

View file

@ -95,6 +95,11 @@ class Post extends Postable
return (bool) $this->getRecord()->nsfw; return (bool) $this->getRecord()->nsfw;
} }
function isClosed(): bool
{
return (bool) $this->getRecord()->closed;
}
function isDeleted(): bool function isDeleted(): bool
{ {
return (bool) $this->getRecord()->deleted; return (bool) $this->getRecord()->deleted;
@ -126,6 +131,27 @@ class Post extends Postable
$this->save(); $this->save();
} }
function close(): void
{
DB::i()
->getContext()
->table("posts")
->where([
"wall" => $this->getTargetWall(),
"closed" => true,
])
->update(["closed" => false]);
$this->stateChanges("closed", true);
$this->save();
}
function open(): void
{
$this->stateChanges("closed", false);
$this->save();
}
function canBePinnedBy(User $user): bool function canBePinnedBy(User $user): bool
{ {
if($this->getTargetWall() < 0) if($this->getTargetWall() < 0)
@ -139,6 +165,11 @@ class Post extends Postable
return $this->getOwnerPost() === $user->getId() || $this->canBePinnedBy($user); return $this->getOwnerPost() === $user->getId() || $this->canBePinnedBy($user);
} }
function canBeClosedBy(User $user): bool
{
return $this->canBeDeletedBy($user);
}
function setContent(string $content): void function setContent(string $content): void
{ {
if(ctype_space($content)) if(ctype_space($content))

View file

@ -427,6 +427,8 @@ class User extends RowModel
"friends.add", "friends.add",
"wall.write", "wall.write",
"messages.write", "messages.write",
"comments.read",
"comments.write",
], ],
])->get($id); ])->get($id);
} }
@ -869,6 +871,8 @@ class User extends RowModel
"friends.add", "friends.add",
"wall.write", "wall.write",
"messages.write", "messages.write",
"comments.read",
"comments.write",
], ],
])->set($id, $status)->toInteger()); ])->set($id, $status)->toInteger());
} }

View file

@ -1,6 +1,6 @@
<?php declare(strict_types=1); <?php declare(strict_types=1);
namespace openvk\Web\Presenters; namespace openvk\Web\Presenters;
use openvk\Web\Models\Entities\{Comment, Photo, Video, User, Topic, Post}; use openvk\Web\Models\Entities\{Comment, Photo, Video, User, Topic, Post, Wall};
use openvk\Web\Models\Entities\Notifications\CommentNotification; use openvk\Web\Models\Entities\Notifications\CommentNotification;
use openvk\Web\Models\Repositories\{Comments, Clubs}; use openvk\Web\Models\Repositories\{Comments, Clubs};
@ -42,6 +42,9 @@ final class CommentPresenter extends OpenVKPresenter
if($entity instanceof Topic && $entity->isClosed()) if($entity instanceof Topic && $entity->isClosed())
$this->notFound(); $this->notFound();
if($entity instanceof Post && !$entity->getOwner()->getPrivacyPermission('comments.write', $this->user->identity))
exit(header("HTTP/1.1 403 Forbidden"));
if($entity instanceof Post && $entity->getTargetWall() < 0) if($entity instanceof Post && $entity->getTargetWall() < 0)
$club = (new Clubs)->get(abs($entity->getTargetWall())); $club = (new Clubs)->get(abs($entity->getTargetWall()));
else if($entity instanceof Topic) else if($entity instanceof Topic)

View file

@ -386,6 +386,8 @@ final class UserPresenter extends OpenVKPresenter
"friends.add", "friends.add",
"wall.write", "wall.write",
"messages.write", "messages.write",
"comments.read",
"comments.write",
]; ];
foreach($settings as $setting) { foreach($settings as $setting) {
$input = $this->postParam(str_replace(".", "_", $setting)); $input = $this->postParam(str_replace(".", "_", $setting));

View file

@ -409,4 +409,26 @@ 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"));
} }
function renderOpen(int $wall, int $post_id): void
{
$this->assertUserLoggedIn();
$this->willExecuteWriteAction();
$post = $this->posts->getPostById($wall, $post_id);
if(!$post)
$this->notFound();
if(!$post->canBeClosedBy($this->user->identity))
$this->flashFail("err", tr("not_enough_permissions"), tr("not_enough_permissions_comment"));
if(($this->queryParam("act") ?? "open") === "open") {
$post->open();
} else {
$post->close();
}
# TODO localize message based on language and ?act=(open|close)
$this->flashFail("succ", tr("information_-1"), tr("changes_saved_comment"));
}
} }

View file

@ -77,6 +77,7 @@
page => $cPage, page => $cPage,
model => "notes", model => "notes",
parent => $note, parent => $note,
showTitle => false} showTitle => false,
wallOwner => $author}
</div> </div>
{/block} {/block}

View file

@ -356,6 +356,31 @@
</select> </select>
</td> </td>
</tr> </tr>
<tr>
<td width="120" valign="top">
<span class="nobold">{_privacy_setting_see_comments}</span>
</td>
<td>
<select name="comments.read" style="width: 164px;">
<option value="3" {if $user->getPrivacySetting('comments.read') == 3}selected{/if}>{_privacy_value_anybody_dative}</option>
<option value="2" {if $user->getPrivacySetting('comments.read') == 2}selected{/if}>{_privacy_value_users}</option>
<option value="1" {if $user->getPrivacySetting('comments.read') == 1}selected{/if}>{_privacy_value_friends_dative}</option>
<option value="0" {if $user->getPrivacySetting('comments.read') == 0}selected{/if}>{_privacy_value_only_me_dative}</option>
</select>
</td>
</tr>
<tr>
<td width="120" valign="top">
<span class="nobold">{_privacy_setting_write_comments}</span>
</td>
<td>
<select name="comments.write", style="width: 164px;">
<option value="2" {if $user->getPrivacySetting('comments.write') == 2}selected{/if}>{_privacy_value_anybody}</option>
<option value="1" {if $user->getPrivacySetting('comments.write') == 1}selected{/if}>{_privacy_value_friends}</option>
<option value="0" {if $user->getPrivacySetting('comments.write') == 0}selected{/if}>{_privacy_value_nobody}</option>
</select>
</td>
</tr>
<tr> <tr>
<td> <td>

View file

@ -14,22 +14,39 @@
{/block} {/block}
{block content} {block content}
{include "../components/post.xml", post => $post, forceNoCommentsLink => TRUE, forceNoDeleteLink => TRUE} {include "../components/post.xml", post => $post, forceNoCommentsLink => TRUE, forceNoPinLink => TRUE, forceNoDeleteLink => TRUE}
<hr/> <hr/>
<div style="float: left; min-height: 100px; width: 68%;"> <div n:if="$wallOwner->getPrivacyPermission('comments.read', $thisUser)" style="float: left; min-height: 100px; width: 68%;">
{include "../components/comments.xml", {include "../components/comments.xml",
comments => $comments, comments => $comments,
count => $cCount, count => $cCount,
page => $cPage, page => $cPage,
model => "posts", model => "posts",
parent => $post } parent => $post,
readOnly => (!$wallOwner->getPrivacyPermission('comments.write', $thisUser) XOR $post->isClosed()) }
</div> </div>
<div style="float: left; min-height: 100px; width: 32%;"> <div style="float: right; min-height: 100px; width: 32%;">
<h4>{_actions}</h4> <h4>{_actions}</h4>
{if isset($thisUser)} {if isset($thisUser)}
{var $canPin = $post->canBePinnedBy($thisUser)}
{var $canClose = $post->canBeClosedBy($thisUser)}
{var $canDelete = $post->canBeDeletedBy($thisUser)} {var $canDelete = $post->canBeDeletedBy($thisUser)}
{/if} {/if}
{if $canPin}
{if $post->isPinned()}
<a class="profile_link" style="display:block;width:96%;" href="/wall{$post->getPrettyId()}/pin?act=unpin&hash={rawurlencode($csrfToken)}">{_unpin}</a>
{else}
<a class="profile_link" style="display:block;width:96%;" href="/wall{$post->getPrettyId()}/pin?act=pin&hash={rawurlencode($csrfToken)}">{_pin}</a>
{/if}
{/if}
{if $canClose}
{if $post->isClosed()}
<a class="profile_link" style="display:block;width:96%;" href="/wall{$post->getPrettyId()}/open?act=open&hash={rawurlencode($csrfToken)}">{_enable_comments}</a>
{else}
<a class="profile_link" style="display:block;width:96%;" href="/wall{$post->getPrettyId()}/open?act=close&hash={rawurlencode($csrfToken)}">{_disable_comments}</a>
{/if}
{/if}
<a n:if="$canDelete ?? false" class="profile_link" style="display:block;width:96%;" href="/wall{$post->getPrettyId()}/delete">{_delete}</a> <a n:if="$canDelete ?? false" class="profile_link" style="display:block;width:96%;" href="/wall{$post->getPrettyId()}/delete">{_delete}</a>
</div> </div>
{/block} {/block}

View file

@ -1,6 +1,7 @@
{var $author = $comment->getOwner()} {var $author = $comment->getOwner()}
{var $Club = openvk\Web\Models\Entities\Club::class} {var $Club = openvk\Web\Models\Entities\Club::class}
{var $postId = $comment->getTarget() instanceof \openvk\Web\Models\Entities\Post ? $comment->getTarget()->getId() : NULL} {var $postId = $comment->getTarget() instanceof \openvk\Web\Models\Entities\Post ? $comment->getTarget()->getId() : NULL}
{var $post = $comment->getTarget() instanceof \openvk\Web\Models\Entities\Post ? (new \openvk\Web\Models\Repositories\Posts)->get($postId) : NULL}
<a name="cid={$comment->getId()}"></a> <a name="cid={$comment->getId()}"></a>
<table border="0" style="font-size: 11px;" class="post comment" id="_comment{$comment->getId()}" data-comment-id="{$comment->getId()}" data-owner-id="{$author->getId()}" data-from-group="{$comment->getOwner() instanceof $Club}" n:attr="data-post-id => $postId"> <table border="0" style="font-size: 11px;" class="post comment" id="_comment{$comment->getId()}" data-comment-id="{$comment->getId()}" data-owner-id="{$author->getId()}" data-from-group="{$comment->getOwner() instanceof $Club}" n:attr="data-post-id => $postId">
@ -29,11 +30,13 @@
</div> </div>
</div> </div>
<div n:if="isset($thisUser) &&! ($compact ?? false)" class="post-menu"> <div n:if="isset($thisUser) &&! ($compact ?? false)" class="post-menu">
<a href="#_comment{$comment->getId()}" class="date">{$comment->getPublicationTime()}</a>&nbsp;| <a href="#_comment{$comment->getId()}" class="date">{$comment->getPublicationTime()}</a>
{if $comment->canBeDeletedBy($thisUser)} {if $comment->canBeDeletedBy($thisUser)}
<a href="/comment{$comment->getId()}/delete">{_delete}</a>&nbsp;| |&nbsp;<a href="/comment{$comment->getId()}/delete">{_delete}</a>
{/if}
{if $post->getOwner()->getPrivacyPermission('comments.write', $thisUser) && !$post->isClosed()}
|&nbsp;<a class="comment-reply">{_reply}</a>
{/if} {/if}
<a class="comment-reply">{_reply}</a>
<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>

View file

@ -16,7 +16,9 @@
{include "paginator.xml", conf => (object) ["page" => $page, "count" => $count, "amount" => sizeof($comments), "perPage" => 10]} {include "paginator.xml", conf => (object) ["page" => $page, "count" => $count, "amount" => sizeof($comments), "perPage" => 10]}
</div> </div>
{else} {else}
{if $wallOwner->getPrivacyPermission('comments.write', $thisUser)}
{_comments_tip} {_comments_tip}
{/if}
{/if} {/if}
{script "js/al_comments.js"} {script "js/al_comments.js"}

View file

@ -88,7 +88,7 @@
{if isset($thisUser)} {if isset($thisUser)}
&nbsp; &nbsp;
<a n:if="!($forceNoCommentsLink ?? false) && $commentsCount == 0" href="javascript:expand_comment_textarea({$commentTextAreaId})">{_comment}</a> <a n:if="!($forceNoCommentsLink ?? false) && $author->getPrivacyPermission('comments.read', $thisUser) && $commentsCount == 0" href="javascript:expand_comment_textarea({$commentTextAreaId})">{_comment}</a>
<div class="like_wrap"> <div class="like_wrap">
<a n:if="!($forceNoShareLink ?? false)" class="post-share-button" href="javascript:repostPost('{$post->getPrettyId()}', '{rawurlencode($csrfToken)}')"> <a n:if="!($forceNoShareLink ?? false)" class="post-share-button" href="javascript:repostPost('{$post->getPrettyId()}', '{rawurlencode($csrfToken)}')">
@ -106,12 +106,12 @@
</div> </div>
{/if} {/if}
</div> </div>
<div n:if="!($forceNoCommentsLink ?? false) && $commentSection == true && $compact == false" class="post-menu-s"> <div n:if="!($forceNoCommentsLink ?? false) && $author->getPrivacyPermission('comments.read', $thisUser) && $commentSection == true && $compact == false" class="post-menu-s">
<a n:if="$commentsCount > 3" href="/wall{$post->getPrettyId()}" class="expand_button">{_view_other_comments}</a> <a n:if="$commentsCount > 3" href="/wall{$post->getPrettyId()}" class="expand_button">{_view_other_comments}</a>
{foreach $comments as $comment} {foreach $comments as $comment}
{include "../comment.xml", comment => $comment, $compact => true} {include "../comment.xml", comment => $comment, $compact => true}
{/foreach} {/foreach}
<div n:ifset="$thisUser" id="commentTextArea{$commentTextAreaId}" n:attr="style => ($commentsCount == 0 ? 'display: none;')" class="commentsTextFieldWrap"> <div n:ifset="$thisUser" n:if="$author->getPrivacyPermission('comments.write', $thisUser) && !$post->isClosed()" id="commentTextArea{$commentTextAreaId}" n:attr="style => ($commentsCount == 0 ? 'display: none;')" class="commentsTextFieldWrap">
{var $commentsURL = "/al_comments/create/posts/" . $post->getId()} {var $commentsURL = "/al_comments/create/posts/" . $post->getId()}
{var $club = is_null($club) ? ($post->getTargetWall() < 0 ? (new openvk\Web\Models\Repositories\Clubs)->get(abs($post->getTargetWall())) : NULL) : $club} {var $club = is_null($club) ? ($post->getTargetWall() < 0 ? (new openvk\Web\Models\Repositories\Clubs)->get(abs($post->getTargetWall())) : NULL) : $club}
{include "../textArea.xml", route => $commentsURL, postOpts => false, graffiti => (bool) ovkGetQuirk("comments.allow-graffiti"), post => $post, club => $club} {include "../textArea.xml", route => $commentsURL, postOpts => false, graffiti => (bool) ovkGetQuirk("comments.allow-graffiti"), post => $post, club => $club}

View file

@ -83,14 +83,14 @@
&nbsp;|&nbsp; &nbsp;|&nbsp;
{/if} {/if}
<a n:if="!($forceNoCommentsLink ?? false)" href="/wall{$post->getPrettyId()}#comments"> <a n:if="!($forceNoCommentsLink ?? false) && $author->getPrivacyPermission('comments.read', $thisUser)" href="/wall{$post->getPrettyId()}#comments">
{_comments} {_comments}
{if $post->getCommentsCount() > 0} {if $post->getCommentsCount() > 0}
(<b>{$post->getCommentsCount()}</b>) (<b>{$post->getCommentsCount()}</b>)
{/if} {/if}
</a> </a>
{if !($forceNoCommentsLink ?? false) && !($forceNoShareLink ?? false)} {if (!($forceNoCommentsLink ?? false) && $author->getPrivacyPermission('comments.read', $thisUser)) && !($forceNoShareLink ?? false)}
&nbsp;|&nbsp; &nbsp;|&nbsp;
{/if} {/if}

View file

@ -129,6 +129,8 @@ 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}/open"
handler: "Wall->open"
- url: "/blob_{text}/{?path}.{text}" - url: "/blob_{text}/{?path}.{text}"
handler: "Blob->file" handler: "Blob->file"
placeholders: placeholders:

View file

@ -0,0 +1 @@
ALTER TABLE `posts` ADD `closed` tinyint(1) NOT NULL DEFAULT '0' AFTER `anonymous`;

View file

@ -165,6 +165,8 @@
"pinned" = "pinned"; "pinned" = "pinned";
"comments_tip" = "Be first, who leaves a comment at this post!"; "comments_tip" = "Be first, who leaves a comment at this post!";
"your_comment" = "Your comment"; "your_comment" = "Your comment";
"enable_comments" = "Enable comments";
"disable_comments" = "Disable comments";
"shown" = "Shown"; "shown" = "Shown";
"x_out_of" = "$1 of"; "x_out_of" = "$1 of";
"wall_zero" = "no posts"; "wall_zero" = "no posts";
@ -452,6 +454,8 @@
"privacy_setting_add_to_friends" = "Who can add me to friends"; "privacy_setting_add_to_friends" = "Who can add me to friends";
"privacy_setting_write_wall" = "Who can publish post on my wall"; "privacy_setting_write_wall" = "Who can publish post on my wall";
"privacy_setting_write_messages" = "Who can write messages to me"; "privacy_setting_write_messages" = "Who can write messages to me";
"privacy_setting_see_comments" = "Who can see comments on my posts";
"privacy_setting_write_comments" = "Who can write comment on my posts";
"privacy_value_anybody" = "Anybody"; "privacy_value_anybody" = "Anybody";
"privacy_value_anybody_dative" = "Anybody"; "privacy_value_anybody_dative" = "Anybody";
"privacy_value_users" = "OpenVK users"; "privacy_value_users" = "OpenVK users";

View file

@ -171,6 +171,8 @@
"pinned" = "закреплено"; "pinned" = "закреплено";
"comments_tip" = "Будьте первым, кто оставит комментарий!"; "comments_tip" = "Будьте первым, кто оставит комментарий!";
"your_comment" = "Ваш комментарий"; "your_comment" = "Ваш комментарий";
"enable_comments" = "Включить комментарии";
"disable_comments" = "Выключить комментарии";
"shown" = "Показано"; "shown" = "Показано";
"x_out_of" = "$1 из"; "x_out_of" = "$1 из";
"wall_zero" = "нет записей"; "wall_zero" = "нет записей";
@ -488,6 +490,8 @@
"privacy_setting_add_to_friends" = "Кто может называть меня другом"; "privacy_setting_add_to_friends" = "Кто может называть меня другом";
"privacy_setting_write_wall" = "Кто может писать у меня на стене"; "privacy_setting_write_wall" = "Кто может писать у меня на стене";
"privacy_setting_write_messages" = "Кто может писать мне сообщения"; "privacy_setting_write_messages" = "Кто может писать мне сообщения";
"privacy_setting_see_comments" = "Кому видно комментарии к моим записям";
"privacy_setting_write_comments" = "Кто может комментировать мои записи";
"privacy_value_anybody" = "Все желающие"; "privacy_value_anybody" = "Все желающие";
"privacy_value_anybody_dative" = "Всем желающим"; "privacy_value_anybody_dative" = "Всем желающим";
"privacy_value_users" = "Пользователям OpenVK"; "privacy_value_users" = "Пользователям OpenVK";