add liked content

This commit is contained in:
mrilyew 2025-03-02 20:05:34 +03:00
parent a88e929717
commit df0bb41276
12 changed files with 247 additions and 3 deletions

View file

@ -558,6 +558,7 @@ class User extends RowModel
"poster",
"apps",
"docs",
"fave",
],
])->get($id);
}
@ -1195,6 +1196,7 @@ class User extends RowModel
"poster",
"apps",
"docs",
"fave",
],
])->set($id, (int) $status)->toInteger();

View file

@ -0,0 +1,48 @@
<?php declare(strict_types=1);
namespace openvk\Web\Models\Repositories;
use Chandler\Database\DatabaseConnection;
use openvk\Web\Models\Entities\User;
use Nette\Database\Table\ActiveRow;
class Faves
{
private $context;
private $likes;
function __construct()
{
$this->context = DatabaseConnection::i()->getContext();
$this->likes = $this->context->table("likes");
}
private function fetchLikes(User $user, string $class = 'Post')
{
$fetch = $this->likes->where([
"model" => "openvk\\Web\\Models\\Entities\\".$class,
"origin" => $user->getRealId(),
]);
return $fetch;
}
function fetchLikesSection(User $user, string $class = 'Post', int $page = 1, ?int $perPage = NULL): \Traversable
{
$perPage ??= OPENVK_DEFAULT_PER_PAGE;
$fetch = $this->fetchLikes($user, $class)->page($page, $perPage);
foreach($fetch as $like) {
$className = "openvk\\Web\\Models\\Repositories\\".$class."s";
$repo = new $className;
if(!$repo) {
continue;
}
$entity = $repo->get($like->target);
yield $entity;
}
}
function fetchLikesSectionCount(User $user, string $class = 'Post')
{
return $this->fetchLikes($user, $class)->count();
}
}

View file

@ -373,6 +373,7 @@ final class GroupPresenter extends OpenVKPresenter
public function renderDeleteAvatar(int $id)
{
$this->assertUserLoggedIn();
$this->assertNoCSRF();
$this->willExecuteWriteAction();
$club = $this->clubs->get($id);

View file

@ -9,7 +9,7 @@ use openvk\Web\Util\Sms;
use openvk\Web\Themes\Themepacks;
use openvk\Web\Models\Entities\{Photo, Post, EmailChangeVerification};
use openvk\Web\Models\Entities\Notifications\{CoinsTransferNotification, RatingUpNotification};
use openvk\Web\Models\Repositories\{Users, Clubs, Albums, Videos, Notes, Vouchers, EmailChangeVerifications, Audios};
use openvk\Web\Models\Repositories\{Users, Clubs, Albums, Videos, Notes, Vouchers, EmailChangeVerifications, Audios, Faves};
use openvk\Web\Models\Exceptions\InvalidUserNameException;
use openvk\Web\Util\Validator;
use Chandler\Security\Authenticator;
@ -474,6 +474,7 @@ final class UserPresenter extends OpenVKPresenter
public function renderDeleteAvatar()
{
$this->assertUserLoggedIn();
$this->assertNoCSRF();
$this->willExecuteWriteAction();
$avatar = $this->user->identity->getAvatarPhoto();
@ -666,6 +667,7 @@ final class UserPresenter extends OpenVKPresenter
"menu_standardo" => "poster",
"menu_aplikoj" => "apps",
"menu_doxc" => "docs",
"menu_feva" => "fave",
];
foreach ($settings as $checkbox => $setting) {
$user->setLeftMenuItemStatus($setting, $this->checkbox($checkbox));
@ -942,4 +944,65 @@ final class UserPresenter extends OpenVKPresenter
$this->redirect("/settings");
}
}
function renderFave(): void
{
$this->assertUserLoggedIn();
$page = (int)($this->queryParam("p") ?? 1);
$section = $this->queryParam("section") ?? "posts";
$display_section = "posts";
$data = NULL;
$count = 0;
switch($section) {
default:
$this->notFound();
break;
case 'wall':
case 'post':
case 'posts':
$data = (new Faves)->fetchLikesSection($this->user->identity, 'Post', $page);
$count = (new Faves)->fetchLikesSectionCount($this->user->identity, 'Post');
$display_section = "posts";
break;
case 'comment':
case 'comments':
$data = (new Faves)->fetchLikesSection($this->user->identity, 'Comment', $page);
$count = (new Faves)->fetchLikesSectionCount($this->user->identity, 'Comment');
$display_section = "comments";
break;
case 'photo':
case 'photos':
$data = (new Faves)->fetchLikesSection($this->user->identity, 'Photo', $page);
$count = (new Faves)->fetchLikesSectionCount($this->user->identity, 'Photo');
$display_section = "photos";
break;
case 'video':
case 'videos':
$data = (new Faves)->fetchLikesSection($this->user->identity, 'Video', $page);
$count = (new Faves)->fetchLikesSectionCount($this->user->identity, 'Video');
$display_section = "videos";
break;
}
$this->template->data = iterator_to_array($data);
$this->template->count = $count;
$this->template->page = $page;
$this->template->perPage = OPENVK_DEFAULT_PER_PAGE;
$this->template->section = $display_section;
$this->template->paginatorConf = (object) [
"page" => $page,
"count" => $count,
"amount" => sizeof($this->template->data),
"perPage" => $this->template->perPage,
"atBottom" => false,
"tidy" => true,
'pageCount' => ceil($count / $this->template->perPage),
];
$this->template->extendedPaginatorConf = clone $this->template->paginatorConf;
$this->template->extendedPaginatorConf->space = 11;
$this->template->paginatorConf->atTop = true;
}
}

