mirror of
https://github.com/openvk/openvk
synced 2024-12-22 16:42:32 +03:00
Groups: Wall: add suggestions (#935)
* Wall: add early suggestions * Fix br * Fix empty posts * fck * Add offset for api * Add notifications of new suggestion posts * Fix mentions in suggested posts * 🤮🤢 * Change regex Теперь оно удаляет все теги а не только <br> * Add da koroche pohuy * Эдд апи метходс Методы нестандартные немного * Pon * Add skloneniyia * newlines * int * Update loaders and add avtopodgruzka postov * Update JOERGK.strings * Blin * Remove repeated code, fix loaded buttons on chr... ...ome and fix getting suggested posts via API.Wall.getPost * Fix polls * Fihes Теперь уведомление о принятии поста не приходит, если вы приняли свой же пост Пофикшен баг перехода в предложку Добавлен старый вид постов в предложке Теперь счётчик постов в предложке у прикреплённой группы обновляется при принятии или отклонении поста Убрано всплывающее уведомление об отклонении поста (оно раздражает) Теперь если вы посмотрели все посты на одной странице (не на первой) и на ней не осталось постов, вас телепортирует на предыдущую страницу * Remove ability to delete your accepted psto * oi blin * Improvements 2 api * g * openvk.uk Возможно, приведение кода к кодстайлу (удаление скобочек то есть) * aiaks * al_wall.js -> al_suggestions.js * 👨💻 Add 👨💻 fading 👨💻 * Add "owner's posts' and "other's posts" Давайте рофлить👨💻👨💻👨💻 * planshet openvk Add tabs for post view, add signer's object in wall get and add person icon in microblog * Simplefai ze kod * PHP 8 FIX WATAFAK * Add indesk
This commit is contained in:
parent
3112372d01
commit
4699fcbeb9
35 changed files with 1195 additions and 57 deletions
|
@ -22,7 +22,10 @@ class Wall implements Handler
|
|||
{
|
||||
$post = $this->posts->get($id);
|
||||
if(!$post || $post->isDeleted())
|
||||
$reject("No post with id=$id");
|
||||
$reject(53, "No post with id=$id");
|
||||
|
||||
if($post->getSuggestionType() != 0)
|
||||
$reject(25, "Can't get suggested post");
|
||||
|
||||
$res = (object) [];
|
||||
$res->id = $post->getId();
|
||||
|
@ -129,7 +132,7 @@ class Wall implements Handler
|
|||
];
|
||||
|
||||
foreach($videos as $video) {
|
||||
$res = json_decode(json_encode($video->toVkApiStruct()), true);
|
||||
$res = json_decode(json_encode($video->toVkApiStruct($this->user)), true);
|
||||
$res["video"]["author_name"] = $video->getOwner()->getCanonicalName();
|
||||
|
||||
$arr["items"][] = $res;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
namespace openvk\VKAPI\Handlers;
|
||||
use openvk\Web\Models\Repositories\Clubs as ClubsRepo;
|
||||
use openvk\Web\Models\Repositories\Users as UsersRepo;
|
||||
use openvk\Web\Models\Repositories\Posts as PostsRepo;
|
||||
use openvk\Web\Models\Entities\Club;
|
||||
|
||||
final class Groups extends VKAPIRequestHandler
|
||||
|
@ -80,6 +81,19 @@ final class Groups extends VKAPIRequestHandler
|
|||
break;
|
||||
case "members_count":
|
||||
$rClubs[$i]->members_count = $usr->getFollowersCount();
|
||||
break;
|
||||
case "can_suggest":
|
||||
$rClubs[$i]->can_suggest = !$usr->canBeModifiedBy($this->getUser()) && $usr->getWallType() == 2;
|
||||
break;
|
||||
# unstandard feild
|
||||
case "suggested_count":
|
||||
if($usr->getWallType() != 2) {
|
||||
$rClubs[$i]->suggested_count = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
$rClubs[$i]->suggested_count = $usr->getSuggestedPostsCount($this->getUser());
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -188,6 +202,18 @@ final class Groups extends VKAPIRequestHandler
|
|||
case "description":
|
||||
$response[$i]->description = $clb->getDescription();
|
||||
break;
|
||||
case "can_suggest":
|
||||
$response[$i]->can_suggest = !$clb->canBeModifiedBy($this->getUser()) && $clb->getWallType() == 2;
|
||||
break;
|
||||
# unstandard feild
|
||||
case "suggested_count":
|
||||
if($clb->getWallType() != 2) {
|
||||
$response[$i]->suggested_count = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
$response[$i]->suggested_count = $clb->getSuggestedPostsCount($this->getUser());
|
||||
break;
|
||||
case "contacts":
|
||||
$contacts;
|
||||
$contactTmp = $clb->getManagers(1, true);
|
||||
|
@ -288,7 +314,7 @@ final class Groups extends VKAPIRequestHandler
|
|||
string $description = NULL,
|
||||
string $screen_name = NULL,
|
||||
string $website = NULL,
|
||||
int $wall = NULL,
|
||||
int $wall = -1,
|
||||
int $topics = NULL,
|
||||
int $adminlist = NULL,
|
||||
int $topicsAboveWall = NULL,
|
||||
|
@ -308,17 +334,26 @@ final class Groups extends VKAPIRequestHandler
|
|||
!empty($description) ? $club->setAbout($description) : NULL;
|
||||
!empty($screen_name) ? $club->setShortcode($screen_name) : NULL;
|
||||
!empty($website) ? $club->setWebsite((!parse_url($website, PHP_URL_SCHEME) ? "https://" : "") . $website) : NULL;
|
||||
!empty($wall) ? $club->setWall($wall) : NULL;
|
||||
|
||||
try {
|
||||
$wall != -1 ? $club->setWall($wall) : NULL;
|
||||
} catch(\Exception $e) {
|
||||
$this->fail(50, "Invalid wall value");
|
||||
}
|
||||
|
||||
!empty($topics) ? $club->setEveryone_Can_Create_Topics($topics) : NULL;
|
||||
!empty($adminlist) ? $club->setAdministrators_List_Display($adminlist) : NULL;
|
||||
!empty($topicsAboveWall) ? $club->setDisplay_Topics_Above_Wall($topicsAboveWall) : NULL;
|
||||
!empty($hideFromGlobalFeed) ? $club->setHide_From_Global_Feed($hideFromGlobalFeed) : NULL;
|
||||
|
||||
in_array($audio, [0, 1]) ? $club->setEveryone_can_upload_audios($audio) : NULL;
|
||||
|
||||
try {
|
||||
$club->save();
|
||||
} catch(\TypeError $e) {
|
||||
$this->fail(8, "Nothing changed");
|
||||
$this->fail(15, "Nothing changed");
|
||||
} catch(\Exception $e) {
|
||||
$this->fail(18, "An unknown error occurred: maybe you set an incorrect value?");
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -472,7 +507,7 @@ final class Groups extends VKAPIRequestHandler
|
|||
"title" => $club->getName(),
|
||||
"description" => $club->getDescription() != NULL ? $club->getDescription() : "",
|
||||
"address" => $club->getShortcode(),
|
||||
"wall" => $club->canPost() == true ? 1 : 0,
|
||||
"wall" => $club->getWallType(), # отличается от вкшных но да ладно
|
||||
"photos" => 1,
|
||||
"video" => 0,
|
||||
"audio" => $club->isEveryoneCanUploadAudios() ? 1 : 0,
|
||||
|
|
|
@ -51,7 +51,7 @@ final class Newsfeed extends VKAPIRequestHandler
|
|||
{
|
||||
$this->requireUser();
|
||||
|
||||
$queryBase = "FROM `posts` LEFT JOIN `groups` ON GREATEST(`posts`.`wall`, 0) = 0 AND `groups`.`id` = ABS(`posts`.`wall`) WHERE (`groups`.`hide_from_global_feed` = 0 OR `groups`.`name` IS NULL) AND `posts`.`deleted` = 0";
|
||||
$queryBase = "FROM `posts` LEFT JOIN `groups` ON GREATEST(`posts`.`wall`, 0) = 0 AND `groups`.`id` = ABS(`posts`.`wall`) WHERE (`groups`.`hide_from_global_feed` = 0 OR `groups`.`name` IS NULL) AND `posts`.`deleted` = 0 AND `posts`.`suggested` = 0";
|
||||
|
||||
if($this->getUser()->getNsfwTolerance() === User::NSFW_INTOLERANT)
|
||||
$queryBase .= " AND `nsfw` = 0";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
use openvk\Web\Models\Entities\User;
|
||||
use openvk\Web\Models\Entities\Notifications\{WallPostNotification, RepostNotification, CommentNotification};
|
||||
use openvk\Web\Models\Entities\Notifications\{PostAcceptedNotification, WallPostNotification, NewSuggestedPostsNotification, RepostNotification, CommentNotification};
|
||||
use openvk\Web\Models\Repositories\Users as UsersRepo;
|
||||
use openvk\Web\Models\Entities\Club;
|
||||
use openvk\Web\Models\Repositories\Clubs as ClubsRepo;
|
||||
|
@ -20,7 +20,7 @@ use openvk\Web\Models\Repositories\Audios as AudiosRepo;
|
|||
|
||||
final class Wall extends VKAPIRequestHandler
|
||||
{
|
||||
function get(int $owner_id, string $domain = "", int $offset = 0, int $count = 30, int $extended = 0): object
|
||||
function get(int $owner_id, string $domain = "", int $offset = 0, int $count = 30, int $extended = 0, string $filter = "all"): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
|
@ -29,7 +29,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
$items = [];
|
||||
$profiles = [];
|
||||
$groups = [];
|
||||
$cnt = $posts->getPostCountOnUserWall($owner_id);
|
||||
$cnt = 0;
|
||||
|
||||
if ($owner_id > 0)
|
||||
$wallOnwer = (new UsersRepo)->get($owner_id);
|
||||
|
@ -43,7 +43,47 @@ final class Wall extends VKAPIRequestHandler
|
|||
if(!$wallOnwer)
|
||||
$this->fail(15, "Access denied: wall is disabled"); // Don't search for logic here pls
|
||||
|
||||
foreach($posts->getPostsFromUsersWall($owner_id, 1, $count, $offset) as $post) {
|
||||
$iteratorv;
|
||||
|
||||
switch($filter) {
|
||||
case "all":
|
||||
$iteratorv = $posts->getPostsFromUsersWall($owner_id, 1, $count, $offset);
|
||||
$cnt = $posts->getPostCountOnUserWall($owner_id);
|
||||
break;
|
||||
case "owner":
|
||||
$iteratorv = $posts->getOwnersPostsFromWall($owner_id, 1, $count, $offset);
|
||||
$cnt = $posts->getOwnersCountOnUserWall($owner_id);
|
||||
break;
|
||||
case "others":
|
||||
$iteratorv = $posts->getOthersPostsFromWall($owner_id, 1, $count, $offset);
|
||||
$cnt = $posts->getOthersCountOnUserWall($owner_id);
|
||||
break;
|
||||
case "postponed":
|
||||
$this->fail(42, "Postponed posts are not implemented.");
|
||||
break;
|
||||
case "suggests":
|
||||
if($owner_id < 0) {
|
||||
if($wallOnwer->getWallType() != 2)
|
||||
$this->fail(125, "Group's wall type is open or closed");
|
||||
|
||||
if($wallOnwer->canBeModifiedBy($this->getUser())) {
|
||||
$iteratorv = $posts->getSuggestedPosts($owner_id * -1, 1, $count, $offset);
|
||||
$cnt = $posts->getSuggestedPostsCount($owner_id * -1);
|
||||
} else {
|
||||
$iteratorv = $posts->getSuggestedPostsByUser($owner_id * -1, $this->getUser()->getId(), 1, $count, $offset);
|
||||
$cnt = $posts->getSuggestedPostsCountByUser($owner_id * -1, $this->getUser()->getId());
|
||||
}
|
||||
} else {
|
||||
$this->fail(528, "Suggested posts avaiable only at groups");
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
$this->fail(254, "Invalid filter");
|
||||
break;
|
||||
}
|
||||
|
||||
foreach($iteratorv as $post) {
|
||||
$from_id = get_class($post->getOwner()) == "openvk\Web\Models\Entities\Club" ? $post->getOwner()->getId() * (-1) : $post->getOwner()->getId();
|
||||
|
||||
$attachments = [];
|
||||
|
@ -118,12 +158,23 @@ final class Wall extends VKAPIRequestHandler
|
|||
];
|
||||
}
|
||||
|
||||
$postType = "post";
|
||||
$signerId = NULL;
|
||||
if($post->getSuggestionType() != 0)
|
||||
$postType = "suggest";
|
||||
|
||||
|
||||
if($post->isSigned()) {
|
||||
$actualAuthor = $post->getOwner(false);
|
||||
$signerId = $actualAuthor->getId();
|
||||
}
|
||||
|
||||
$items[] = (object)[
|
||||
"id" => $post->getVirtualId(),
|
||||
"from_id" => $from_id,
|
||||
"owner_id" => $post->getTargetWall(),
|
||||
"date" => $post->getPublicationTime()->timestamp(),
|
||||
"post_type" => "post",
|
||||
"post_type" => $postType,
|
||||
"text" => $post->getText(false),
|
||||
"copy_history" => $repost,
|
||||
"can_edit" => $post->canBeEditedBy($this->getUser()),
|
||||
|
@ -135,6 +186,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
"is_explicit" => $post->isExplicit(),
|
||||
"attachments" => $attachments,
|
||||
"post_source" => $post_source,
|
||||
"signer_id" => $signerId,
|
||||
"comments" => (object)[
|
||||
"count" => $post->getCommentsCount(),
|
||||
"can_post" => 1
|
||||
|
@ -156,6 +208,9 @@ final class Wall extends VKAPIRequestHandler
|
|||
else
|
||||
$groups[] = $from_id * -1;
|
||||
|
||||
if($post->isSigned())
|
||||
$profiles[] = $post->getOwner(false)->getId();
|
||||
|
||||
$attachments = NULL; # free attachments so it will not clone everythingg
|
||||
}
|
||||
|
||||
|
@ -298,12 +353,24 @@ final class Wall extends VKAPIRequestHandler
|
|||
];
|
||||
}
|
||||
|
||||
# TODO: $post->getVkApiType()
|
||||
$postType = "post";
|
||||
$signerId = NULL;
|
||||
if($post->getSuggestionType() != 0)
|
||||
$postType = "suggest";
|
||||
|
||||
|
||||
if($post->isSigned()) {
|
||||
$actualAuthor = $post->getOwner(false);
|
||||
$signerId = $actualAuthor->getId();
|
||||
}
|
||||
|
||||
$items[] = (object)[
|
||||
"id" => $post->getVirtualId(),
|
||||
"from_id" => $from_id,
|
||||
"owner_id" => $post->getTargetWall(),
|
||||
"date" => $post->getPublicationTime()->timestamp(),
|
||||
"post_type" => "post",
|
||||
"post_type" => $postType,
|
||||
"text" => $post->getText(false),
|
||||
"copy_history" => $repost,
|
||||
"can_edit" => $post->canBeEditedBy($this->getUser()),
|
||||
|
@ -314,6 +381,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
"is_pinned" => $post->isPinned(),
|
||||
"is_explicit" => $post->isExplicit(),
|
||||
"post_source" => $post_source,
|
||||
"signer_id" => $signerId,
|
||||
"attachments" => $attachments,
|
||||
"comments" => (object)[
|
||||
"count" => $post->getCommentsCount(),
|
||||
|
@ -336,6 +404,9 @@ final class Wall extends VKAPIRequestHandler
|
|||
else
|
||||
$groups[] = $from_id * -1;
|
||||
|
||||
if($post->isSigned())
|
||||
$profiles[] = $post->getOwner(false)->getId();
|
||||
|
||||
$attachments = NULL; # free attachments so it will not clone everything
|
||||
$repost = NULL; # same
|
||||
}
|
||||
|
@ -391,7 +462,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
];
|
||||
}
|
||||
|
||||
function post(string $owner_id, string $message = "", int $from_group = 0, int $signed = 0, string $attachments = ""): object
|
||||
function post(string $owner_id, string $message = "", int $from_group = 0, int $signed = 0, string $attachments = "", int $post_id = 0): object
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
@ -412,6 +483,46 @@ final class Wall extends VKAPIRequestHandler
|
|||
|
||||
if($canPost == false) $this->fail(15, "Access denied");
|
||||
|
||||
if($post_id > 0) {
|
||||
if($owner_id > 0)
|
||||
$this->fail(62, "Suggested posts available only at groups");
|
||||
|
||||
$post = (new PostsRepo)->getPostById($owner_id, $post_id, true);
|
||||
|
||||
if(!$post || $post->isDeleted())
|
||||
$this->fail(32, "Invald post");
|
||||
|
||||
if($post->getSuggestionType() == 0)
|
||||
$this->fail(20, "Post is not suggested");
|
||||
|
||||
if($post->getSuggestionType() == 2)
|
||||
$this->fail(16, "Post is declined");
|
||||
|
||||
if(!$post->canBePinnedBy($this->getUser()))
|
||||
$this->fail(51, "Access denied");
|
||||
|
||||
$author = $post->getOwner();
|
||||
$flags = 0;
|
||||
$flags |= 0b10000000;
|
||||
|
||||
if($signed == 1)
|
||||
$flags |= 0b01000000;
|
||||
|
||||
$post->setSuggested(0);
|
||||
$post->setCreated(time());
|
||||
$post->setFlags($flags);
|
||||
|
||||
if(!empty($message) && iconv_strlen($message) > 0)
|
||||
$post->setContent($message);
|
||||
|
||||
$post->save();
|
||||
|
||||
if($author->getId() != $this->getUser()->getId())
|
||||
(new PostAcceptedNotification($author, $post, $post->getWallOwner()))->emit();
|
||||
|
||||
return (object)["post_id" => $post->getVirtualId()];
|
||||
}
|
||||
|
||||
$anon = OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["anonymousPosting"]["enable"];
|
||||
if($wallOwner instanceof Club && $from_group == 1 && $signed != 1 && $anon) {
|
||||
$manager = $wallOwner->getManager($this->getUser());
|
||||
|
@ -440,6 +551,10 @@ final class Wall extends VKAPIRequestHandler
|
|||
$post->setContent($message);
|
||||
$post->setFlags($flags);
|
||||
$post->setApi_Source_Name($this->getPlatform());
|
||||
|
||||
if($owner_id < 0 && !$wallOwner->canBeModifiedBy($this->getUser()) && $wallOwner->getWallType() == 2)
|
||||
$post->setSuggested(1);
|
||||
|
||||
$post->save();
|
||||
} catch(\LogicException $ex) {
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid");
|
||||
|
@ -528,6 +643,22 @@ final class Wall extends VKAPIRequestHandler
|
|||
if($wall > 0 && $wall !== $this->user->identity->getId())
|
||||
(new WallPostNotification($wallOwner, $post, $this->user->identity))->emit();
|
||||
|
||||
if($owner_id < 0 && !$wallOwner->canBeModifiedBy($this->getUser()) && $wallOwner->getWallType() == 2) {
|
||||
$suggsCount = (new PostsRepo)->getSuggestedPostsCount($wallOwner->getId());
|
||||
|
||||
if($suggsCount % 10 == 0) {
|
||||
$managers = $wallOwner->getManagers();
|
||||
$owner = $wallOwner->getOwner();
|
||||
(new NewSuggestedPostsNotification($owner, $wallOwner))->emit();
|
||||
|
||||
foreach($managers as $manager) {
|
||||
(new NewSuggestedPostsNotification($manager->getUser(), $wallOwner))->emit();
|
||||
}
|
||||
}
|
||||
|
||||
return (object)["post_id" => "on_view"];
|
||||
}
|
||||
|
||||
return (object)["post_id" => $post->getVirtualId()];
|
||||
}
|
||||
|
||||
|
@ -831,6 +962,30 @@ final class Wall extends VKAPIRequestHandler
|
|||
return 1;
|
||||
}
|
||||
|
||||
function delete(int $owner_id, int $post_id)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$post = (new PostsRepo)->getPostById($owner_id, $post_id, true);
|
||||
if(!$post || $post->isDeleted())
|
||||
$this->fail(583, "Invalid post");
|
||||
|
||||
$wallOwner = $post->getWallOwner();
|
||||
|
||||
if($post->getTargetWall() < 0 && !$post->getWallOwner()->canBeModifiedBy($this->getUser()) && $post->getWallOwner()->getWallType() != 1 && $post->getSuggestionType() == 0)
|
||||
$this->fail(12, "Access denied: you can't delete your accepted post.");
|
||||
|
||||
if($post->getOwnerPost() == $this->getUser()->getId() || $post->getTargetWall() == $this->getUser()->getId() || $owner_id < 0 && $wallOwner->canBeModifiedBy($this->getUser())) {
|
||||
$post->unwire();
|
||||
$post->delete();
|
||||
|
||||
return 1;
|
||||
} else {
|
||||
$this->fail(15, "Access denied");
|
||||
}
|
||||
}
|
||||
|
||||
function edit(int $owner_id, int $post_id, string $message = "", string $attachments = "") {
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
|
|
@ -3,7 +3,7 @@ namespace openvk\Web\Models\Entities;
|
|||
use openvk\Web\Util\DateTime;
|
||||
use openvk\Web\Models\RowModel;
|
||||
use openvk\Web\Models\Entities\{User, Manager};
|
||||
use openvk\Web\Models\Repositories\{Users, Clubs, Albums, Managers};
|
||||
use openvk\Web\Models\Repositories\{Users, Clubs, Albums, Managers, Posts};
|
||||
use Nette\Database\Table\{ActiveRow, GroupedSelection};
|
||||
use Chandler\Database\DatabaseConnection as DB;
|
||||
use Chandler\Security\User as ChandlerUser;
|
||||
|
@ -24,6 +24,10 @@ class Club extends RowModel
|
|||
const SUBSCRIBED = 1;
|
||||
const REQUEST_SENT = 2;
|
||||
|
||||
const WALL_CLOSED = 0;
|
||||
const WALL_OPEN = 1;
|
||||
const WALL_LIMITED = 2;
|
||||
|
||||
function getId(): int
|
||||
{
|
||||
return $this->getRecord()->id;
|
||||
|
@ -46,6 +50,11 @@ class Club extends RowModel
|
|||
return is_null($avPhoto) ? "$serverUrl/assets/packages/static/openvk/img/camera_200.png" : $avPhoto->getURLBySizeId($size);
|
||||
}
|
||||
|
||||
function getWallType(): int
|
||||
{
|
||||
return $this->getRecord()->wall;
|
||||
}
|
||||
|
||||
function getAvatarLink(): string
|
||||
{
|
||||
$avPhoto = $this->getAvatarPhoto();
|
||||
|
@ -183,6 +192,14 @@ class Club extends RowModel
|
|||
return true;
|
||||
}
|
||||
|
||||
function setWall(int $type)
|
||||
{
|
||||
if($type > 2 || $type < 0)
|
||||
throw new \LogicException("Invalid wall");
|
||||
|
||||
$this->stateChanges("wall", $type);
|
||||
}
|
||||
|
||||
function isSubscriptionAccepted(User $user): bool
|
||||
{
|
||||
return !is_null($this->getRecord()->related("subscriptions.follower")->where([
|
||||
|
@ -292,6 +309,21 @@ class Club extends RowModel
|
|||
}
|
||||
}
|
||||
|
||||
function getSuggestedPostsCount(User $user = NULL)
|
||||
{
|
||||
$count = 0;
|
||||
|
||||
if(is_null($user))
|
||||
return NULL;
|
||||
|
||||
if($this->canBeModifiedBy($user))
|
||||
$count = (new Posts)->getSuggestedPostsCount($this->getId());
|
||||
else
|
||||
$count = (new Posts)->getSuggestedPostsCountByUser($this->getId(), $user->getId());
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
function getManagers(int $page = 1, bool $ignoreHidden = false): \Traversable
|
||||
{
|
||||
$rels = $this->getRecord()->related("group_coadmins.club")->page($page, 6);
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\Web\Models\Entities\Notifications;
|
||||
use openvk\Web\Models\Entities\{User, Club};
|
||||
|
||||
final class NewSuggestedPostsNotification extends Notification
|
||||
{
|
||||
protected $actionCode = 7;
|
||||
|
||||
function __construct(User $owner, Club $group)
|
||||
{
|
||||
parent::__construct($owner, $owner, $group, time(), "");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\Web\Models\Entities\Notifications;
|
||||
use openvk\Web\Models\Entities\{User, Club, Post};
|
||||
|
||||
final class PostAcceptedNotification extends Notification
|
||||
{
|
||||
protected $actionCode = 6;
|
||||
|
||||
function __construct(User $author, Post $post, Club $group)
|
||||
{
|
||||
parent::__construct($author, $post, $group, time(), "");
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ use openvk\Web\Models\Exceptions\TooMuchOptionsException;
|
|||
use openvk\Web\Util\DateTime;
|
||||
use \UnexpectedValueException;
|
||||
use Nette\InvalidStateException;
|
||||
use openvk\Web\Models\Repositories\Users;
|
||||
use openvk\Web\Models\Repositories\{Users, Posts};
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
use openvk\Web\Models\Exceptions\PollLockedException;
|
||||
use openvk\Web\Models\Exceptions\AlreadyVotedException;
|
||||
|
@ -165,7 +165,7 @@ class Poll extends Attachable
|
|||
|
||||
function canVote(User $user): bool
|
||||
{
|
||||
return !$this->hasEnded() && !$this->hasVoted($user);
|
||||
return !$this->hasEnded() && !$this->hasVoted($user) && !is_null($this->getAttachedPost()) && $this->getAttachedPost()->getSuggestionType() == 0;
|
||||
}
|
||||
|
||||
function vote(User $user, array $optionIds): void
|
||||
|
@ -292,4 +292,17 @@ class Poll extends Attachable
|
|||
]);
|
||||
}
|
||||
}
|
||||
|
||||
function getAttachedPost()
|
||||
{
|
||||
$post = DatabaseConnection::i()->getContext()->table("attachments")
|
||||
->where(
|
||||
["attachable_type" => static::class,
|
||||
"attachable_id" => $this->getId()])->fetch();
|
||||
|
||||
if(!is_null($post->target_id))
|
||||
return (new Posts)->get($post->target_id);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -207,6 +207,9 @@ class Post extends Postable
|
|||
|
||||
function canBeDeletedBy(User $user): bool
|
||||
{
|
||||
if($this->getTargetWall() < 0 && !$this->getWallOwner()->canBeModifiedBy($user) && $this->getWallOwner()->getWallType() != 1 && $this->getSuggestionType() == 0)
|
||||
return false;
|
||||
|
||||
return $this->getOwnerPost() === $user->getId() || $this->canBePinnedBy($user);
|
||||
}
|
||||
|
||||
|
@ -246,6 +249,11 @@ class Post extends Postable
|
|||
$this->save();
|
||||
}
|
||||
|
||||
function getSuggestionType()
|
||||
{
|
||||
return $this->getRecord()->suggested;
|
||||
}
|
||||
|
||||
function toNotifApiStruct()
|
||||
{
|
||||
$res = (object)[];
|
||||
|
@ -273,6 +281,12 @@ class Post extends Postable
|
|||
|
||||
if($this->getTargetWall() > 0)
|
||||
return $this->getPublicationTime()->timestamp() + WEEK > time() && $user->getId() == $this->getOwner(false)->getId();
|
||||
else {
|
||||
if($this->isPostedOnBehalfOfGroup())
|
||||
return $this->getWallOwner()->canBeModifiedBy($user);
|
||||
else
|
||||
return $user->getId() == $this->getOwner(false)->getId();
|
||||
}
|
||||
|
||||
return $user->getId() == $this->getOwner(false)->getId();
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ abstract class Postable extends Attachable
|
|||
{
|
||||
$oid = (int) $this->getRecord()->owner;
|
||||
if(!$real && $this->isAnonymous())
|
||||
$oid = OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["anonymousPosting"]["account"];
|
||||
$oid = (int) OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["anonymousPosting"]["account"];
|
||||
|
||||
$oid = abs($oid);
|
||||
if($oid > 0)
|
||||
|
|
|
@ -61,12 +61,57 @@ class Posts
|
|||
"wall" => $user,
|
||||
"pinned" => false,
|
||||
"deleted" => false,
|
||||
"suggested" => 0,
|
||||
])->order("created DESC")->limit($perPage, $offset);
|
||||
|
||||
foreach($sel as $post)
|
||||
yield new Post($post);
|
||||
}
|
||||
|
||||
function getOwnersPostsFromWall(int $user, int $page = 1, ?int $perPage = NULL, ?int $offset = NULL): \Traversable
|
||||
{
|
||||
$perPage ??= OPENVK_DEFAULT_PER_PAGE;
|
||||
$offset ??= $perPage * ($page - 1);
|
||||
|
||||
$sel = $this->posts->where([
|
||||
"wall" => $user,
|
||||
"deleted" => false,
|
||||
"suggested" => 0,
|
||||
]);
|
||||
|
||||
if($user > 0)
|
||||
$sel->where("owner", $user);
|
||||
else
|
||||
$sel->where("flags !=", 0);
|
||||
|
||||
$sel->order("created DESC")->limit($perPage, $offset);
|
||||
|
||||
foreach($sel as $post)
|
||||
yield new Post($post);
|
||||
}
|
||||
|
||||
function getOthersPostsFromWall(int $user, int $page = 1, ?int $perPage = NULL, ?int $offset = NULL): \Traversable
|
||||
{
|
||||
$perPage ??= OPENVK_DEFAULT_PER_PAGE;
|
||||
$offset ??= $perPage * ($page - 1);
|
||||
|
||||
$sel = $this->posts->where([
|
||||
"wall" => $user,
|
||||
"deleted" => false,
|
||||
"suggested" => 0,
|
||||
]);
|
||||
|
||||
if($user > 0)
|
||||
$sel->where("owner !=", $user);
|
||||
else
|
||||
$sel->where("flags", 0);
|
||||
|
||||
$sel->order("created DESC")->limit($perPage, $offset);
|
||||
|
||||
foreach($sel as $post)
|
||||
yield new Post($post);
|
||||
}
|
||||
|
||||
function getPostsByHashtag(string $hashtag, int $page = 1, ?int $perPage = NULL): \Traversable
|
||||
{
|
||||
$hashtag = "#$hashtag";
|
||||
|
@ -74,6 +119,7 @@ class Posts
|
|||
->where("MATCH (content) AGAINST (? IN BOOLEAN MODE)", "+$hashtag")
|
||||
->where("deleted", 0)
|
||||
->order("created DESC")
|
||||
->where("suggested", 0)
|
||||
->page($page, $perPage ?? OPENVK_DEFAULT_PER_PAGE);
|
||||
|
||||
foreach($sel as $post)
|
||||
|
@ -85,14 +131,22 @@ class Posts
|
|||
$hashtag = "#$hashtag";
|
||||
$sel = $this->posts
|
||||
->where("content LIKE ?", "%$hashtag%")
|
||||
->where("deleted", 0);
|
||||
->where("deleted", 0)
|
||||
->where("suggested", 0);
|
||||
|
||||
return sizeof($sel);
|
||||
}
|
||||
|
||||
function getPostById(int $wall, int $post): ?Post
|
||||
function getPostById(int $wall, int $post, bool $forceSuggestion = false): ?Post
|
||||
{
|
||||
$post = $this->posts->where(['wall' => $wall, 'virtual_id' => $post])->fetch();
|
||||
$post = $this->posts->where(['wall' => $wall, 'virtual_id' => $post]);
|
||||
|
||||
if(!$forceSuggestion) {
|
||||
$post->where("suggested", 0);
|
||||
}
|
||||
|
||||
$post = $post->fetch();
|
||||
|
||||
if(!is_null($post))
|
||||
return new Post($post);
|
||||
else
|
||||
|
@ -112,7 +166,7 @@ class Posts
|
|||
else
|
||||
$paramValue != NULL ? $notNullParams+=["$paramName" => "$paramValue"] : NULL;
|
||||
|
||||
$result = $this->posts->where("content LIKE ?", $query)->where("deleted", 0);
|
||||
$result = $this->posts->where("content LIKE ?", $query)->where("deleted", 0)->where("suggested", 0);
|
||||
$nnparamsCount = sizeof($notNullParams);
|
||||
|
||||
if($nnparamsCount > 0) {
|
||||
|
@ -134,7 +188,66 @@ class Posts
|
|||
|
||||
function getPostCountOnUserWall(int $user): int
|
||||
{
|
||||
return sizeof($this->posts->where(["wall" => $user, "deleted" => 0]));
|
||||
return sizeof($this->posts->where(["wall" => $user, "deleted" => 0, "suggested" => 0]));
|
||||
}
|
||||
|
||||
function getOwnersCountOnUserWall(int $user): int
|
||||
{
|
||||
if($user > 0)
|
||||
return sizeof($this->posts->where(["wall" => $user, "deleted" => 0, "owner" => $user]));
|
||||
else
|
||||
return sizeof($this->posts->where(["wall" => $user, "deleted" => 0, "suggested" => 0])->where("flags !=", 0));
|
||||
}
|
||||
|
||||
function getOthersCountOnUserWall(int $user): int
|
||||
{
|
||||
if($user > 0)
|
||||
return sizeof($this->posts->where(["wall" => $user, "deleted" => 0])->where("owner !=", $user));
|
||||
else
|
||||
return sizeof($this->posts->where(["wall" => $user, "deleted" => 0, "suggested" => 0])->where("flags", 0));
|
||||
}
|
||||
|
||||
function getSuggestedPosts(int $club, int $page = 1, ?int $perPage = NULL, ?int $offset = NULL): \Traversable
|
||||
{
|
||||
$perPage ??= OPENVK_DEFAULT_PER_PAGE;
|
||||
$offset ??= $perPage * ($page - 1);
|
||||
|
||||
$sel = $this->posts
|
||||
->where("deleted", 0)
|
||||
->where("wall", $club * -1)
|
||||
->order("created DESC")
|
||||
->where("suggested", 1)
|
||||
->limit($perPage, $offset);
|
||||
|
||||
foreach($sel as $post)
|
||||
yield new Post($post);
|
||||
}
|
||||
|
||||
function getSuggestedPostsCount(int $club)
|
||||
{
|
||||
return sizeof($this->posts->where(["wall" => $club * -1, "deleted" => 0, "suggested" => 1]));
|
||||
}
|
||||
|
||||
function getSuggestedPostsByUser(int $club, int $user, int $page = 1, ?int $perPage = NULL, ?int $offset = NULL): \Traversable
|
||||
{
|
||||
$perPage ??= OPENVK_DEFAULT_PER_PAGE;
|
||||
$offset ??= $perPage * ($page - 1);
|
||||
|
||||
$sel = $this->posts
|
||||
->where("deleted", 0)
|
||||
->where("wall", $club * -1)
|
||||
->where("owner", $user)
|
||||
->order("created DESC")
|
||||
->where("suggested", 1)
|
||||
->limit($perPage, $offset);
|
||||
|
||||
foreach($sel as $post)
|
||||
yield new Post($post);
|
||||
}
|
||||
|
||||
function getSuggestedPostsCountByUser(int $club, int $user): int
|
||||
{
|
||||
return sizeof($this->posts->where(["wall" => $club * -1, "deleted" => 0, "suggested" => 1, "owner" => $user]));
|
||||
}
|
||||
|
||||
function getCount(): int
|
||||
|
|
|
@ -3,7 +3,7 @@ namespace openvk\Web\Presenters;
|
|||
use openvk\Web\Models\Entities\{Club, Photo, Post};
|
||||
use Nette\InvalidStateException;
|
||||
use openvk\Web\Models\Entities\Notifications\ClubModeratorNotification;
|
||||
use openvk\Web\Models\Repositories\{Clubs, Users, Albums, Managers, Topics, Audios};
|
||||
use openvk\Web\Models\Repositories\{Clubs, Users, Albums, Managers, Topics, Audios, Posts};
|
||||
use Chandler\Security\Authenticator;
|
||||
|
||||
final class GroupPresenter extends OpenVKPresenter
|
||||
|
@ -35,6 +35,13 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
$this->template->audiosCount = (new Audios)->getClubCollectionSize($club);
|
||||
}
|
||||
|
||||
if(!is_null($this->user->identity) && $club->getWallType() == 2) {
|
||||
if(!$club->canBeModifiedBy($this->user->identity))
|
||||
$this->template->suggestedPostsCountByUser = (new Posts)->getSuggestedPostsCountByUser($club->getId(), $this->user->id);
|
||||
else
|
||||
$this->template->suggestedPostsCountByEveryone = (new Posts)->getSuggestedPostsCount($club->getId());
|
||||
}
|
||||
|
||||
$this->template->club = $club;
|
||||
}
|
||||
}
|
||||
|
@ -216,7 +223,12 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
|
||||
$club->setName((empty($this->postParam("name")) || mb_strlen(trim($this->postParam("name"))) === 0) ? $club->getName() : $this->postParam("name"));
|
||||
$club->setAbout(empty($this->postParam("about")) ? NULL : $this->postParam("about"));
|
||||
$club->setWall(empty($this->postParam("wall")) ? 0 : 1);
|
||||
try {
|
||||
$club->setWall(empty($this->postParam("wall")) ? 0 : (int)$this->postParam("wall"));
|
||||
} catch(\Exception $e) {
|
||||
$this->flashFail("err", tr("error"), tr("error_invalid_wall_value"));
|
||||
}
|
||||
|
||||
$club->setAdministrators_List_Display(empty($this->postParam("administrators_list_display")) ? 0 : $this->postParam("administrators_list_display"));
|
||||
$club->setEveryone_Can_Create_Topics(empty($this->postParam("everyone_can_create_topics")) ? 0 : 1);
|
||||
$club->setDisplay_Topics_Above_Wall(empty($this->postParam("display_topics_above_wall")) ? 0 : 1);
|
||||
|
@ -414,4 +426,37 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
|
||||
$this->flashFail("succ", tr("information_-1"), tr("group_owner_setted", $newOwner->getCanonicalName(), $club->getName()));
|
||||
}
|
||||
|
||||
function renderSuggested(int $id): void
|
||||
{
|
||||
$this->assertUserLoggedIn();
|
||||
|
||||
$club = $this->clubs->get($id);
|
||||
if(!$club)
|
||||
$this->notFound();
|
||||
else
|
||||
$this->template->club = $club;
|
||||
|
||||
if($club->getWallType() == 0) {
|
||||
$this->flash("err", tr("error_suggestions"), tr("error_suggestions_closed"));
|
||||
$this->redirect("/club".$club->getId());
|
||||
}
|
||||
|
||||
if($club->getWallType() == 1) {
|
||||
$this->flash("err", tr("error_suggestions"), tr("error_suggestions_open"));
|
||||
$this->redirect("/club".$club->getId());
|
||||
}
|
||||
|
||||
if(!$club->canBeModifiedBy($this->user->identity)) {
|
||||
$this->template->posts = iterator_to_array((new Posts)->getSuggestedPostsByUser($club->getId(), $this->user->id, (int) ($this->queryParam("p") ?? 1)));
|
||||
$this->template->count = (new Posts)->getSuggestedPostsCountByUser($club->getId(), $this->user->id);
|
||||
$this->template->type = "my";
|
||||
} else {
|
||||
$this->template->posts = iterator_to_array((new Posts)->getSuggestedPosts($club->getId(), (int) ($this->queryParam("p") ?? 1)));
|
||||
$this->template->count = (new Posts)->getSuggestedPostsCount($club->getId());
|
||||
$this->template->type = "everyone";
|
||||
}
|
||||
|
||||
$this->template->page = (int) ($this->queryParam("p") ?? 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ final class InternalAPIPresenter extends OpenVKPresenter
|
|||
}
|
||||
|
||||
if($this->postParam("parentType", false) == "post") {
|
||||
$post = (new Posts)->getPostById($owner_id, $post_id);
|
||||
$post = (new Posts)->getPostById($owner_id, $post_id, true);
|
||||
} else {
|
||||
$post = (new Comments)->get($post_id);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
namespace openvk\Web\Presenters;
|
||||
use openvk\Web\Models\Exceptions\TooMuchOptionsException;
|
||||
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, PostAcceptedNotification, NewSuggestedPostsNotification};
|
||||
use openvk\Web\Models\Repositories\{Posts, Users, Clubs, Albums, Notes, Videos, Comments, Photos, Audios};
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
use Nette\InvalidStateException as ISE;
|
||||
|
@ -67,10 +67,31 @@ final class WallPresenter extends OpenVKPresenter
|
|||
if($user < 0)
|
||||
$this->template->club = $owner;
|
||||
|
||||
$iterator = NULL;
|
||||
$count = 0;
|
||||
$type = $this->queryParam("type") ?? "all";
|
||||
|
||||
switch($type) {
|
||||
default:
|
||||
case "all":
|
||||
$iterator = $this->posts->getPostsFromUsersWall($user, (int) ($_GET["p"] ?? 1));
|
||||
$count = $this->posts->getPostCountOnUserWall($user);
|
||||
break;
|
||||
case "owners":
|
||||
$iterator = $this->posts->getOwnersPostsFromWall($user, (int) ($_GET["p"] ?? 1));
|
||||
$count = $this->posts->getOwnersCountOnUserWall($user);
|
||||
break;
|
||||
case "others":
|
||||
$iterator = $this->posts->getOthersPostsFromWall($user, (int) ($_GET["p"] ?? 1));
|
||||
$count = $this->posts->getOthersCountOnUserWall($user);
|
||||
break;
|
||||
}
|
||||
|
||||
$this->template->owner = $user;
|
||||
$this->template->canPost = $canPost;
|
||||
$this->template->count = $this->posts->getPostCountOnUserWall($user);
|
||||
$this->template->posts = iterator_to_array($this->posts->getPostsFromUsersWall($user, (int) ($_GET["p"] ?? 1)));
|
||||
$this->template->count = $count;
|
||||
$this->template->type = $type;
|
||||
$this->template->posts = iterator_to_array($iterator);
|
||||
$this->template->paginatorConf = (object) [
|
||||
"count" => $this->template->count,
|
||||
"page" => (int) ($_GET["p"] ?? 1),
|
||||
|
@ -150,6 +171,7 @@ final class WallPresenter extends OpenVKPresenter
|
|||
->select("id")
|
||||
->where("wall IN (?)", $ids)
|
||||
->where("deleted", 0)
|
||||
->where("suggested", 0)
|
||||
->order("created DESC");
|
||||
$this->template->paginatorConf = (object) [
|
||||
"count" => sizeof($posts),
|
||||
|
@ -169,7 +191,7 @@ final class WallPresenter extends OpenVKPresenter
|
|||
$page = (int) ($_GET["p"] ?? 1);
|
||||
$pPage = min((int) ($_GET["posts"] ?? OPENVK_DEFAULT_PER_PAGE), 50);
|
||||
|
||||
$queryBase = "FROM `posts` LEFT JOIN `groups` ON GREATEST(`posts`.`wall`, 0) = 0 AND `groups`.`id` = ABS(`posts`.`wall`) WHERE (`groups`.`hide_from_global_feed` = 0 OR `groups`.`name` IS NULL) AND `posts`.`deleted` = 0";
|
||||
$queryBase = "FROM `posts` LEFT JOIN `groups` ON GREATEST(`posts`.`wall`, 0) = 0 AND `groups`.`id` = ABS(`posts`.`wall`) WHERE (`groups`.`hide_from_global_feed` = 0 OR `groups`.`name` IS NULL) AND `posts`.`deleted` = 0 AND `posts`.`suggested` = 0";
|
||||
|
||||
if($this->user->identity->getNsfwTolerance() === User::NSFW_INTOLERANT)
|
||||
$queryBase .= " AND `nsfw` = 0";
|
||||
|
@ -343,6 +365,10 @@ final class WallPresenter extends OpenVKPresenter
|
|||
$post->setAnonymous($anon);
|
||||
$post->setFlags($flags);
|
||||
$post->setNsfw($this->postParam("nsfw") === "on");
|
||||
|
||||
if($wall < 0 && !$wallOwner->canBeModifiedBy($this->user->identity) && $wallOwner->getWallType() == 2)
|
||||
$post->setSuggested(1);
|
||||
|
||||
$post->save();
|
||||
} catch (\LengthException $ex) {
|
||||
$this->flashFail("err", tr("failed_to_publish_post"), tr("post_is_too_big"));
|
||||
|
@ -371,13 +397,33 @@ final class WallPresenter extends OpenVKPresenter
|
|||
if($wall > 0)
|
||||
$excludeMentions[] = $wall;
|
||||
|
||||
if($wall < 0 && !$wallOwner->canBeModifiedBy($this->user->identity) && $wallOwner->getWallType() == 2) {
|
||||
# Чтобы не было упоминаний из предложки
|
||||
} else {
|
||||
$mentions = iterator_to_array($post->resolveMentions($excludeMentions));
|
||||
|
||||
foreach($mentions as $mentionee)
|
||||
if($mentionee instanceof User)
|
||||
(new MentionNotification($mentionee, $post, $post->getOwner(), strip_tags($post->getText())))->emit();
|
||||
}
|
||||
|
||||
if($wall < 0 && !$wallOwner->canBeModifiedBy($this->user->identity) && $wallOwner->getWallType() == 2) {
|
||||
$suggsCount = $this->posts->getSuggestedPostsCount($wallOwner->getId());
|
||||
|
||||
if($suggsCount % 10 == 0) {
|
||||
$managers = $wallOwner->getManagers();
|
||||
$owner = $wallOwner->getOwner();
|
||||
(new NewSuggestedPostsNotification($owner, $wallOwner))->emit();
|
||||
|
||||
foreach($managers as $manager)
|
||||
(new NewSuggestedPostsNotification($manager->getUser(), $wallOwner))->emit();
|
||||
}
|
||||
|
||||
$this->redirect("/club".$wallOwner->getId()."/suggested");
|
||||
} else {
|
||||
$this->redirect($wallOwner->getURL());
|
||||
}
|
||||
}
|
||||
|
||||
function renderPost(int $wall, int $post_id): void
|
||||
{
|
||||
|
@ -487,7 +533,7 @@ final class WallPresenter extends OpenVKPresenter
|
|||
$this->assertUserLoggedIn();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$post = $this->posts->getPostById($wall, $post_id);
|
||||
$post = $this->posts->getPostById($wall, $post_id, true);
|
||||
if(!$post)
|
||||
$this->notFound();
|
||||
$user = $this->user->id;
|
||||
|
@ -502,6 +548,9 @@ final class WallPresenter extends OpenVKPresenter
|
|||
else $canBeDeletedByOtherUser = false;
|
||||
|
||||
if(!is_null($user)) {
|
||||
if($post->getTargetWall() < 0 && !$post->getWallOwner()->canBeModifiedBy($this->user->identity) && $post->getWallOwner()->getWallType() != 1 && $post->getSuggestionType() == 0)
|
||||
$this->flashFail("err", tr("failed_to_delete_post"), tr("error_deleting_suggested"));
|
||||
|
||||
if($post->getOwnerPost() == $user || $post->getTargetWall() == $user || $canBeDeletedByOtherUser) {
|
||||
$post->unwire();
|
||||
$post->delete();
|
||||
|
@ -597,4 +646,93 @@ final class WallPresenter extends OpenVKPresenter
|
|||
"avatar" => $post->getOwner()->getAvatarUrl()
|
||||
]]);
|
||||
}
|
||||
|
||||
function renderAccept() {
|
||||
$this->assertUserLoggedIn();
|
||||
$this->willExecuteWriteAction(true);
|
||||
|
||||
if($_SERVER["REQUEST_METHOD"] !== "POST") {
|
||||
header("HTTP/1.1 405 Method Not Allowed");
|
||||
exit("Ты дебил, это точка апи.");
|
||||
}
|
||||
|
||||
$id = $this->postParam("id");
|
||||
$sign = $this->postParam("sign") == 1;
|
||||
$content = $this->postParam("new_content");
|
||||
|
||||
$post = (new Posts)->get((int)$id);
|
||||
|
||||
if(!$post || $post->isDeleted())
|
||||
$this->flashFail("err", "Error", tr("error_accepting_invalid_post"), NULL, true);
|
||||
|
||||
if($post->getSuggestionType() == 0)
|
||||
$this->flashFail("err", "Error", tr("error_accepting_not_suggested_post"), NULL, true);
|
||||
|
||||
if($post->getSuggestionType() == 2)
|
||||
$this->flashFail("err", "Error", tr("error_accepting_declined_post"), NULL, true);
|
||||
|
||||
if(!$post->canBePinnedBy($this->user->identity))
|
||||
$this->flashFail("err", "Error", "Can't accept this post.", NULL, true);
|
||||
|
||||
$author = $post->getOwner();
|
||||
|
||||
$flags = 0;
|
||||
$flags |= 0b10000000;
|
||||
|
||||
if($sign)
|
||||
$flags |= 0b01000000;
|
||||
|
||||
$post->setSuggested(0);
|
||||
$post->setCreated(time());
|
||||
$post->setApi_Source_Name(NULL);
|
||||
$post->setFlags($flags);
|
||||
|
||||
if(mb_strlen($content) > 0)
|
||||
$post->setContent($content);
|
||||
|
||||
$post->save();
|
||||
|
||||
if($author->getId() != $this->user->id)
|
||||
(new PostAcceptedNotification($author, $post, $post->getWallOwner()))->emit();
|
||||
|
||||
$this->returnJson([
|
||||
"success" => true,
|
||||
"id" => $post->getPrettyId(),
|
||||
"new_count" => (new Posts)->getSuggestedPostsCount($post->getWallOwner()->getId())
|
||||
]);
|
||||
}
|
||||
|
||||
function renderDecline() {
|
||||
$this->assertUserLoggedIn();
|
||||
$this->willExecuteWriteAction(true);
|
||||
|
||||
if($_SERVER["REQUEST_METHOD"] !== "POST") {
|
||||
header("HTTP/1.1 405 Method Not Allowed");
|
||||
exit("Ты дебил, это метод апи.");
|
||||
}
|
||||
|
||||
$id = $this->postParam("id");
|
||||
$post = (new Posts)->get((int)$id);
|
||||
|
||||
if(!$post || $post->isDeleted())
|
||||
$this->flashFail("err", "Error", tr("error_declining_invalid_post"), NULL, true);
|
||||
|
||||
if($post->getSuggestionType() == 0)
|
||||
$this->flashFail("err", "Error", tr("error_declining_not_suggested_post"), NULL, true);
|
||||
|
||||
if($post->getSuggestionType() == 2)
|
||||
$this->flashFail("err", "Error", tr("error_declining_declined_post"), NULL, true);
|
||||
|
||||
if(!$post->canBePinnedBy($this->user->identity))
|
||||
$this->flashFail("err", "Error", "Can't decline this post.", NULL, true);
|
||||
|
||||
$post->setSuggested(2);
|
||||
$post->setDeleted(1);
|
||||
$post->save();
|
||||
|
||||
$this->returnJson([
|
||||
"success" => true,
|
||||
"new_count" => (new Posts)->getSuggestedPostsCount($post->getWallOwner()->getId())
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -233,7 +233,16 @@
|
|||
|
||||
<div id="_groupListPinnedGroups">
|
||||
<div n:if="$thisUser->getPinnedClubCount() > 0" class="menu_divider"></div>
|
||||
<a n:foreach="$thisUser->getPinnedClubs() as $club" href="{$club->getURL()}" class="link group_link">{$club->getName()}</a>
|
||||
|
||||
<a n:foreach="$thisUser->getPinnedClubs() as $club" href="{$club->getURL()}" class="link group_link">
|
||||
{ovk_proc_strtr($club->getName(), 14)}
|
||||
|
||||
<object type="internal/link" style="white-space: normal;" id="sug{$club->getId()}" n:if="$club->getSuggestedPostsCount($thisUser) > 0 && $club->getWallType() == 2">
|
||||
<a href="/club{$club->getId()}/suggested" class="linkunderline">
|
||||
(<b>{$club->getSuggestedPostsCount($thisUser)}</b>)
|
||||
</a>
|
||||
</object>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div n:if="OPENVK_ROOT_CONF['openvk']['preferences']['commerce'] && $thisUser->getCoins() != 0" id="votesBalance">
|
||||
|
@ -388,6 +397,7 @@
|
|||
{script "js/al_api.js"}
|
||||
{script "js/al_mentions.js"}
|
||||
{script "js/al_polls.js"}
|
||||
{script "js/al_suggestions.js"}
|
||||
|
||||
{ifset $thisUser}
|
||||
{script "js/al_notifs.js"}
|
||||
|
|
|
@ -77,7 +77,12 @@
|
|||
<span class="nobold">{_wall}: </span>
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" name="wall" value="1" n:attr="checked => $club->canPost()" /> {_group_allow_post_for_everyone}<br>
|
||||
<select name="wall">
|
||||
<option value="1" n:attr="selected => $club->getWallType() == 1" /> {_group_allow_post_for_everyone}</option>
|
||||
<option value="2" n:attr="selected => $club->getWallType() == 2" /> {_group_limited_post}</option>
|
||||
<option value="0" n:attr="selected => $club->getWallType() == 0" /> {_group_closed_post}</option>
|
||||
<select>
|
||||
|
||||
<input type="checkbox" name="hide_from_global_feed" value="1" n:attr="checked => $club->isHideFromGlobalFeedEnabled()" /> {_group_hide_from_global_feed}
|
||||
</td>
|
||||
</tr>
|
||||
|
|
34
Web/Presenters/templates/Group/Suggested.xml
Normal file
34
Web/Presenters/templates/Group/Suggested.xml
Normal file
|
@ -0,0 +1,34 @@
|
|||
{extends "../@layout.xml"}
|
||||
|
||||
{block title}{_suggested} {$club->getCanonicalName()}{/block}
|
||||
|
||||
{block header}
|
||||
<a href="{$club->getURL()}">{$club->getName()}</a>
|
||||
» {if $type == "my"}{_suggested_posts_by_you}{else}{_suggested_posts_by_everyone}{/if}
|
||||
{/block}
|
||||
|
||||
{block content}
|
||||
{if $count < 1}
|
||||
{include "../components/error.xml", title => "", description => $type == "my" ? tr("no_suggested_posts_by_you") : tr("no_suggested_posts_by_people")}
|
||||
{else}
|
||||
<h4 id="cound">{if $type == "my"}{tr("suggested_posts_in_group_by_you", $count)}{else}{tr("suggested_posts_in_group", $count)}{/if}</h4>
|
||||
<div id="postz" class="infContainer">
|
||||
{var $microblog = $thisUser->hasMicroblogEnabled()}
|
||||
<div class="infObj" n:foreach="$posts as $post">
|
||||
{if $microblog}
|
||||
{include "../components/post/microblogpost.xml", post => $post, commentSection => false, suggestion => true, forceNoCommentsLink => true, forceNoPinLink => true, forceNoLike => true, forceNoShareLink => true, forceNoDeleteLink => false}
|
||||
{else}
|
||||
{include "../components/post/oldpost.xml", post => $post, commentSection => false, suggestion => true, forceNoCommentsLink => true, forceNoPinLink => true, forceNoLike => true, forceNoShareLink => true, forceNoDeleteLink => false}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{include "../components/paginator.xml", conf => (object) [
|
||||
"page" => $page,
|
||||
"count" => $count,
|
||||
"amount" => sizeof($posts),
|
||||
"perPage" => OPENVK_DEFAULT_PER_PAGE,
|
||||
"atBottom" => true,
|
||||
]}
|
||||
</div>
|
||||
{/if}
|
||||
{/block}
|
|
@ -110,7 +110,19 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div n:if="!is_null($suggestedPostsCountByUser) && $suggestedPostsCountByUser > 0" class="sugglist">
|
||||
<a href="/club{$club->getId()}/suggested" id="cound_r">{tr("suggested_by_you", $suggestedPostsCountByUser)}</a>
|
||||
</div>
|
||||
|
||||
<div n:if="!is_null($suggestedPostsCountByEveryone) && $suggestedPostsCountByEveryone > 0" class="sugglist">
|
||||
<a href="/club{$club->getId()}/suggested" id="cound_r">{tr("suggested_by_everyone", $suggestedPostsCountByEveryone)}</a>
|
||||
</div>
|
||||
|
||||
{presenter "openvk!Wall->wallEmbedded", -$club->getId()}
|
||||
|
||||
<script n:if="isset($thisUser) && $club->getWallType() == 2 && !$club->canBeModifiedBy($thisUser)">
|
||||
document.querySelector("textarea").setAttribute("placeholder", tr("suggest_new"))
|
||||
</script>
|
||||
</div>
|
||||
<div class="right_small_block">
|
||||
{var $avatarPhoto = $club->getAvatarPhoto()}
|
||||
|
|
|
@ -14,6 +14,20 @@
|
|||
{/block}
|
||||
|
||||
{block content}
|
||||
<div class="tabs">
|
||||
<div class="tab">
|
||||
<a href="/wall{$post->getTargetWall()}">{_all_posts}</a>
|
||||
</div>
|
||||
<div class="tab">
|
||||
<a href="/wall{$post->getTargetWall()}?type=owners">{$post->getTargetWall() < 0 ? tr("clubs_posts") : tr("users_posts", ovk_proc_strtr($wallOwner->getFirstName(), 20))}</a>
|
||||
</div>
|
||||
<div class="tab">
|
||||
<a href="/wall{$post->getTargetWall()}?type=others">{_others_posts}</a>
|
||||
</div>
|
||||
<div class="tab" id="activetabs">
|
||||
<a href="" id="act_tab_a">{_post}</a>
|
||||
</div>
|
||||
</div>
|
||||
{include "../components/post.xml", post => $post, forceNoCommentsLink => TRUE, forceNoDeleteLink => TRUE}
|
||||
<hr/>
|
||||
<div style="float: left; min-height: 100px; width: 68%;">
|
||||
|
|
|
@ -15,7 +15,19 @@
|
|||
{block content}
|
||||
<div class="content_divider">
|
||||
<div>
|
||||
<div n:if="$canPost" class="content_subtitle">
|
||||
<div class="tabs">
|
||||
<div n:attr="id => ($type != 'all' ? 'ki' : 'activetabs')" class="tab">
|
||||
<a n:attr="id => ($type != 'all' ? 'ki' : 'act_tab_a')" href="/wall{$owner}">{_all_posts}</a>
|
||||
</div>
|
||||
<div n:attr="id => ($type != 'owners' ? 'ki' : 'activetabs')" class="tab">
|
||||
<a n:attr="id => ($type != 'owners' ? 'ki' : 'act_tab_a')" href="/wall{$owner}?type=owners">{isset($club) ? tr("clubs_posts") : tr("users_posts", ovk_proc_strtr($oObj->getFirstName(), 20))}</a>
|
||||
</div>
|
||||
<div n:attr="id => ($type != 'others' ? 'ki' : 'activetabs')" class="tab">
|
||||
<a n:attr="id => ($type != 'others' ? 'ki' : 'act_tab_a')" href="/wall{$owner}?type=others">{_others_posts}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div n:if="$canPost && $type == 'all'" class="content_subtitle">
|
||||
{include "../components/textArea.xml", route => "/wall$owner/makePost"}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
{var $club = $notification->getModel(1)}
|
||||
{var $post = $notification->getModel(0)}
|
||||
|
||||
{_group}
|
||||
<a href="{$club->getURL()}"><b>{$club->getName()}</b></a>
|
||||
{_nt_accepted_your_post}
|
||||
<a href="/wall{$post->getPrettyId()}"><b>{_nt_post_small}</b></a>.
|
|
@ -0,0 +1,5 @@
|
|||
{var $club = $notification->getModel(1)}
|
||||
|
||||
{_nt_in_club}
|
||||
<a href="/club{$club->getId()}/suggested"><b>{$club->getName()}</b></a>
|
||||
{_nt_new_suggested_posts}
|
|
@ -71,7 +71,7 @@
|
|||
{/if}
|
||||
</div>
|
||||
<div class="post-content" id="{$post->getPrettyId()}">
|
||||
<div class="text">
|
||||
<div class="text" id="text{$post->getPrettyId()}">
|
||||
<span data-text="{$post->getText(false)}" class="really_text">{$post->getText()|noescape}</span>
|
||||
|
||||
{var $width = ($GLOBALS["_bigWall"] ?? false) ? 550 : 320}
|
||||
|
@ -98,17 +98,18 @@
|
|||
<div n:if="$post->isSigned()" class="post-signature">
|
||||
{var $actualAuthor = $post->getOwner(false)}
|
||||
<span>
|
||||
{_author}:
|
||||
<a href="{$actualAuthor->getURL()}" class="mention" data-mention-ref="{$actualAuthor->getId()}">
|
||||
<div class="authorIcon"></div>
|
||||
<a href="{$actualAuthor->getURL()}" class="mention authorName" data-mention-ref="{$actualAuthor->getId()}">
|
||||
{$actualAuthor->getCanonicalName()}
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="post-menu" n:if="$compact == false">
|
||||
<a href="/wall{$post->getPrettyId()}" class="date">{$post->getPublicationTime()}
|
||||
<a href="{if !$suggestion}/wall{$post->getPrettyId()}{else}javascript:void(0){/if}" class="date">{$post->getPublicationTime()}
|
||||
<span n:if="$post->getEditTime()" class="edited editedMark">({_edited_short})</span>
|
||||
</a>
|
||||
|
||||
<a n:if="!empty($platform)" class="client_app" data-app-tag="{$platform}" data-app-name="{$platformDetails['name']}" data-app-url="{$platformDetails['url']}" data-app-img="{$platformDetails['img']}">
|
||||
<img src="/assets/packages/static/openvk/img/app_icons_mini/{$post->getPlatform(this)}.svg">
|
||||
</a>
|
||||
|
@ -144,6 +145,10 @@
|
|||
{include "../textArea.xml", route => $commentsURL, postOpts => false, graffiti => (bool) ovkGetQuirk("comments.allow-graffiti"), post => $post, club => $club}
|
||||
</div>
|
||||
</div>
|
||||
<div n:if="$suggestion && $post->canBePinnedBy($thisUser ?? NULL)" class="suggestionControls">
|
||||
<input type="button" class="button" id="publish_post" data-id="{$post->getId()}" value="{_publish_suggested}">
|
||||
<input type="button" class="button" id="decline_post" data-id="{$post->getId()}" value="{_decline_suggested}">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -52,15 +52,16 @@
|
|||
</a>
|
||||
{/if}
|
||||
<br/>
|
||||
<a href="/wall{$post->getPrettyId()}" class="date">
|
||||
<a href="{if !$suggestion}/wall{$post->getPrettyId()}{else}javascript:void(0){/if}" class="date">
|
||||
{$post->getPublicationTime()} <span n:if="$post->getEditTime()" class="editedMark">({_edited_short})</span>{if $post->isPinned()}, {_pinned}{/if}
|
||||
|
||||
<a n:if="!empty($platform)" class="client_app" data-app-tag="{$platform}" data-app-name="{$platformDetails['name']}" data-app-url="{$platformDetails['url']}" data-app-img="{$platformDetails['img']}">
|
||||
<img src="/assets/packages/static/openvk/img/app_icons_mini/{$post->getPlatform(this)}.svg">
|
||||
</a>
|
||||
</a>
|
||||
</div>
|
||||
<div class="post-content" id="{$post->getPrettyId()}">
|
||||
<div class="text">
|
||||
<div class="text" id="text{$post->getPrettyId()}">
|
||||
{var $owner = $author->getId()}
|
||||
|
||||
<span data-text="{$post->getText(false)}" class="really_text">{$post->getText()|noescape}</span>
|
||||
|
@ -82,6 +83,10 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div n:if="$suggestion && $post->canBePinnedBy($thisUser ?? NULL)" class="suggestionControls" style="margin-bottom: 7px;">
|
||||
<input type="button" class="button" id="publish_post" data-id="{$post->getId()}" value="{_publish_suggested}">
|
||||
<input type="button" class="button" id="decline_post" data-id="{$post->getId()}" value="{_decline_suggested}">
|
||||
</div>
|
||||
<div n:if="$post->isAd()" style="color:grey;">
|
||||
<br/>
|
||||
! {_post_is_ad}
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
</nobold>
|
||||
</div>
|
||||
<div>
|
||||
<div class="insertThere" id="postz"></div>
|
||||
<div id="underHeader">
|
||||
<div n:if="$canPost" class="content_subtitle">
|
||||
{include "../components/textArea.xml", route => "/wall$owner/makePost", graffiti => true, polls => true, notes => true}
|
||||
</div>
|
||||
|
@ -24,6 +26,7 @@
|
|||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{if isset($thisUser) && $thisUser->hasMicroblogEnabled()}
|
||||
|
|
|
@ -141,6 +141,10 @@ routes:
|
|||
handler: "Wall->delete"
|
||||
- url: "/wall{num}_{num}/pin"
|
||||
handler: "Wall->pin"
|
||||
- url: "/wall/accept"
|
||||
handler: "Wall->accept"
|
||||
- url: "/wall/decline"
|
||||
handler: "Wall->decline"
|
||||
- url: "/blob_{text}/{?path}.{text}"
|
||||
handler: "Blob->file"
|
||||
placeholders:
|
||||
|
@ -235,6 +239,8 @@ routes:
|
|||
handler: "Group->admin"
|
||||
- url: "/club{num}/setAdmin"
|
||||
handler: "Group->modifyAdmin"
|
||||
- url: "/club{num}/suggested"
|
||||
handler: "Group->suggested"
|
||||
- url: "/groups{num}"
|
||||
handler: "User->groups"
|
||||
- url: "/groups_pin"
|
||||
|
|
|
@ -2849,6 +2849,59 @@ body.article .floating_sidebar, body.article .page_content {
|
|||
font-size: 12px;
|
||||
}
|
||||
|
||||
.sugglist {
|
||||
padding-bottom: 5px;
|
||||
padding-top: 5px;
|
||||
margin-bottom: -5px;
|
||||
padding-left: 9px;
|
||||
border-top: 1px solid gray;
|
||||
background-color: #e6e6e6;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.sugglist a {
|
||||
color: #626262;
|
||||
}
|
||||
|
||||
.suggestionControls {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.button.loaded {
|
||||
background: #595959 url("/assets/packages/static/openvk/img/loading_mini.gif") no-repeat 50% 50%;
|
||||
padding: 2px 9px 7px 39px;
|
||||
margin-bottom: -6px;
|
||||
}
|
||||
|
||||
@-moz-document url-prefix() {
|
||||
.button.loaded {
|
||||
padding: 16px 40px 6px 4px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.sugglist a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.sugglist a[data-toogled="true"] {
|
||||
text-decoration: underline;
|
||||
color:#4a4a4a;
|
||||
}
|
||||
|
||||
.authorIcon {
|
||||
height: 11px;
|
||||
margin-top: 1px;
|
||||
width: 10px;
|
||||
float: left;
|
||||
background: url("/assets/packages/static/openvk/img/person.png") no-repeat 0 0;
|
||||
}
|
||||
|
||||
.authorName {
|
||||
margin-left: 4px;
|
||||
font-weight: normal !important;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.topGrayBlock {
|
||||
background: #F0F0F0;
|
||||
height: 37px;
|
||||
|
@ -3002,3 +3055,4 @@ hr {
|
|||
background-repeat: no-repeat !important;
|
||||
background-position: 50% !important;
|
||||
}
|
||||
|
||||
|
|
BIN
Web/static/img/person.png
Normal file
BIN
Web/static/img/person.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 265 B |
231
Web/static/js/al_suggestions.js
Normal file
231
Web/static/js/al_suggestions.js
Normal file
|
@ -0,0 +1,231 @@
|
|||
function endSuggestAction(new_count, post_node) {
|
||||
if(document.getElementById("cound") != null)
|
||||
document.getElementById("cound").innerHTML = tr("suggested_posts_in_group", new_count)
|
||||
else
|
||||
document.getElementById("cound_r").innerHTML = tr("suggested_by_everyone", new_count)
|
||||
|
||||
if(document.querySelector("object a[href='"+location.pathname+"'] b") != null) {
|
||||
document.querySelector("object a[href='"+location.pathname+"'] b").innerHTML = new_count
|
||||
|
||||
if(new_count < 1) {
|
||||
u("object a[href='"+location.pathname+"']").remove()
|
||||
}
|
||||
}
|
||||
|
||||
if(new_count < 1 && document.querySelector(".sugglist") != null) {
|
||||
$(".sugglist a").click()
|
||||
$(".sugglist").remove()
|
||||
}
|
||||
|
||||
post_node.style.transition = "opacity 300ms ease-in-out";
|
||||
post_node.style.opacity = "0";
|
||||
post_node.classList.remove("post")
|
||||
|
||||
setTimeout(() => {post_node.outerHTML = ""}, 300)
|
||||
|
||||
if(document.querySelectorAll("#postz .post").length < 1 && new_count > 0 && document.querySelector(".paginator") != null)
|
||||
loadMoreSuggestedPosts()
|
||||
}
|
||||
|
||||
// "Опубликовать запись"
|
||||
$(document).on("click", "#publish_post", async (e) => {
|
||||
let id = Number(e.currentTarget.dataset.id)
|
||||
let post;
|
||||
let body = `
|
||||
<textarea id="pooblish" style="max-height:500px;resize:vertical;min-height:54px;"></textarea>
|
||||
<label><input type="checkbox" id="signatr" checked>${tr("add_signature")}</label>
|
||||
`
|
||||
|
||||
MessageBox(tr("publishing_suggested_post"), body, [tr("publish"), tr("cancel")], [(async () => {
|
||||
let id = Number(e.currentTarget.dataset.id)
|
||||
let post;
|
||||
|
||||
let formData = new FormData()
|
||||
formData.append("id", id)
|
||||
formData.append("sign", document.getElementById("signatr").checked ? 1 : 0)
|
||||
formData.append("new_content", document.getElementById("pooblish").value)
|
||||
formData.append("hash", u("meta[name=csrf]").attr("value"))
|
||||
|
||||
ky.post("/wall/accept", {
|
||||
hooks: {
|
||||
beforeRequest: [
|
||||
(_request) => {
|
||||
e.currentTarget.classList.add("loaded")
|
||||
e.currentTarget.setAttribute("value", "")
|
||||
e.currentTarget.setAttribute("id", "")
|
||||
}
|
||||
],
|
||||
afterResponse: [
|
||||
async (_request, _options, response) => {
|
||||
json = await response.json()
|
||||
|
||||
if(json.success) {
|
||||
NewNotification(tr("suggestion_succefully_published"), tr("suggestion_press_to_go"), null, () => {window.location.assign("/wall" + json.id)});
|
||||
endSuggestAction(json.new_count, e.currentTarget.closest("table"))
|
||||
} else {
|
||||
MessageBox(tr("error"), json.flash.message, [tr("ok")], [Function.noop]);
|
||||
}
|
||||
|
||||
e.currentTarget.setAttribute("value", tr("publish_suggested"))
|
||||
e.currentTarget.classList.remove("loaded")
|
||||
e.currentTarget.setAttribute("id", "publish_post")
|
||||
}
|
||||
]
|
||||
},
|
||||
body: formData
|
||||
})
|
||||
}), Function.noop]);
|
||||
|
||||
document.getElementById("pooblish").innerHTML = e.currentTarget.closest("table").querySelector(".really_text").dataset.text
|
||||
document.querySelector(".ovk-diag-body").style.padding = "9px";
|
||||
})
|
||||
|
||||
// "Отклонить"
|
||||
$(document).on("click", "#decline_post", async (e) => {
|
||||
let id = Number(e.currentTarget.dataset.id)
|
||||
|
||||
let formData = new FormData()
|
||||
formData.append("id", id)
|
||||
formData.append("hash", u("meta[name=csrf]").attr("value"))
|
||||
|
||||
ky.post("/wall/decline", {
|
||||
hooks: {
|
||||
beforeRequest: [
|
||||
(_request) => {
|
||||
e.currentTarget.classList.add("loaded")
|
||||
e.currentTarget.setAttribute("value", "")
|
||||
e.currentTarget.setAttribute("id", "")
|
||||
}
|
||||
],
|
||||
afterResponse: [
|
||||
async (_request, _options, response) => {
|
||||
json = await response.json()
|
||||
|
||||
if(json.success) {
|
||||
endSuggestAction(json.new_count, e.currentTarget.closest("table"))
|
||||
} else {
|
||||
MessageBox(tr("error"), json.flash.message, [tr("ok")], [Function.noop]);
|
||||
}
|
||||
|
||||
e.currentTarget.setAttribute("value", tr("decline_suggested"))
|
||||
e.currentTarget.setAttribute("id", "decline_post")
|
||||
e.currentTarget.classList.remove("loaded")
|
||||
}
|
||||
]
|
||||
},
|
||||
body: formData
|
||||
})
|
||||
})
|
||||
|
||||
function loadMoreSuggestedPosts() {
|
||||
let link = location.href
|
||||
|
||||
if(!link.includes("/suggested")) {
|
||||
link += "/suggested"
|
||||
}
|
||||
|
||||
ky.get(link, {
|
||||
hooks: {
|
||||
beforeRequest: [
|
||||
(_request) => {
|
||||
document.getElementById("postz").innerHTML = `<img src="/assets/packages/static/openvk/img/loading_mini.gif">`
|
||||
}
|
||||
],
|
||||
afterResponse: [
|
||||
async (_request, _options, response) => {
|
||||
let text = await response.text()
|
||||
let parser = new DOMParser()
|
||||
let body = parser.parseFromString(text, "text/html")
|
||||
|
||||
if(body.querySelectorAll(".post").length < 1) {
|
||||
let url = new URL(location.href)
|
||||
url.searchParams.set("p", url.searchParams.get("p") - 1)
|
||||
|
||||
if(url.searchParams.get("p") < 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
history.pushState({}, "", url)
|
||||
|
||||
loadMoreSuggestedPosts()
|
||||
}
|
||||
|
||||
body.querySelectorAll(".bsdn").forEach(bsdnInitElement)
|
||||
document.getElementById("postz").innerHTML = body.getElementById("postz").innerHTML
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// нажатие на "x предложенных записей"
|
||||
$(document).on("click", ".sugglist a", (e) => {
|
||||
e.preventDefault()
|
||||
|
||||
if(e.currentTarget.getAttribute("data-toogled") == null || e.currentTarget.getAttribute("data-toogled") == "false") {
|
||||
e.currentTarget.setAttribute("data-toogled", "true")
|
||||
document.getElementById("underHeader").style.display = "none"
|
||||
document.querySelector(".insertThere").style.display = "block"
|
||||
document.querySelector(".insertThere").classList.add("infContainer")
|
||||
history.pushState({}, "", e.currentTarget.href)
|
||||
|
||||
// если ещё ничего не подгружалось
|
||||
if(document.querySelector(".insertThere").innerHTML == "") {
|
||||
ky(e.currentTarget.href, {
|
||||
hooks: {
|
||||
beforeRequest: [
|
||||
(_request) => {
|
||||
document.querySelector(".insertThere").insertAdjacentHTML("afterbegin", `<img src="/assets/packages/static/openvk/img/loading_mini.gif">`)
|
||||
}
|
||||
],
|
||||
afterResponse: [
|
||||
async (_request, _options, response) => {
|
||||
let parser = new DOMParser
|
||||
let result = parser.parseFromString(await response.text(), 'text/html').querySelector(".infContainer")
|
||||
|
||||
result.querySelectorAll(".bsdn").forEach(bsdnInitElement)
|
||||
document.querySelector(".insertThere").innerHTML = result.innerHTML
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// переключение на нормальную стену
|
||||
e.currentTarget.setAttribute("data-toogled", "false")
|
||||
document.getElementById("underHeader").style.display = "block"
|
||||
document.querySelector(".insertThere").style.display = "none"
|
||||
document.querySelector(".insertThere").classList.remove("infContainer")
|
||||
history.pushState({}, "", e.currentTarget.href.replace("/suggested", ""))
|
||||
}
|
||||
})
|
||||
|
||||
// нажатие на пагинатор у постов предложки
|
||||
$(document).on("click", "#postz .paginator a", (e) => {
|
||||
e.preventDefault()
|
||||
|
||||
ky(e.currentTarget.href, {
|
||||
hooks: {
|
||||
beforeRequest: [
|
||||
(_request) => {
|
||||
if(document.querySelector(".sugglist") != null) {
|
||||
document.querySelector(".sugglist").scrollIntoView({behavior: "smooth"})
|
||||
} else {
|
||||
document.querySelector(".infContainer").scrollIntoView({behavior: "smooth"})
|
||||
}
|
||||
|
||||
setTimeout(() => {document.getElementById("postz").innerHTML = `<img src="/assets/packages/static/openvk/img/loading_mini.gif">`}, 500)
|
||||
}
|
||||
],
|
||||
afterResponse: [
|
||||
async (_request, _options, response) => {
|
||||
let result = (new DOMParser).parseFromString(await response.text(), "text/html").querySelector(".infContainer")
|
||||
result.querySelectorAll(".bsdn").forEach(bsdnInitElement)
|
||||
|
||||
document.getElementById("postz").innerHTML = result.innerHTML
|
||||
history.pushState({}, "", e.currentTarget.href)
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
})
|
|
@ -445,7 +445,7 @@ tippy(".client_app", {
|
|||
function addNote(textareaId, nid)
|
||||
{
|
||||
if(nid > 0) {
|
||||
note.value = nid
|
||||
document.getElementById("note").value = nid
|
||||
let noteObj = document.querySelector("#nd"+nid)
|
||||
|
||||
let nortd = document.querySelector("#post-buttons"+textareaId+" .post-has-note");
|
||||
|
@ -453,7 +453,7 @@ function addNote(textareaId, nid)
|
|||
|
||||
nortd.innerHTML = `${tr("note")} ${escapeHtml(noteObj.dataset.name)}`
|
||||
} else {
|
||||
note.value = "none"
|
||||
document.getElementById("note").value = "none"
|
||||
|
||||
let nortd = document.querySelector("#post-buttons"+textareaId+" .post-has-note");
|
||||
nortd.style.display = "none"
|
||||
|
@ -481,7 +481,7 @@ async function attachNote(id)
|
|||
${tr("select_or_create_new")}
|
||||
<div id="notesList">`
|
||||
|
||||
if(note.value != "none") {
|
||||
if(document.getElementById("note").value != "none") {
|
||||
body += `
|
||||
<div class="ntSelect" onclick="addNote(${id}, 0)">
|
||||
<span>${tr("do_not_attach_note")}</span>
|
||||
|
|
1
install/sqls/00043-suggest-posts.sql
Normal file
1
install/sqls/00043-suggest-posts.sql
Normal file
|
@ -0,0 +1 @@
|
|||
ALTER TABLE `posts` ADD `suggested` TINYINT(2) UNSIGNED NOT NULL DEFAULT '0' AFTER `deleted`, ADD INDEX (`suggested`);
|
|
@ -230,6 +230,11 @@
|
|||
|
||||
"edited_short" = "edited";
|
||||
|
||||
"all_posts" = "All posts";
|
||||
"users_posts" = "Posts by $1";
|
||||
"clubs_posts" = "Group's posts";
|
||||
"others_posts" = "Others posts";
|
||||
|
||||
/* Friends */
|
||||
|
||||
"friends" = "Friends";
|
||||
|
@ -276,6 +281,7 @@
|
|||
|
||||
/* Group */
|
||||
|
||||
"group" = "Group";
|
||||
"name_group" = "Name";
|
||||
"subscribe" = "Subscribe";
|
||||
"unsubscribe" = "Unsubscribe";
|
||||
|
@ -313,8 +319,60 @@
|
|||
"set_comment" = "Set comment";
|
||||
"hidden_yes" = "Hidden: Yes";
|
||||
"hidden_no" = "Hidden: No";
|
||||
"group_allow_post_for_everyone" = "Allow posting for everyone";
|
||||
"group_allow_post_for_everyone" = "Open";
|
||||
"group_limited_post" = "Suggestions";
|
||||
"group_closed_post" = "Closed";
|
||||
"suggest_new" = "Suggest post";
|
||||
|
||||
"suggested_by_you_zero" = "$1 suggested posts by you";
|
||||
"suggested_by_you_one" = "One suggested post by you";
|
||||
"suggested_by_you_few" = "$1 suggested posts by you";
|
||||
"suggested_by_you_many" = "$1 suggested posts by you";
|
||||
"suggested_by_you_other" = "$1 suggested posts by you";
|
||||
|
||||
"suggested_by_everyone_zero" = "$1 suggested posts";
|
||||
"suggested_by_everyone_one" = "One suggested post";
|
||||
"suggested_by_everyone_few" = "$1 suggested posts";
|
||||
"suggested_by_everyone_many" = "$1 suggested posts";
|
||||
"suggested_by_everyone_other" = "$1 suggested posts";
|
||||
|
||||
"group_hide_from_global_feed" = "Don't display posts in the global feed";
|
||||
"suggested_posts_by_you" = "Suggested posts by you";
|
||||
"suggested_posts_by_everyone" = "Suggested posts";
|
||||
"suggested" = "Suggested";
|
||||
"suggested_posts_everyone" = "Suggested by users posts";
|
||||
"no_suggested_posts_by_you" = "You haven't suggested posts to this group yet.";
|
||||
"no_suggested_posts_by_people" = "No posts have been suggested to this group yet.";
|
||||
|
||||
"publish_suggested" = "Accept";
|
||||
"decline_suggested" = "Decline";
|
||||
|
||||
"error_loading_suggest" = "Error when loading new posts";
|
||||
|
||||
"publishing_suggested_post" = "Publishing suggested post";
|
||||
"suggested_posts_in_group_zero" = "You've looked at all the suggested posts, congratulations!";
|
||||
"suggested_posts_in_group_one" = "This group has one suggested post";
|
||||
"suggested_posts_in_group_few" = "This group has $1 suggested posts";
|
||||
"suggested_posts_in_group_many" = "This group has $1 suggested posts";
|
||||
"suggested_posts_in_group_other" = "This group has $1 suggested posts";
|
||||
|
||||
"suggested_posts_in_group_by_you_zero" = "You haven't suggested any posts to this group";
|
||||
"suggested_posts_in_group_by_you_one" = "You suggested one post to this group";
|
||||
"suggested_posts_in_group_by_you_few" = "You suggested $1 posts to this group";
|
||||
"suggested_posts_in_group_by_you_many" = "You suggested $1 posts to this group";
|
||||
"suggested_posts_in_group_by_you_other" = "You suggested $1 posts to this group";
|
||||
|
||||
"suggestion_succefully_published" = "Post successfully published";
|
||||
"suggestion_succefully_declined" = "Post successfully declined";
|
||||
"suggestion_press_to_go" = "Click to show it";
|
||||
|
||||
"error_declining_invalid_post" = "Error when declining post: post does not exists";
|
||||
"error_declining_not_suggested_post" = "Error when declining post: post is not suggested";
|
||||
"error_declining_declined_post" = "Error when declining post: post is already declined";
|
||||
|
||||
"error_accepting_invalid_post" = "Error when accepting post: post does not exists";
|
||||
"error_accepting_not_suggested_post" = "Error when accepting post: post is not suggested";
|
||||
"error_accepting_declined_post" = "Error when accepting post: cant accept declined post";
|
||||
"statistics" = "Statistics";
|
||||
"group_administrators_list" = "Admins list";
|
||||
"group_display_only_creator" = "Display only group creator";
|
||||
|
@ -347,6 +405,11 @@
|
|||
"search_by_groups" = "Explore Groups";
|
||||
"search_group_desc" = "Browse through existing groups and find the one that suits your needs...";
|
||||
|
||||
"error_suggestions" = "Error accessing to suggestions";
|
||||
"error_suggestions_closed" = "This group has closed wall.";
|
||||
"error_suggestions_open" = "This group has open wall.";
|
||||
"error_suggestions_access" = "Only group's administrators can view all suggested posts.";
|
||||
|
||||
"group_banned" = "Unfortunately, we had to block the <b>$1</b> group.";
|
||||
|
||||
/* Albums */
|
||||
|
@ -870,6 +933,9 @@
|
|||
"nt_shared_yours" = "shared your";
|
||||
"nt_commented_yours" = "commented";
|
||||
"nt_written_on_your_wall" = "wrote on your wall";
|
||||
"nt_accepted_your_post" = "accepted your suggested";
|
||||
"nt_in_club" = "In group";
|
||||
"nt_new_suggested_posts" = "new posts in suggestions";
|
||||
"nt_made_you_admin" = "appointed you in the community";
|
||||
|
||||
"nt_from" = "from";
|
||||
|
@ -890,6 +956,8 @@
|
|||
"nt_mention_in_topic" = "in the discussion";
|
||||
"nt_sent_gift" = "sent you a gift";
|
||||
|
||||
"nt_post_small" = "post";
|
||||
|
||||
/* Time */
|
||||
|
||||
"time_at_sp" = " at ";
|
||||
|
@ -1325,6 +1393,8 @@
|
|||
"media_file_corrupted_or_too_large" = "The media content file is corrupted or too large.";
|
||||
"post_is_empty_or_too_big" = "The post is empty or too big.";
|
||||
"post_is_too_big" = "The post is too big.";
|
||||
"error_deleting_suggested" = "You can't delete your accepted post";
|
||||
"error_invalid_wall_value" = "Invalid wall value";
|
||||
|
||||
"error_sending_report" = "Failed to make a report...";
|
||||
|
||||
|
|
|
@ -206,6 +206,11 @@
|
|||
"post_is_ad" = "Этот пост был размещён за взятку.";
|
||||
"edited_short" = "ред.";
|
||||
|
||||
"all_posts" = "Все записи";
|
||||
"users_posts" = "Записи $1";
|
||||
"clubs_posts" = "Записи сообщества";
|
||||
"others_posts" = "Чужие записи";
|
||||
|
||||
/* Friends */
|
||||
|
||||
"friends" = "Друзья";
|
||||
|
@ -259,6 +264,7 @@
|
|||
|
||||
/* Group */
|
||||
|
||||
"group" = "Сообщество";
|
||||
"name_group" = "Название";
|
||||
"subscribe" = "Подписаться";
|
||||
"unsubscribe" = "Отписаться";
|
||||
|
@ -295,8 +301,61 @@
|
|||
"set_comment" = "Изменить комментарий";
|
||||
"hidden_yes" = "Скрыт: Да";
|
||||
"hidden_no" = "Скрыт: Нет";
|
||||
"group_allow_post_for_everyone" = "Разрешить публиковать записи всем";
|
||||
|
||||
"group_allow_post_for_everyone" = "Открытая";
|
||||
"group_limited_post" = "Предложка";
|
||||
"group_closed_post" = "Закрытая";
|
||||
"suggest_new" = "Предложить новость";
|
||||
"suggested_by_you_zero" = "$1 предложенных вами записей";
|
||||
"suggested_by_you_one" = "Одна предложенная вами запись";
|
||||
"suggested_by_you_few" = "$1 предложенные вами записи";
|
||||
"suggested_by_you_many" = "$1 предложенных вами записей";
|
||||
"suggested_by_you_other" = "$1 предложенных вами записей";
|
||||
|
||||
"suggested_by_everyone_zero" = "$1 предложенных записей";
|
||||
"suggested_by_everyone_one" = "Одна предложенная запись";
|
||||
"suggested_by_everyone_few" = "$1 предложенные записи";
|
||||
"suggested_by_everyone_many" = "$1 предложенных записей";
|
||||
"suggested_by_everyone_other" = "$1 предложенных записей";
|
||||
|
||||
"group_hide_from_global_feed" = "Не отображать публикации в глобальной ленте";
|
||||
"suggested_posts_by_you" = "Предложенные вами записи";
|
||||
"suggested_posts_by_everyone" = "Предложенные записи";
|
||||
"suggested" = "Предложено";
|
||||
"suggested_posts_everyone" = "Предложенные пользователями записи";
|
||||
"no_suggested_posts_by_you" = "Вы ещё не предлагали записей в эту группу.";
|
||||
"no_suggested_posts_by_people" = "В эту группу ещё не предлагали записей.";
|
||||
|
||||
"publish_suggested" = "Опубликовать запись";
|
||||
"decline_suggested" = "Отклонить";
|
||||
|
||||
"error_loading_suggest" = "Не удалось подгрузить новые посты";
|
||||
|
||||
"publishing_suggested_post" = "Публикация предложенной записи";
|
||||
"suggested_posts_in_group_zero" = "Вы посмотрели всю предложку, поздравляю!";
|
||||
"suggested_posts_in_group_one" = "В эту группу предложили одну запись";
|
||||
"suggested_posts_in_group_few" = "В эту группу предложили $1 записи";
|
||||
"suggested_posts_in_group_many" = "В эту группу предложили $1 записей";
|
||||
"suggested_posts_in_group_other" = "В эту группу предложили $1 записей";
|
||||
|
||||
"suggested_posts_in_group_by_you_zero" = "Вы не предлагали в эту группу никаких записей";
|
||||
"suggested_posts_in_group_by_you_one" = "Вы предложили в эту группу одну запись";
|
||||
"suggested_posts_in_group_by_you_few" = "Вы предложили в эту группу $1 записи";
|
||||
"suggested_posts_in_group_by_you_many" = "Вы предложили в эту группу $1 записей";
|
||||
"suggested_posts_in_group_by_you_other" = "Вы предложили в эту группу $1 записей";
|
||||
|
||||
"suggestion_succefully_published" = "Запись успешно опубликована";
|
||||
"suggestion_succefully_declined" = "Запись успешно отклонена";
|
||||
"suggestion_press_to_go" = "Нажмите, чтобы перейти к ней";
|
||||
|
||||
"error_declining_invalid_post" = "Не удалость отклонить пост: поста не существует";
|
||||
"error_declining_not_suggested_post" = "Не удалость отклонить пост: пост не из предложки";
|
||||
"error_declining_declined_post" = "Не удалость отклонить пост: пост уже отклонён";
|
||||
|
||||
"error_accepting_invalid_post" = "Не удалость принять пост: поста не существует";
|
||||
"error_accepting_not_suggested_post" = "Не удалость принять пост: пост не из предложки";
|
||||
"error_accepting_declined_post" = "Не удалость принять пост: пост отклонён";
|
||||
|
||||
"statistics" = "Статистика";
|
||||
"group_administrators_list" = "Список админов";
|
||||
"group_display_only_creator" = "Отображать только создателя группы";
|
||||
|
@ -330,6 +389,11 @@
|
|||
"search_group_desc" = "Здесь Вы можете просмотреть существующие группы и выбрать группу себе по вкусу...";
|
||||
"group_banned" = "К сожалению, нам пришлось заблокировать сообщество <b>$1</b>.";
|
||||
|
||||
"error_suggestions" = "Ошибка доступа к предложенным";
|
||||
"error_suggestions_closed" = "У этой группы закрытая стена.";
|
||||
"error_suggestions_open" = "У этой группы открытая стена.";
|
||||
"error_suggestions_access" = "Просматривать все предложенные записи могут только администраторы группы.";
|
||||
|
||||
/* Albums */
|
||||
|
||||
"create" = "Создать";
|
||||
|
@ -821,6 +885,9 @@
|
|||
"nt_shared_yours" = "поделился(-ась) вашим";
|
||||
"nt_commented_yours" = "оставил(а) комментарий под";
|
||||
"nt_written_on_your_wall" = "написал(а) на вашей стене";
|
||||
"nt_accepted_your_post" = "опубликовало вашу предложенную";
|
||||
"nt_in_club" = "В сообществе";
|
||||
"nt_new_suggested_posts" = "новые записи в предложке";
|
||||
"nt_made_you_admin" = "назначил(а) вас руководителем сообщества";
|
||||
"nt_from" = "от";
|
||||
"nt_yours_adjective" = "вашим";
|
||||
|
@ -838,6 +905,7 @@
|
|||
"nt_mention_in_video" = "в обсуждении видеозаписи";
|
||||
"nt_mention_in_note" = "в обсуждении заметки";
|
||||
"nt_mention_in_topic" = "в обсуждении";
|
||||
"nt_post_small" = "запись";
|
||||
"nt_sent_gift" = "отправил вам подарок";
|
||||
|
||||
/* Time */
|
||||
|
@ -1226,6 +1294,10 @@
|
|||
"media_file_corrupted_or_too_large" = "Файл медиаконтента повреждён или слишком велик.";
|
||||
"post_is_empty_or_too_big" = "Пост пустой или слишком большой.";
|
||||
"post_is_too_big" = "Пост слишком большой.";
|
||||
|
||||
"error_deleting_suggested" = "Вы не можете удалить ваш принятый пост";
|
||||
"error_invalid_wall_value" = "Некорректное значение стены";
|
||||
|
||||
"error_sending_report" = "Не удалось подать жалобу...";
|
||||
"error_when_saving_gift" = "Не удалось сохранить подарок";
|
||||
"error_when_saving_gift_bad_image" = "Изображение подарка кривое.";
|
||||
|
|
|
@ -243,6 +243,19 @@ input[type="radio"] {
|
|||
border-color: #473e66 !important;
|
||||
}
|
||||
|
||||
.sugglist {
|
||||
background-color: #231e33;
|
||||
border-color: #2c2640 !important;
|
||||
}
|
||||
|
||||
.sugglist a {
|
||||
color: #7c94c5;
|
||||
}
|
||||
|
||||
.button.loaded {
|
||||
background: #383052 url("/assets/packages/static/openvk/img/loading_mini.gif") no-repeat 50% 50% !important;
|
||||
}
|
||||
|
||||
.bigPlayer {
|
||||
background-color: rgb(30, 26, 43) !important;
|
||||
}
|
||||
|
|
|
@ -47,13 +47,13 @@ body {
|
|||
|
||||
.content_title_expanded {
|
||||
cursor: pointer;
|
||||
background-image: unset;
|
||||
background-image: unset !important;
|
||||
padding: 3px 10px;
|
||||
border-top: #e6e6e6 solid 1px;
|
||||
}
|
||||
|
||||
.content_title_unexpanded {
|
||||
background-image: unset;
|
||||
background-image: unset !important;
|
||||
padding: 3px 10px;
|
||||
border-top: #eee solid 1px;
|
||||
}
|
||||
|
@ -329,6 +329,11 @@ input[type=checkbox] {
|
|||
border-top: 1px solid #2f2f2f;
|
||||
}
|
||||
|
||||
.sugglist {
|
||||
border-top: unset;
|
||||
border-bottom: 1px solid gray;
|
||||
}
|
||||
|
||||
.musicIcon {
|
||||
filter: contrast(202%) !important;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue