mirror of
https://github.com/YGGverse/YGGtracker.git
synced 2025-01-08 22:17:57 +00:00
implement events pagination
This commit is contained in:
parent
cc6c68957c
commit
995d4bde54
2
.env
2
.env
@ -52,6 +52,8 @@ APP_NAME=YGGtracker
|
||||
APP_LOCALE=en
|
||||
APP_LOCALES=en|cs|eo|fr|ka|de|he|it|lv|pl|pt|ru|es|uk
|
||||
|
||||
APP_PAGINATION=10
|
||||
|
||||
APP_THEME=default
|
||||
APP_THEMES=default
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
parameters:
|
||||
app.version: '%env(APP_VERSION)%'
|
||||
app.name: '%env(APP_NAME)%'
|
||||
app.pagination: '%env(APP_PAGINATION)%'
|
||||
app.trackers: '%env(APP_TRACKERS)%'
|
||||
app.locales: '%env(APP_LOCALES)%'
|
||||
app.themes: '%env(APP_THEMES)%'
|
||||
|
@ -103,13 +103,25 @@ a.label-green:hover {
|
||||
background-color: #65916d;
|
||||
}
|
||||
|
||||
.button {
|
||||
border: transparent 1px solid;
|
||||
.button,
|
||||
a.button,
|
||||
a.button:active,
|
||||
a.button:visited,
|
||||
a.button:hover {
|
||||
background: #5d627d;
|
||||
border: #5d627d 1px solid;
|
||||
color: #ccc;
|
||||
padding: 6px 8px;
|
||||
border-radius: 3px;
|
||||
padding: 8px;
|
||||
opacity: .96;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.button-green {
|
||||
.button-green,
|
||||
a.button-green,
|
||||
a.button-green:active,
|
||||
a.button-green:visited,
|
||||
a.button-green:hover {
|
||||
color: #fff;
|
||||
background-color: #65916d;
|
||||
border: #65916d 1px solid;
|
||||
|
@ -17,11 +17,16 @@ class TorrentController extends AbstractController
|
||||
{
|
||||
// Torrent
|
||||
#[Route(
|
||||
'/{_locale}/torrent/{torrentId}',
|
||||
'/{_locale}/torrent/{torrentId}/{page}',
|
||||
name: 'torrent_info',
|
||||
requirements:
|
||||
[
|
||||
'torrentId' => '\d+'
|
||||
'torrentId' => '\d+',
|
||||
'page' => '\d+',
|
||||
],
|
||||
defaults:
|
||||
[
|
||||
'page' => 1,
|
||||
],
|
||||
methods:
|
||||
[
|
||||
@ -29,6 +34,7 @@ class TorrentController extends AbstractController
|
||||
]
|
||||
)]
|
||||
public function info(
|
||||
int $page,
|
||||
Request $request,
|
||||
TranslatorInterface $translator,
|
||||
UserService $userService,
|
||||
@ -82,6 +88,12 @@ class TorrentController extends AbstractController
|
||||
);
|
||||
}
|
||||
|
||||
// Get total activities
|
||||
$total = $activityService->findActivitiesTotalByTorrentId(
|
||||
$torrent->getId(),
|
||||
$user->getEvents()
|
||||
);
|
||||
|
||||
// Render template
|
||||
return $this->render('default/torrent/info.html.twig', [
|
||||
'torrent' =>
|
||||
@ -166,6 +178,18 @@ class TorrentController extends AbstractController
|
||||
// 'magnet' => $file->getMagnetLink()
|
||||
],
|
||||
'trackers' => explode('|', $this->getParameter('app.trackers')),
|
||||
'activities' => $activityService->findLastActivitiesByTorrentId(
|
||||
$torrent->getId(),
|
||||
$user->getEvents(),
|
||||
$this->getParameter('app.pagination'),
|
||||
($page - 1) * $this->getParameter('app.pagination')
|
||||
),
|
||||
'pagination' =>
|
||||
[
|
||||
'page' => $page,
|
||||
'pages' => ceil($total / $this->getParameter('app.pagination')),
|
||||
'total' => $total
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -39,10 +39,23 @@ class UserController extends AbstractController
|
||||
}
|
||||
|
||||
#[Route(
|
||||
'/{_locale}',
|
||||
name: 'user_dashboard'
|
||||
'/{_locale}/{page}',
|
||||
name: 'user_dashboard',
|
||||
requirements:
|
||||
[
|
||||
'page' => '\d+',
|
||||
],
|
||||
defaults:
|
||||
[
|
||||
'page' => 1,
|
||||
],
|
||||
methods:
|
||||
[
|
||||
'GET'
|
||||
]
|
||||
)]
|
||||
public function index(
|
||||
int $page,
|
||||
Request $request,
|
||||
UserService $userService,
|
||||
ActivityService $activityService
|
||||
@ -54,12 +67,24 @@ class UserController extends AbstractController
|
||||
$activityService
|
||||
);
|
||||
|
||||
$total = $activityService->findActivitiesTotal(
|
||||
$user->getEvents()
|
||||
);
|
||||
|
||||
return $this->render(
|
||||
'default/user/dashboard.html.twig',
|
||||
[
|
||||
'activities' => $activityService->findLastActivities(
|
||||
$user->getEvents()
|
||||
)
|
||||
$user->getEvents(),
|
||||
$this->getParameter('app.pagination'),
|
||||
($page - 1) * $this->getParameter('app.pagination')
|
||||
),
|
||||
'pagination' =>
|
||||
[
|
||||
'page' => $page,
|
||||
'pages' => ceil($total / $this->getParameter('app.pagination')),
|
||||
'total' => $total
|
||||
]
|
||||
]
|
||||
);
|
||||
}
|
||||
@ -181,18 +206,22 @@ class UserController extends AbstractController
|
||||
}
|
||||
|
||||
#[Route(
|
||||
'/{_locale}/profile/{userId}',
|
||||
'/{_locale}/profile/{userId}/{page}',
|
||||
name: 'user_info',
|
||||
defaults: [
|
||||
'_locale' => '%app.locale%',
|
||||
'userId' => null
|
||||
'userId' => 0,
|
||||
'page' => 1,
|
||||
],
|
||||
requirements: [
|
||||
'_locale' => '%app.locales%',
|
||||
'userId' => '\d+',
|
||||
'userId' => '\d+',
|
||||
'page' => '\d+',
|
||||
],
|
||||
)]
|
||||
public function info(
|
||||
int $userId,
|
||||
int $page,
|
||||
Request $request,
|
||||
TranslatorInterface $translator,
|
||||
UserService $userService,
|
||||
@ -216,12 +245,18 @@ class UserController extends AbstractController
|
||||
|
||||
// Init target user
|
||||
if (!$userTarget = $userService->getUser(
|
||||
$request->get('userId') ? $request->get('userId') : $user->getId()
|
||||
$userId ? $userId : $user->getId()
|
||||
))
|
||||
{
|
||||
throw $this->createNotFoundException();
|
||||
}
|
||||
|
||||
// Get total activities
|
||||
$total = $activityService->findActivitiesTotalByUserId(
|
||||
$userTarget->getId(),
|
||||
$user->getEvents()
|
||||
);
|
||||
|
||||
// Render template
|
||||
return $this->render(
|
||||
'default/user/info.html.twig',
|
||||
@ -260,6 +295,18 @@ class UserController extends AbstractController
|
||||
)
|
||||
],
|
||||
'events' => $activityService->getEventsTree(),
|
||||
'activities' => $activityService->findLastActivitiesByUserId(
|
||||
$userTarget->getId(),
|
||||
$user->getEvents(),
|
||||
$this->getParameter('app.pagination'),
|
||||
($page - 1) * $this->getParameter('app.pagination')
|
||||
),
|
||||
'pagination' =>
|
||||
[
|
||||
'page' => $page,
|
||||
'pages' => ceil($total / $this->getParameter('app.pagination')),
|
||||
'total' => $total
|
||||
]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
@ -20,4 +20,65 @@ class ActivityRepository extends ServiceEntityRepository
|
||||
{
|
||||
parent::__construct($registry, Activity::class);
|
||||
}
|
||||
|
||||
public function findActivitiesTotal(
|
||||
array $whitelist
|
||||
): int
|
||||
{
|
||||
return $this->createQueryBuilder('a')
|
||||
->select('count(a.id)')
|
||||
->where('a.event IN (:event)')
|
||||
->setParameter(':event', $whitelist)
|
||||
->getQuery()
|
||||
->getSingleScalarResult()
|
||||
;
|
||||
}
|
||||
|
||||
public function findActivitiesTotalByUserId(
|
||||
int $userId,
|
||||
array $whitelist
|
||||
): int
|
||||
{
|
||||
return $this->createQueryBuilder('a')
|
||||
->select('count(a.id)')
|
||||
->where('a.userId = :userId')
|
||||
->andWhere('a.event IN (:event)')
|
||||
->setParameter(':userId', $userId)
|
||||
->setParameter(':event', $whitelist)
|
||||
->getQuery()
|
||||
->getSingleScalarResult()
|
||||
;
|
||||
}
|
||||
|
||||
public function findActivitiesTotalByTorrentId(
|
||||
int $torrentId,
|
||||
array $whitelist
|
||||
): int
|
||||
{
|
||||
return $this->createQueryBuilder('a')
|
||||
->select('count(a.id)')
|
||||
->where('a.torrentId = :torrentId')
|
||||
->andWhere('a.event IN (:event)')
|
||||
->setParameter(':torrentId', $torrentId)
|
||||
->setParameter(':event', $whitelist)
|
||||
->getQuery()
|
||||
->getSingleScalarResult()
|
||||
;
|
||||
}
|
||||
|
||||
public function findActivitiesTotalByArticleId(
|
||||
int $articleId,
|
||||
array $whitelist
|
||||
): int
|
||||
{
|
||||
return $this->createQueryBuilder('a')
|
||||
->select('count(a.id)')
|
||||
->where('a.articleId = :articleId')
|
||||
->andWhere('a.event IN (:event)')
|
||||
->setParameter(':articleId', $articleId)
|
||||
->setParameter(':event', $whitelist)
|
||||
->getQuery()
|
||||
->getSingleScalarResult()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
@ -361,7 +361,9 @@ class ActivityService
|
||||
}
|
||||
|
||||
public function findLastActivities(
|
||||
array $whitelist
|
||||
array $whitelist,
|
||||
int $limit = 10,
|
||||
int $offset = 0
|
||||
): array
|
||||
{
|
||||
return $this->entityManagerInterface
|
||||
@ -372,13 +374,17 @@ class ActivityService
|
||||
],
|
||||
[
|
||||
'id' => 'DESC'
|
||||
]
|
||||
],
|
||||
$limit,
|
||||
$offset
|
||||
);
|
||||
}
|
||||
|
||||
public function findLastActivitiesByUserId(
|
||||
int $userId,
|
||||
array $whitelist
|
||||
array $whitelist,
|
||||
int $limit = 10,
|
||||
int $offset = 0
|
||||
): array
|
||||
{
|
||||
return $this->entityManagerInterface
|
||||
@ -386,11 +392,105 @@ class ActivityService
|
||||
->findBy(
|
||||
[
|
||||
'userId' => $userId,
|
||||
'event' => $whitelist
|
||||
'event' => $whitelist,
|
||||
],
|
||||
[
|
||||
'id' => 'DESC'
|
||||
]
|
||||
],
|
||||
$limit,
|
||||
$offset
|
||||
);
|
||||
}
|
||||
|
||||
public function findLastActivitiesByTorrentId(
|
||||
int $torrentId,
|
||||
array $whitelist,
|
||||
int $limit = 10,
|
||||
int $offset = 0
|
||||
): array
|
||||
{
|
||||
return $this->entityManagerInterface
|
||||
->getRepository(Activity::class)
|
||||
->findBy(
|
||||
[
|
||||
'torrentId' => $torrentId,
|
||||
'event' => $whitelist,
|
||||
],
|
||||
[
|
||||
'id' => 'DESC'
|
||||
],
|
||||
$limit,
|
||||
$offset
|
||||
);
|
||||
}
|
||||
|
||||
public function findLastActivitiesByArticleId(
|
||||
int $articleId,
|
||||
array $whitelist,
|
||||
int $limit = 10,
|
||||
int $offset = 0
|
||||
): array
|
||||
{
|
||||
return $this->entityManagerInterface
|
||||
->getRepository(Activity::class)
|
||||
->findBy(
|
||||
[
|
||||
'articleId' => $articleId,
|
||||
'event' => $whitelist,
|
||||
],
|
||||
[
|
||||
'id' => 'DESC'
|
||||
],
|
||||
$limit,
|
||||
$offset
|
||||
);
|
||||
}
|
||||
|
||||
public function findActivitiesTotal(
|
||||
array $whitelist
|
||||
): int
|
||||
{
|
||||
return $this->entityManagerInterface
|
||||
->getRepository(Activity::class)
|
||||
->findActivitiesTotal($whitelist);
|
||||
}
|
||||
|
||||
public function findActivitiesTotalByUserId(
|
||||
int $userId,
|
||||
array $whitelist
|
||||
): int
|
||||
{
|
||||
return $this->entityManagerInterface
|
||||
->getRepository(Activity::class)
|
||||
->findActivitiesTotalByUserId(
|
||||
$userId,
|
||||
$whitelist
|
||||
);
|
||||
}
|
||||
|
||||
public function findActivitiesTotalByTorrentId(
|
||||
int $torrentId,
|
||||
array $whitelist
|
||||
): int
|
||||
{
|
||||
return $this->entityManagerInterface
|
||||
->getRepository(Activity::class)
|
||||
->findActivitiesTotalByTorrentId(
|
||||
$torrentId,
|
||||
$whitelist
|
||||
);
|
||||
}
|
||||
|
||||
public function findActivitiesTotalByArticleId(
|
||||
int $articleId,
|
||||
array $whitelist
|
||||
): int
|
||||
{
|
||||
return $this->entityManagerInterface
|
||||
->getRepository(Activity::class)
|
||||
->findActivitiesTotalByArticleId(
|
||||
$articleId,
|
||||
$whitelist
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
{% endmacro %}
|
||||
{% from _self import recursive_file_tree %}
|
||||
{% extends 'default/layout.html.twig' %}
|
||||
{% block title %}{{ 'Torrent' | trans }} #{{ torrent.id }} - {{ name }}{% endblock %}
|
||||
{% block title %}{{ 'Torrent' | trans }} #{{ torrent.id }}{% if pagination.page > 1 %} - {{ 'Page' | trans }} {{ pagination.page }}{% endif %} - {{ name }}{% endblock %}
|
||||
{% block main_content %}
|
||||
<div class="padding-24-px margin-y-8-px border-radius-3-px background-color-night">
|
||||
<div class="padding-b-16-px">
|
||||
@ -322,4 +322,50 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if activities %}
|
||||
<a name="activity"></a>
|
||||
{% for activity in activities %}
|
||||
<div class="padding-16-px margin-y-8-px border-radius-3-px background-color-night">
|
||||
{{ render(controller(
|
||||
'App\\Controller\\ActivityController::event',
|
||||
{ activity : activity }
|
||||
)) }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if pagination.pages > 1 %}
|
||||
<div class="row margin-t-16-px">
|
||||
<div class="column width-50 padding-t-16-px">
|
||||
|
||||
{# @TODO
|
||||
<a class="text-color-night" href="#" title="RSS">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm1.5 2.5c5.523 0 10 4.477 10 10a1 1 0 1 1-2 0 8 8 0 0 0-8-8 1 1 0 0 1 0-2zm0 4a6 6 0 0 1 6 6 1 1 0 1 1-2 0 4 4 0 0 0-4-4 1 1 0 0 1 0-2zm.5 7a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z"/>
|
||||
</svg>
|
||||
</a>
|
||||
#}
|
||||
</div>
|
||||
<div class="column width-50 text-right">
|
||||
{% if pagination.pages > 1 %}
|
||||
{{ 'Page' | trans | lower }} {{ pagination.page }} / {{ pagination.pages }}
|
||||
{% if pagination.page > 1 %}
|
||||
{% if pagination.page == 2 %}
|
||||
<a rel="nofollow" class="button margin-l-8-px" href="{{ path('torrent_info', { torrentId : torrent.id }) }}#activity">
|
||||
{{ 'Back' | trans | lower }}
|
||||
</a>
|
||||
{% else %}
|
||||
<a rel="nofollow" class="button margin-l-8-px" href="{{ path('torrent_info', { torrentId : torrent.id, page : pagination.page - 1 }) }}#activity">
|
||||
{{ 'Back' | trans | lower }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if pagination.page < pagination.pages %}
|
||||
<a rel="nofollow" class="button margin-l-8-px" href="{{ path('torrent_info', { torrentId : torrent.id, page : pagination.page + 1 }) }}#activity">
|
||||
{{ 'Next' | trans | lower }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
@ -1,5 +1,5 @@
|
||||
{% extends 'default/layout.html.twig' %}
|
||||
{% block title %}{{ 'Activity' | trans }} - {{ name }}{% endblock %}
|
||||
{% block title %}{{ 'Activity' | trans }}{% if pagination.page > 1 %} - {{ 'Page' | trans }} {{ pagination.page }}{% endif %} - {{ name }}{% endblock %}
|
||||
{% block main_content %}
|
||||
{% for activity in activities %}
|
||||
<div class="padding-16-px margin-y-8-px border-radius-3-px background-color-night">
|
||||
@ -9,4 +9,39 @@
|
||||
)) }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if pagination.pages > 1 %}
|
||||
<div class="row margin-t-16-px">
|
||||
<div class="column width-50 padding-t-16-px">
|
||||
|
||||
{# @TODO
|
||||
<a class="text-color-night" href="#" title="RSS">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm1.5 2.5c5.523 0 10 4.477 10 10a1 1 0 1 1-2 0 8 8 0 0 0-8-8 1 1 0 0 1 0-2zm0 4a6 6 0 0 1 6 6 1 1 0 1 1-2 0 4 4 0 0 0-4-4 1 1 0 0 1 0-2zm.5 7a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z"/>
|
||||
</svg>
|
||||
</a>
|
||||
#}
|
||||
</div>
|
||||
<div class="column width-50 text-right">
|
||||
{% if pagination.pages > 1 %}
|
||||
{{ 'Page' | trans | lower }} {{ pagination.page }} / {{ pagination.pages }}
|
||||
{% if pagination.page > 1 %}
|
||||
{% if pagination.page == 2 %}
|
||||
<a rel="nofollow" class="button margin-l-8-px" href="{{ path('user_dashboard') }}">
|
||||
{{ 'Back' | trans | lower }}
|
||||
</a>
|
||||
{% else %}
|
||||
<a rel="nofollow" class="button margin-l-8-px" href="{{ path('user_dashboard', { page : pagination.page - 1 }) }}">
|
||||
{{ 'Back' | trans | lower }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if pagination.page < pagination.pages %}
|
||||
<a rel="nofollow" class="button margin-l-8-px" href="{{ path('user_dashboard', { page : pagination.page + 1 }) }}">
|
||||
{{ 'Next' | trans | lower }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
@ -1,5 +1,5 @@
|
||||
{% extends 'default/layout.html.twig' %}
|
||||
{% block title %}{{ 'User'|trans }} #{{ user.id }} - {{ name }}{% endblock %}
|
||||
{% block title %}{{ 'User'|trans }} #{{ user.id }}{% if pagination.page > 1 %} - {{ 'Page' | trans }} {{ pagination.page }}{% endif %} - {{ name }}{% endblock %}
|
||||
{% block main_content %}
|
||||
<div class="padding-24-px margin-y-8-px border-radius-3-px background-color-night">
|
||||
<div class="margin-b-16-px text-center">
|
||||
@ -219,12 +219,15 @@
|
||||
</table>
|
||||
</div>
|
||||
{% if user.activities %}
|
||||
<a name="activity"></a>
|
||||
{#
|
||||
<div class="padding-x-24-px padding-y-8-px margin-y-16-px">
|
||||
<h2>{{ 'Last activity' | trans }}</h2>
|
||||
<sup>
|
||||
<a href="#">RSS</a>
|
||||
</sup>
|
||||
</div>
|
||||
#}
|
||||
{% for activity in user.activities %}
|
||||
<div class="padding-x-24-px padding-y-16-px margin-y-8-px border-radius-3-px background-color-night">
|
||||
{{ render(controller(
|
||||
@ -233,5 +236,40 @@
|
||||
)) }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if pagination.pages > 1 %}
|
||||
<div class="row margin-t-16-px">
|
||||
<div class="column width-50 padding-t-16-px">
|
||||
|
||||
{# @TODO
|
||||
<a class="text-color-night" href="#" title="RSS">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm1.5 2.5c5.523 0 10 4.477 10 10a1 1 0 1 1-2 0 8 8 0 0 0-8-8 1 1 0 0 1 0-2zm0 4a6 6 0 0 1 6 6 1 1 0 1 1-2 0 4 4 0 0 0-4-4 1 1 0 0 1 0-2zm.5 7a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z"/>
|
||||
</svg>
|
||||
</a>
|
||||
#}
|
||||
</div>
|
||||
<div class="column width-50 text-right">
|
||||
{% if pagination.pages > 1 %}
|
||||
{{ 'Page' | trans | lower }} {{ pagination.page }} / {{ pagination.pages }}
|
||||
{% if pagination.page > 1 %}
|
||||
{% if pagination.page == 2 %}
|
||||
<a rel="nofollow" class="button margin-l-8-px" href="{{ path('user_info', { userId : user.id }) }}#activity">
|
||||
{{ 'Back' | trans | lower }}
|
||||
</a>
|
||||
{% else %}
|
||||
<a rel="nofollow" class="button margin-l-8-px" href="{{ path('user_info', { userId : user.id, page : pagination.page - 1 }) }}#activity">
|
||||
{{ 'Back' | trans | lower }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if pagination.page < pagination.pages %}
|
||||
<a rel="nofollow" class="button margin-l-8-px" href="{{ path('user_info', { userId : user.id, page : pagination.page + 1 }) }}#activity">
|
||||
{{ 'Next' | trans | lower }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
Loading…
Reference in New Issue
Block a user