From 81da6e1518b0dd4718883828f16abff1608d4438 Mon Sep 17 00:00:00 2001
From: lalka2016 <99399973+lalka2016@users.noreply.github.com>
Date: Wed, 24 May 2023 10:51:08 +0300
Subject: [PATCH] Search with parameters
---
Web/Models/Repositories/Applications.php | 8 +
Web/Models/Repositories/Clubs.php | 4 +-
Web/Models/Repositories/Comments.php | 23 ++
Web/Models/Repositories/Posts.php | 25 +-
Web/Models/Repositories/Users.php | 38 +-
Web/Models/Repositories/Videos.php | 23 ++
Web/Presenters/SearchPresenter.php | 74 +++-
Web/Presenters/templates/@layout.xml | 50 ++-
Web/Presenters/templates/Search/Index.xml | 329 +++++++++++++++---
Web/Presenters/templates/User/View.xml | 40 ++-
.../templates/components/comment.xml | 7 +-
Web/Presenters/templates/components/video.xml | 35 ++
Web/static/css/main.css | 150 ++++++++
Web/static/img/hide.png | Bin 0 -> 184 bytes
Web/static/img/show.png | Bin 0 -> 169 bytes
Web/static/js/openvk.cls.js | 44 +++
locales/en.strings | 58 ++-
locales/ru.strings | 60 +++-
18 files changed, 892 insertions(+), 76 deletions(-)
create mode 100644 Web/Presenters/templates/components/video.xml
create mode 100644 Web/static/img/hide.png
create mode 100644 Web/static/img/show.png
diff --git a/Web/Models/Repositories/Applications.php b/Web/Models/Repositories/Applications.php
index 3aa6e5be..0687856e 100644
--- a/Web/Models/Repositories/Applications.php
+++ b/Web/Models/Repositories/Applications.php
@@ -66,4 +66,12 @@ class Applications
{
return sizeof($this->appRels->where("user", $user->getId()));
}
+
+ function find(string $query, array $pars = [], string $sort = "id"): Util\EntityStream
+ {
+ $query = "%$query%";
+ $result = $this->apps->where("CONCAT_WS(' ', name, description) LIKE ?", $query)->where("enabled", 1);
+
+ return new Util\EntityStream("Application", $result->order("$sort"));
+ }
}
\ No newline at end of file
diff --git a/Web/Models/Repositories/Clubs.php b/Web/Models/Repositories/Clubs.php
index 8e97f3eb..04bb30ab 100644
--- a/Web/Models/Repositories/Clubs.php
+++ b/Web/Models/Repositories/Clubs.php
@@ -43,12 +43,12 @@ class Clubs
return $this->toClub($this->clubs->get($id));
}
- function find(string $query, int $page = 1, ?int $perPage = NULL): \Traversable
+ function find(string $query, array $pars = [], string $sort = "id DESC", int $page = 1, ?int $perPage = NULL): \Traversable
{
$query = "%$query%";
$result = $this->clubs->where("name LIKE ? OR about LIKE ?", $query, $query);
- return new Util\EntityStream("Club", $result);
+ return new Util\EntityStream("Club", $result->order($sort));
}
function getCount(): int
diff --git a/Web/Models/Repositories/Comments.php b/Web/Models/Repositories/Comments.php
index 4774cf35..4b4dfc57 100644
--- a/Web/Models/Repositories/Comments.php
+++ b/Web/Models/Repositories/Comments.php
@@ -59,4 +59,27 @@ class Comments
"deleted" => false,
]));
}
+
+ function find(string $query = "", array $pars = [], string $sort = "id"): Util\EntityStream
+ {
+ $query = "%$query%";
+
+ $notNullParams = [];
+
+ foreach($pars as $paramName => $paramValue) {
+ if($paramName != "before" && $paramName != "after")
+ $paramValue != NULL ? $notNullParams+=["$paramName" => "%$paramValue%"] : NULL;
+ else
+ $paramValue != NULL ? $notNullParams+=["$paramName" => "$paramValue"] : NULL;
+ }
+
+ $result = $this->comments->where("content LIKE ?", $query)->where("deleted", 0);
+ $nnparamsCount = sizeof($notNullParams);
+
+ if($nnparamsCount > 0) {
+ !is_null($notNullParams["before"]) ? $result->where("created < ?", $notNullParams["before"]) : NULL;
+ !is_null($notNullParams["after"]) ? $result->where("created > ?", $notNullParams["after"]) : NULL;
+ }
+ return new Util\EntityStream("Comment", $result->order("$sort"));
+ }
}
diff --git a/Web/Models/Repositories/Posts.php b/Web/Models/Repositories/Posts.php
index 7aadc0bb..8056264a 100644
--- a/Web/Models/Repositories/Posts.php
+++ b/Web/Models/Repositories/Posts.php
@@ -99,7 +99,30 @@ class Posts
return NULL;
}
-
+
+ function find(string $query = "", array $pars = [], string $sort = "id"): Util\EntityStream
+ {
+ $query = "%$query%";
+
+ $notNullParams = [];
+
+ foreach($pars as $paramName => $paramValue) {
+ if($paramName != "before" && $paramName != "after")
+ $paramValue != NULL ? $notNullParams+=["$paramName" => "%$paramValue%"] : NULL;
+ else
+ $paramValue != NULL ? $notNullParams+=["$paramName" => "$paramValue"] : NULL;
+ }
+
+ $result = $this->posts->where("content LIKE ?", $query)->where("deleted", 0);
+ $nnparamsCount = sizeof($notNullParams);
+
+ if($nnparamsCount > 0) {
+ !is_null($notNullParams["before"]) ? $result->where("created < ?", $notNullParams["before"]) : NULL;
+ !is_null($notNullParams["after"]) ? $result->where("created > ?", $notNullParams["after"]) : NULL;
+ }
+ return new Util\EntityStream("Post", $result->order("$sort"));
+ }
+
function getPostCountOnUserWall(int $user): int
{
return sizeof($this->posts->where(["wall" => $user, "deleted" => 0]));
diff --git a/Web/Models/Repositories/Users.php b/Web/Models/Repositories/Users.php
index 63e77df0..c98c5a47 100644
--- a/Web/Models/Repositories/Users.php
+++ b/Web/Models/Repositories/Users.php
@@ -49,12 +49,46 @@ class Users
return $this->toUser($this->users->where("user", $user->getId())->fetch());
}
- function find(string $query): Util\EntityStream
+ function find(string $query, array $pars = [], string $sort = "id DESC"): Util\EntityStream
{
$query = "%$query%";
$result = $this->users->where("CONCAT_WS(' ', first_name, last_name, pseudo, shortcode) LIKE ?", $query)->where("deleted", 0);
- return new Util\EntityStream("User", $result);
+ $notNullParams = [];
+ $nnparamsCount = 0;
+
+ foreach($pars as $paramName => $paramValue) {
+ if($paramName != "before" && $paramName != "after" && $paramName != "gender")
+ $paramValue != NULL ? $notNullParams += ["$paramName" => "%$paramValue%"] : NULL;
+ else
+ $paramValue != NULL ? $notNullParams += ["$paramName" => "$paramValue"] : NULL;
+ }
+
+ $nnparamsCount = sizeof($notNullParams);
+
+ if($nnparamsCount > 0) {
+ !is_null($notNullParams["hometown"]) ? $result->where("hometown LIKE ?", $notNullParams["hometown"]) : NULL;
+ !is_null($notNullParams["city"]) ? $result->where("city LIKE ?", $notNullParams["city"]) : NULL;
+ !is_null($notNullParams["maritalstatus"]) ? $result->where("marital_status LIKE ?", $notNullParams["maritalstatus"]) : NULL;
+ !is_null($notNullParams["status"]) ? $result->where("status LIKE ?", $notNullParams["status"]) : NULL;
+ !is_null($notNullParams["politViews"]) ? $result->where("polit_views LIKE ?", $notNullParams["politViews"]) : NULL;
+ !is_null($notNullParams["email"]) ? $result->where("email_contact LIKE ?", $notNullParams["email"]) : NULL;
+ !is_null($notNullParams["telegram"]) ? $result->where("telegram LIKE ?", $notNullParams["telegram"]) : NULL;
+ !is_null($notNullParams["site"]) ? $result->where("website LIKE ?", $notNullParams["site"]) : NULL;
+ !is_null($notNullParams["address"]) ? $result->where("address LIKE ?", $notNullParams["address"]) : NULL;
+ !is_null($notNullParams["is_online"]) ? $result->where("online >= ?", time() - 900) : NULL;
+ !is_null($notNullParams["interests"]) ? $result->where("interests LIKE ?", $notNullParams["interests"]) : NULL;
+ !is_null($notNullParams["fav_mus"]) ? $result->where("fav_music LIKE ?", $notNullParams["fav_mus"]) : NULL;
+ !is_null($notNullParams["fav_films"]) ? $result->where("fav_films LIKE ?", $notNullParams["fav_films"]) : NULL;
+ !is_null($notNullParams["fav_shows"]) ? $result->where("fav_shows LIKE ?", $notNullParams["fav_shows"]) : NULL;
+ !is_null($notNullParams["fav_books"]) ? $result->where("fav_books LIKE ?", $notNullParams["fav_books"]) : NULL;
+ !is_null($notNullParams["fav_quote"]) ? $result->where("fav_quote LIKE ?", $notNullParams["fav_quote"]) : NULL;
+ !is_null($notNullParams["before"]) ? $result->where("UNIX_TIMESTAMP(since) < ?", $notNullParams["before"]) : NULL;
+ !is_null($notNullParams["after"]) ? $result->where("UNIX_TIMESTAMP(since) > ?", $notNullParams["after"]) : NULL;
+ !is_null($notNullParams["gender"]) ? $result->where("sex ?", $notNullParams["gender"]) : NULL;
+ # !is_null($notNullParams["has_avatar"]) ? $result->related(): NULL;
+ }
+ return new Util\EntityStream("User", $result->order($sort));
}
function getStatistics(): object
diff --git a/Web/Models/Repositories/Videos.php b/Web/Models/Repositories/Videos.php
index 5701b44e..92ebc11c 100644
--- a/Web/Models/Repositories/Videos.php
+++ b/Web/Models/Repositories/Videos.php
@@ -45,4 +45,27 @@ class Videos
{
return sizeof($this->videos->where("owner", $user->getId())->where(["deleted" => 0, "unlisted" => 0]));
}
+
+ function find(string $query = "", array $pars = [], string $sort = "id"): Util\EntityStream
+ {
+ $query = "%$query%";
+
+ $notNullParams = [];
+
+ foreach($pars as $paramName => $paramValue) {
+ if($paramName != "before" && $paramName != "after")
+ $paramValue != NULL ? $notNullParams+=["$paramName" => "%$paramValue%"] : NULL;
+ else
+ $paramValue != NULL ? $notNullParams+=["$paramName" => "$paramValue"] : NULL;
+ }
+
+ $result = $this->videos->where("name OR description LIKE ?", $query)->where("deleted", 0);
+ $nnparamsCount = sizeof($notNullParams);
+
+ if($nnparamsCount > 0) {
+ !is_null($notNullParams["before"]) ? $result->where("created < ?", $notNullParams["before"]) : NULL;
+ !is_null($notNullParams["after"]) ? $result->where("created > ?", $notNullParams["after"]) : NULL;
+ }
+ return new Util\EntityStream("Video", $result->order("$sort"));
+ }
}
diff --git a/Web/Presenters/SearchPresenter.php b/Web/Presenters/SearchPresenter.php
index 2171297c..f029edc8 100644
--- a/Web/Presenters/SearchPresenter.php
+++ b/Web/Presenters/SearchPresenter.php
@@ -1,18 +1,28 @@
users = $users;
- $this->clubs = $clubs;
+ $this->users = $users;
+ $this->clubs = $clubs;
+ $this->posts = new Posts;
+ $this->comments = new Comments;
+ $this->videos = new Videos;
+ $this->apps = new Applications;
+ $this->notes = new Notes;
parent::__construct();
}
@@ -21,6 +31,8 @@ final class SearchPresenter extends OpenVKPresenter
{
$query = $this->queryParam("query") ?? "";
$type = $this->queryParam("type") ?? "users";
+ $sorter = $this->queryParam("sort") ?? "id";
+ $invert = $this->queryParam("invert") == 1 ? "ASC" : "DESC";
$page = (int) ($this->queryParam("p") ?? 1);
$this->willExecuteWriteAction();
@@ -28,11 +40,61 @@ final class SearchPresenter extends OpenVKPresenter
$this->assertUserLoggedIn();
# https://youtu.be/pSAWM5YuXx8
-
- $repos = [ "groups" => "clubs", "users" => "users" ];
+
+ $repos = [
+ "groups" => "clubs",
+ "users" => "users",
+ "posts" => "posts",
+ "comments" => "comments",
+ "videos" => "videos",
+ "audios" => "posts",
+ "apps" => "apps",
+ "notes" => "notes"
+ ];
+
+ switch($sorter) {
+ default:
+ case "id":
+ $sort = "id " . $invert;
+ break;
+ case "random":
+ $sort = "RAND()";
+ break;
+ case "name":
+ $sort = "first_name " . $invert;
+ break;
+ case "rating":
+ $sort = "rating " . $invert;
+ break;
+ }
+
+ $parameters = [
+ "type" => $this->queryParam("type"),
+ "city" => $this->queryParam("city") != "" ? $this->queryParam("city") : NULL,
+ "maritalstatus" => $this->queryParam("maritalstatus") != 0 ? $this->queryParam("maritalstatus") : NULL,
+ "with_photo" => $this->queryParam("with_photo"),
+ "status" => $this->queryParam("status") != "" ? $this->queryParam("status") : NULL,
+ "politViews" => $this->queryParam("politViews") != 0 ? $this->queryParam("politViews") : NULL,
+ "email" => $this->queryParam("email"),
+ "telegram" => $this->queryParam("telegram"),
+ "site" => $this->queryParam("site") != "" ? "https://".$this->queryParam("site") : NULL,
+ "address" => $this->queryParam("address"),
+ "is_online" => $this->queryParam("is_online") == 1 ? 1 : NULL,
+ "interests" => $this->queryParam("interests") != "" ? $this->queryParam("interests") : NULL,
+ "fav_mus" => $this->queryParam("fav_mus") != "" ? $this->queryParam("fav_mus") : NULL,
+ "fav_films" => $this->queryParam("fav_films") != "" ? $this->queryParam("fav_films") : NULL,
+ "fav_shows" => $this->queryParam("fav_shows") != "" ? $this->queryParam("fav_shows") : NULL,
+ "fav_books" => $this->queryParam("fav_books") != "" ? $this->queryParam("fav_books") : NULL,
+ "fav_quote" => $this->queryParam("fav_quote") != "" ? $this->queryParam("fav_quote") : NULL,
+ "hometown" => $this->queryParam("hometown") != "" ? $this->queryParam("hometown") : NULL,
+ "before" => $this->queryParam("datebefore") != "" ? strtotime($this->queryParam("datebefore")) : NULL,
+ "after" => $this->queryParam("dateafter") != "" ? strtotime($this->queryParam("dateafter")) : NULL,
+ "gender" => $this->queryParam("gender") != "" && $this->queryParam("gender") != 2 ? $this->queryParam("gender") : NULL
+ ];
+
$repo = $repos[$type] or $this->throwError(400, "Bad Request", "Invalid search entity $type.");
- $results = $this->{$repo}->find($query);
+ $results = $this->{$repo}->find($query, $parameters, $sort);
$iterator = $results->page($page);
$count = $results->size();
diff --git a/Web/Presenters/templates/@layout.xml b/Web/Presenters/templates/@layout.xml
index f211c2c1..ed593490 100644
--- a/Web/Presenters/templates/@layout.xml
+++ b/Web/Presenters/templates/@layout.xml
@@ -70,28 +70,60 @@
{_header_log_out}
{else}
-
+
-
+
-
+
-
+
-
+
-
+
-
+ {var $atSearch = str_contains($_SERVER['REQUEST_URI'], "/search")}
+
+ {if !$atSearch}
+
+ {else}
+
+
+ {/if}
{/if}
{else}
diff --git a/Web/Presenters/templates/Search/Index.xml b/Web/Presenters/templates/Search/Index.xml
index fe39b4e3..7bae1c7f 100644
--- a/Web/Presenters/templates/Search/Index.xml
+++ b/Web/Presenters/templates/Search/Index.xml
@@ -1,11 +1,7 @@
-{extends "../@listView.xml"}
+{extends "../@layout.xml"}
{block title}
- {if $type === "users"}
- {tr("search_for_people")}
- {else}
- {tr("search_for_groups")}
- {/if}
+ {tr("search_for_$type")}
{if $_GET['query']}
- {$_GET['query']}
{/if}
@@ -13,41 +9,17 @@
{block header}
{=OPENVK_ROOT_CONF["openvk"]["appearance"]["name"]} »
- {if $type === "users"}
- {tr("search_for_people")}
- {else}
- {tr("search_for_groups")}
- {/if}
+ {tr("search_for_$type")}
{/block}
{* BEGIN ELEMENTS DESCRIPTION *}
-{block tabs}
-
-
-
-
-
-
- {tr("results", $count)}
-
-
-{/block}
-
{block link|strip|stripHtml}
- {$x->getURL()}
+ {if $type != "apps"}
+ {$x->getURL()}
+ {else}
+ /app{$x->getId()}
+ {/if}
{/block}
{block preview}
@@ -55,17 +27,72 @@
{/block}
{block name}
-
{$x->getCanonicalName()}
-
+ {if $type != "apps"}
+
{$x->getCanonicalName()}
+ {if $_GET['sort'] == "rating"}({$x->getRating()}%)
+ {elseif $_GET['sort'] == "id" || $_GET['sort'] == "random"}(id{$x->getId()}){/if}
+
+ {else}
+ {$x->getName()}
+ {/if}
{/block}
{block description}
{if $type === "users"}
+ {if !is_null($_GET['status']) && $_GET['status'] != ""}
+
+ {_status}:
+ {$x->getStatus()}
+
+ {/if}
+ {if !is_null($_GET['city']) && $_GET['city'] != "" && $x->getPrivacySetting("page.info.read") > 1}
+
+ {_city}:
+ {$x->getCity()}
+
+ {/if}
+ {if !is_null($_GET['city']) && $_GET['hometown'] != "" && $x->getPrivacySetting("page.info.read") > 1}
+
+ {_hometown}:
+ {$x->getHometown()}
+
+ {/if}
+ {if !is_null($_GET['politViews']) && $_GET['politViews'] != 0 && $x->getPrivacySetting("page.info.read") > 1}
+
+ {_politViews}:
+ {tr("politViews_".$x->getPoliticalViews())}
+
+ {/if}
+ {if !is_null($_GET['email']) && $_GET['email'] != "" && $x->getPrivacySetting("page.info.read") > 1}
+
+ {_email}:
+ {$x->getContactEmail()}
+
+ {/if}
+ {if !is_null($_GET['telegram']) && $_GET['telegram'] != "" && $x->getPrivacySetting("page.info.read") > 1}
+
+ {_telegram}:
+ @{$x->getTelegram()}
+
+ {/if}
+ {if !is_null($_GET['site']) && $_GET['site'] != "" && $x->getPrivacySetting("page.info.read") > 1}
+
+ {_personal_website}:
+ {$x->getWebsite()}
+
+ {/if}
+ {if !is_null($_GET['address']) && $_GET['address'] != "" && $x->getPrivacySetting("page.info.read") > 1}
+
+ {_address}:
+ {$x->getPhysicalAddress()}
+
+ {/if}
+ {if $x->getPrivacySetting("page.info.read") > 1}
{_gender}:
{$x->isFemale() ? tr("female") : tr("male")}
@@ -78,11 +105,14 @@
{_registration_date}:
{$x->getRegistrationTime()}
+ {/if}
{/if}
+ {if $type != "apps"}
{_description}:
+ {/if}
{$x->getDescription() ?? '(' . tr("none") . ')'}
@@ -90,3 +120,220 @@
{/block}
+
+{block content}
+
+ {include "../components/paginator.xml", conf => (object) [
+ "page" => $page,
+ "count" => $count,
+ "amount" => sizeof($data),
+ "perPage" => $perPage ?? OPENVK_DEFAULT_PER_PAGE,
+ "atBottom" => false,
+ ]}
+
+
+ {tr("results", $count)}
+
+
+ {include searchOptions}
+
+ {var $data = is_array($iterator) ? $iterator : iterator_to_array($iterator)}
+
+ {if sizeof($data) > 0}
+ {if $type == "users" || $type == "groups" || $type == "apps"}
+
+ {elseif $type == "posts"}
+ {foreach $data as $dat}
+ {if $dat->getTargetWall() < 0 && $dat->getWallOwner()->isHideFromGlobalFeedEnabled()}
+ {php continue;}
+ {* костыль но я по-другому не придумал *}
+ {else}
+
+ {include "../components/post.xml", post => $dat, commentSection => true, onWallOf => true}
+
+ {/if}
+ {/foreach}
+ {elseif $type == "comments"}
+
+ {include "../components/comment.xml", comment => $dat, linkW => true}
+
+ {elseif $type == "videos"}
+ {foreach $data as $dat}
+ {if $dat->getOwner()->isDeleted()}
+ {php continue;}
+ {else}
+
+ {include "../components/video.xml", video => $dat}
+
+ {/if}
+ {/foreach}
+ {elseif $type == "audios"}
+ хуй
+ {/if}
+ {else}
+ {ifset customErrorMessage}
+ {include customErrorMessage}
+ {else}
+ {include "../components/nothing.xml"}
+ {/ifset}
+ {/if}
+
+
+{/block}
+
+{block searchOptions}
+
+
+
+
+
{_s_order_by}
+
+
+ {_s_order_by_id}
+ {_s_order_by_random}
+ {if $type == "users"}
+ {_s_order_by_name}
+ {if OPENVK_ROOT_CONF["preferences"]["commerce"] != "false"}
+ {_s_order_by_rating}
+ {/if}
+ {/if}
+
+ {_s_order_invert}
+
+
+
+ {if $type !== "groups" && $type !== "apps"} {*В OpenVK не сохраняется дата создания группы*}
+
+
{_s_by_date}
+
+
+ {/if}
+
+ {if $type === "users"}
+
+
+
+
{_gender}
+
+
+
+
+
{_relationship}
+
+
+
+ {tr("relationship_".$i)}
+
+
+
+
+
+
+
{_politViews}
+
+
+
+ {tr("politViews_".$i)}
+
+
+
+
+
+
+
+
+
+
{_s_now_on_site}
+
+ {/if}
+
+
+{/block}
\ No newline at end of file
diff --git a/Web/Presenters/templates/User/View.xml b/Web/Presenters/templates/User/View.xml
index e4d55e9e..73e269f9 100644
--- a/Web/Presenters/templates/User/View.xml
+++ b/Web/Presenters/templates/User/View.xml
@@ -420,11 +420,11 @@
{_hometown}:
- {$user->getHometown()}
+ {$user->getHometown()}
{_politViews}:
- {var $pviews = $user->getPoliticalViews()}{_"politViews_$pviews"}
+ {var $pviews = $user->getPoliticalViews()}{_"politViews_$pviews"}
{_birth_date}:
@@ -470,7 +470,7 @@
{_city}:
- {$user->getCity()}
+ {$user->getCity()}
{_address}:
@@ -484,23 +484,45 @@
{_interests}:
- {$user->getInterests()}
+
+ {var $interests = explode(", ", $user->getInterests())}
+ {foreach $interests as $interest}
+ {$interest} {if $interest != end($interests)},{/if}
+ {/foreach}
+
+
{_favorite_music}:
- {$user->getFavoriteMusic()}
+
+ {var $musics = explode(", ", $user->getFavoriteMusic())}
+ {foreach $musics as $music}
+ {$music} {if $music != end($musics)},{/if}
+ {/foreach}
{_favorite_films}:
- {$user->getFavoriteFilms()}
+
+ {var $films = explode(", ", $user->getFavoriteFilms())}
+ {foreach $films as $film}
+ {$film} {if $film != end($films)},{/if}
+ {/foreach}
{_favorite_shows}:
- {$user->getFavoriteShows()}
+
+ {var $shows = explode(", ", $user->getFavoriteShows())}
+ {foreach $shows as $show}
+ {$show} {if $show != end($shows)},{/if}
+ {/foreach}
{_favorite_books}:
- {$user->getFavoriteBooks()}
+
+ {var $books = explode(", ", $user->getFavoriteBooks())}
+ {foreach $books as $book}
+ {$book} {if $book != end($books)},{/if}
+ {/foreach}
{_favorite_quotes}:
@@ -710,4 +732,4 @@
{else} {* isBanned() *}
{include "banned.xml"}
{/if}
-{/block}
+{/block}
\ No newline at end of file
diff --git a/Web/Presenters/templates/components/comment.xml b/Web/Presenters/templates/components/comment.xml
index 125c1cef..94813a5f 100644
--- a/Web/Presenters/templates/components/comment.xml
+++ b/Web/Presenters/templates/components/comment.xml
@@ -29,11 +29,12 @@