View file

@ -198,10 +198,11 @@
</a>
<a href="/settings" class="link">{_my_settings}</a>
{if $thisUser->getLeftMenuItemStatus('docs') || $thisUser->getLeftMenuItemStatus('apps')}
{if $thisUser->getLeftMenuItemStatus('docs') || $thisUser->getLeftMenuItemStatus('apps') || $thisUser->getLeftMenuItemStatus('fave')}
<div class="menu_divider"></div>
<a n:if="$thisUser->getLeftMenuItemStatus('apps')" href="/apps?act=installed" class="link">{_apps}</a>
<a n:if="$thisUser->getLeftMenuItemStatus('docs')" href="/docs" class="link">{_my_documents}</a>
<a n:if="$thisUser->getLeftMenuItemStatus('fave')" href="/fave" class="link">{_bookmarks_tab}</a>
{/if}
{var $canAccessAdminPanel = $thisUser->getChandlerUser()->can("access")->model("admin")->whichBelongsTo(NULL)}

View file

@ -0,0 +1,80 @@
{extends "../@layout.xml"}
{block title}{_bookmarks_tab}{/block}
{block header}
{_bookmarks_tab}
{/block}
{block wrap}
<div class="wrap2">
<div class="wrap1">
<div class="page_wrap">
<div class='summaryBar summaryBarFlex padding'>
<div class='summary'>
<b>{tr("faves", $count)} {*tr("showing_x_y", $page, $count)*}</b>
</div>
{include "../components/paginator.xml", conf => $paginatorConf}
</div>
<div class='page_wrap_content' id='search_page'>
<div n:class='page_wrap_content_main, scroll_container, ($section == "photos" && $count > 0) ? album-flex'>
<style>
.scroll_node:first-of-type .comment {
border-top: unset;
padding: 0px;
}
.scroll_node:last-of-type .post {
border-bottom: unset;
}
.content_page_error {
min-height: 400px;
}
</style>
{if $count > 0}
{foreach $data as $dat}
{if $section == "posts"}
<div class="scroll_node">
{include "../components/post.xml", post => $dat, commentSection => true}
</div>
{elseif $section == "comments"}
<div class="scroll_node">
{include "../components/comment.xml", comment => $dat, correctLink => true, no_reply_button => true}
</div>
{elseif $section == "photos"}
<div class="album-photo scroll_node" onclick="OpenMiniature(event, {$dat->getURLBySizeId('larger')}, null, {$dat->getPrettyId()}, null)">
<a href="/photo{$dat->getPrettyId()}">
<img class="album-photo--image" src="{$dat->getURLBySizeId('tinier')}" alt="{$dat->getDescription()}" loading="lazy" />
</a>
</div>
{elseif $section == "videos"}
<div class="scroll_node">
{include "../components/video.xml", video => $dat}
</div>
{/if}
{/foreach}
{else}
{include "../components/content_error.xml", description => tr("faves_".$section."_empty_tip")}
{/if}
</div>
<div class='page_wrap_content_options verticalGrayTabsWrapper'>
<div class="page_wrap_content_options_list verticalGrayTabs with_padding">
<a n:attr="id => $section === 'posts' ? 'used'" href="/fave?section=posts">{_s_posts}</a>
<a n:attr="id => $section === 'comments' ? 'used'" href="/fave?section=comments">{_s_comments}</a>
<a n:attr="id => $section === 'photos' ? 'used'" href="/fave?section=photos">{_s_photos}</a>
<a n:attr="id => $section === 'videos' ? 'used'" href="/fave?section=videos">{_s_videos}</a>
</div>
</div>
</div>
<div n:if='$paginatorConf->pageCount > 1' class='page_content_paginator_bottom'>
{include "../components/paginator.xml", conf => $extendedPaginatorConf}
</div>
</div>
</div>
</div>
</div>
{/block}

View file

@ -696,6 +696,17 @@
<span class="nobold">{_my_documents}</span>
</td>
</tr>
<tr>
<td width="120" valign="top" align="right" align="right">
<input
n:attr="checked => $user->getLeftMenuItemStatus('fave')"
type="checkbox"
name="menu_feva" />
</td>
<td>
<span class="nobold">{_bookmarks_tab}</span>
</td>
</tr>
<tr n:if="sizeof(OPENVK_ROOT_CONF['openvk']['preferences']['menu']['links']) > 0">
<td width="120" valign="top" align="right" align="right">
<input

View file

@ -60,8 +60,9 @@
<a href="javascript:reportComment({$comment->getId()})">{_report}</a>
{/if}
<div style="float: right; font-size: .7rem;">
{var $isLiked = $comment->hasLikeFrom($thisUser)}
<a class="post-like-button" href="/comment{$comment->getId()}/like?hash={rawurlencode($csrfToken)}" data-likes='{$likesCount}' data-id="1_{$comment->getPrettyId()}" data-type='comment'>
<div class="heart" style="{if $comment->hasLikeFrom($thisUser)}opacity: 1;{else}opacity: 0.4;{/if}"></div>
<div class="heart" n:attr="id => $isLiked ? liked" style="{if $isLiked}opacity: 1;{else}opacity: 0.4;{/if}"></div>
<span class="likeCnt">{if $likesCount > 0}{$likesCount}{/if}</span>
</a>
</div>

View file

@ -54,5 +54,6 @@ services:
- openvk\Web\Models\Repositories\BannedLinks
- openvk\Web\Models\Repositories\ChandlerGroups
- openvk\Web\Models\Repositories\Documents
- openvk\Web\Models\Repositories\Faves
- openvk\Web\Presenters\MaintenancePresenter
- openvk\Web\Presenters\NoSpamPresenter

View file

@ -413,6 +413,8 @@ routes:
handler: "InternalAPI->getPostTemplate"
- url: "/tour"
handler: "About->tour"
- url: "/fave"
handler: "User->fave"
- url: "/{?shortCode}"
handler: "UnknownTextRouteStrategy->delegate"
placeholders:

View file

@ -641,6 +641,8 @@
"my_feed" = "My Feed";
"my_feedback" = "My Feedback";
"my_settings" = "My Settings";
"bookmarks" = "Bookmarks";
"bookmarks_tab" = "Saved";
"bug_tracker" = "Bug Tracker";
"menu_settings" = "Settings";
@ -2113,6 +2115,7 @@
"s_apps" = "Applications";
"s_posts" = "Posts";
"s_comments" = "Comments";
"s_photos" = "Photos";
"s_videos" = "Videos";
"s_audios" = "Music";
"s_audios_playlists" = "Playlists";
@ -2385,3 +2388,17 @@
"select_doc" = "Attach document";
"no_documents" = "No documents found";
"go_to_my_documents" = "Go to own documents";
/* Fave */
"faves" = "Bookmarks";
"faves_empty_tip" = "There will be your liked content.";
"faves_posts_empty_tip" = "There will be posts liked by you.";
"faves_comments_empty_tip" = "There will be comments liked by you.";
"faves_photos_empty_tip" = "There will be photos liked by you.";
"faves_videos_empty_tip" = "There will be videos liked by you.";
"faves_zero" = "No bookmarks";
"faves_one" = "One bookmark";
"faves_few" = "$1 bookmarks";
"faves_many" = "$1 bookmarks";
"faves_other" = "$1 bookmarks";

View file

@ -624,6 +624,8 @@
"my_feed" = "Мои Новости";
"my_feedback" = "Мои Ответы";
"my_settings" = "Мои Настройки";
"bookmarks" = "Закладки";
"bookmarks_tab" = "Избранное";
"bug_tracker" = "Баг-трекер";
"menu_settings" = "Настройки";
@ -2008,6 +2010,7 @@
"s_apps" = "Приложения";
"s_posts" = "Записи";
"s_comments" = "Комментарии";
"s_photos" = "Фотографии";
"s_videos" = "Видео";
"s_audios" = "Аудио";
"s_audios_playlists" = "Плейлисты";
@ -2280,3 +2283,17 @@
"select_doc" = "Выбор документа";
"no_documents" = "Документов нет";
"go_to_my_documents" = "Перейти к своим документам";
/* Fave */
"faves" = "Закладки";
"faves_empty_tip" = "Здесь будет отображаться понравившийся Вам контент...";
"faves_posts_empty_tip" = "Здесь будут отображаться понравившиеся Вам записи.";
"faves_comments_empty_tip" = "Здесь будут отображаться понравившиеся Вам комментарии.";
"faves_photos_empty_tip" = "Здесь будут отображаться понравившиеся Вам фотографии.";
"faves_videos_empty_tip" = "Здесь будут отображаться понравившиеся Вам видео.";
"faves_zero" = "Ни одной закладки"; /* на украинском можно как ни одной вподобайки */
"faves_one" = "Одна закладка";
"faves_few" = "$1 закладки";
"faves_many" = "$1 закладок";
"faves_other" = "$1 закладок";