Added private Forum Leaderboard page.
This commit is contained in:
parent
9451cc384e
commit
a7b82293a6
16 changed files with 355 additions and 27 deletions
10
assets/less/classes/forum/forum.less
Normal file
10
assets/less/classes/forum/forum.less
Normal file
|
@ -0,0 +1,10 @@
|
|||
@import "actions";
|
||||
@import "categories";
|
||||
@import "category";
|
||||
@import "confirm";
|
||||
@import "header";
|
||||
@import "post";
|
||||
@import "status";
|
||||
@import "topic";
|
||||
@import "topics";
|
||||
@import "leaderboard/leaderboard";
|
8
assets/less/classes/forum/leaderboard/categories.less
Normal file
8
assets/less/classes/forum/leaderboard/categories.less
Normal file
|
@ -0,0 +1,8 @@
|
|||
.forum__leaderboard__categories {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
white-space: nowrap;
|
||||
margin: 2px 0;
|
||||
scrollbar-width: thin;
|
||||
}
|
19
assets/less/classes/forum/leaderboard/category.less
Normal file
19
assets/less/classes/forum/leaderboard/category.less
Normal file
|
@ -0,0 +1,19 @@
|
|||
.forum__leaderboard__category {
|
||||
display: inline-block;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
margin: 2px;
|
||||
padding: 2px 5px;
|
||||
border-radius: 4px;
|
||||
transition: background-color .2s;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: fade(#fff, 20%);
|
||||
}
|
||||
|
||||
&--active,
|
||||
&:active {
|
||||
background-color: fade(#fff, 10%);
|
||||
}
|
||||
}
|
4
assets/less/classes/forum/leaderboard/leaderboard.less
Normal file
4
assets/less/classes/forum/leaderboard/leaderboard.less
Normal file
|
@ -0,0 +1,4 @@
|
|||
@import "categories";
|
||||
@import "category";
|
||||
@import "markdown";
|
||||
@import "user";
|
8
assets/less/classes/forum/leaderboard/markdown.less
Normal file
8
assets/less/classes/forum/leaderboard/markdown.less
Normal file
|
@ -0,0 +1,8 @@
|
|||
.forum__leaderboard__markdown {
|
||||
display: block;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
max-width: 100%;
|
||||
min-height: 500px;
|
||||
margin: 2px auto;
|
||||
}
|
83
assets/less/classes/forum/leaderboard/user.less
Normal file
83
assets/less/classes/forum/leaderboard/user.less
Normal file
|
@ -0,0 +1,83 @@
|
|||
.forum__leaderboard__user {
|
||||
margin: 2px 0;
|
||||
font-size: 1.2em;
|
||||
|
||||
&--rank-1 {
|
||||
font-size: 1.6em;
|
||||
}
|
||||
|
||||
&--rank-2,
|
||||
&--rank-3 {
|
||||
font-size: 1.4em;
|
||||
}
|
||||
|
||||
&__background {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
&__content {
|
||||
display: flex;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&__rank {
|
||||
height: 40px;
|
||||
min-width: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 700;
|
||||
flex: 0 0 auto;
|
||||
|
||||
&:before {
|
||||
content: "#";
|
||||
}
|
||||
}
|
||||
|
||||
&--rank-1 &__rank {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
&__avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: 2px 7px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
&--rank-1 &__avatar {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
&__username {
|
||||
flex: 1 1 auto;
|
||||
line-height: 30px;
|
||||
padding: 5px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
&--rank-1 &__username {
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
&__posts {
|
||||
flex: 0 0 auto;
|
||||
min-width: 150px;
|
||||
border-left: 1px solid fade(#fff, 20%);
|
||||
line-height: 30px;
|
||||
padding: 5px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
&--rank-1 &__posts {
|
||||
line-height: 40px;
|
||||
}
|
||||
}
|
|
@ -194,15 +194,7 @@ html {
|
|||
@import "classes/news/post"; // post needs to be able to override sidebar
|
||||
|
||||
// Forums
|
||||
@import "classes/forum/actions";
|
||||
@import "classes/forum/categories";
|
||||
@import "classes/forum/category";
|
||||
@import "classes/forum/confirm";
|
||||
@import "classes/forum/post";
|
||||
@import "classes/forum/topic";
|
||||
@import "classes/forum/topics";
|
||||
@import "classes/forum/status";
|
||||
@import "classes/forum/header";
|
||||
@import "classes/forum/forum";
|
||||
|
||||
// User stuff
|
||||
@import "classes/usercard";
|
||||
|
|
|
@ -50,6 +50,7 @@ require_once 'src/twitter.php';
|
|||
require_once 'src/url.php';
|
||||
require_once 'src/zalgo.php';
|
||||
require_once 'src/Forum/forum.php';
|
||||
require_once 'src/Forum/leaderboard.php';
|
||||
require_once 'src/Forum/perms.php';
|
||||
require_once 'src/Forum/post.php';
|
||||
require_once 'src/Forum/topic.php';
|
||||
|
|
54
public/forum/leaderboard.php
Normal file
54
public/forum/leaderboard.php
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
require_once '../../misuzu.php';
|
||||
|
||||
if (!perms_check_user(MSZ_PERMS_FORUM, user_session_current('user_id'), MSZ_PERM_FORUM_VIEW_LEADERBOARD)) {
|
||||
echo render_error(403);
|
||||
return;
|
||||
}
|
||||
|
||||
$leaderboardMode = !empty($_GET['mode']) && is_string($_GET['mode']) && ctype_lower($_GET['mode']) ? $_GET['mode'] : '';
|
||||
$leaderboardId = !empty($_GET['id']) && is_string($_GET['id'])
|
||||
&& ctype_digit($_GET['id'])
|
||||
? $_GET['id']
|
||||
: MSZ_FORUM_LEADERBOARD_CATEGORY_ALL;
|
||||
$leaderboardIdLength = strlen($leaderboardId);
|
||||
|
||||
$leaderboardYear = $leaderboardIdLength === 4 || $leaderboardIdLength === 6 ? substr($leaderboardId, 0, 4) : null;
|
||||
$leaderboardMonth = $leaderboardIdLength === 6 ? substr($leaderboardId, 4, 2) : null;
|
||||
|
||||
$leaderboards = forum_leaderboard_categories();
|
||||
$leaderboard = forum_leaderboard_listing($leaderboardYear, $leaderboardMonth);
|
||||
|
||||
$leaderboardName = 'All Time';
|
||||
|
||||
if($leaderboardYear) {
|
||||
$leaderboardName = "Leaderboard {$leaderboardYear}";
|
||||
|
||||
if($leaderboardMonth) {
|
||||
$leaderboardName .= "-{$leaderboardMonth}";
|
||||
}
|
||||
}
|
||||
|
||||
if($leaderboardMode === 'markdown') {
|
||||
$markdown = <<<MD
|
||||
# {$leaderboardName}
|
||||
|
||||
| Rank | Usename | Post count |
|
||||
| ----:|:------- | ----------:|
|
||||
|
||||
MD;
|
||||
|
||||
foreach($leaderboard as $user) {
|
||||
$markdown .= sprintf("| %s | [%s](%s%s) | %s |\r\n", $user['rank'], $user['username'], url_prefix(false), url('user-profile', ['user' => $user['user_id']]), $user['posts']);
|
||||
}
|
||||
|
||||
tpl_var('leaderboard_markdown', $markdown);
|
||||
}
|
||||
|
||||
echo tpl_render('forum.leaderboard', [
|
||||
'leaderboard_id' => $leaderboardId,
|
||||
'leaderboard_name' => $leaderboardName,
|
||||
'leaderboard_categories' => $leaderboards,
|
||||
'leaderboard_data' => $leaderboard,
|
||||
'leaderboard_mode' => $leaderboardMode,
|
||||
]);
|
|
@ -3,6 +3,7 @@
|
|||
* GLOBAL PERMISSIONS *
|
||||
**********************/
|
||||
define('MSZ_PERM_FORUM_MANAGE_FORUMS', 1);
|
||||
define('MSZ_PERM_FORUM_VIEW_LEADERBOARD', 2);
|
||||
|
||||
/*************************
|
||||
* PER-FORUM PERMISSIONS *
|
||||
|
|
93
src/Forum/leaderboard.php
Normal file
93
src/Forum/leaderboard.php
Normal file
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
define('MSZ_FORUM_LEADERBOARD_START_YEAR', 2018);
|
||||
define('MSZ_FORUM_LEADERBOARD_START_MONTH', 12);
|
||||
define('MSZ_FORUM_LEADERBOARD_CATEGORY_ALL', 0);
|
||||
|
||||
function forum_leaderboard_year_valid(?int $year): bool
|
||||
{
|
||||
return !is_null($year) && $year >= MSZ_FORUM_LEADERBOARD_START_YEAR && $year <= date('Y');
|
||||
}
|
||||
|
||||
function forum_leaderboard_month_valid(?int $year, ?int $month): bool
|
||||
{
|
||||
if (is_null($month) || !forum_leaderboard_year_valid($year) || $month < 1 || $month > 12) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$combo = sprintf('%04d%02d', $year, $month);
|
||||
$start = sprintf('%04d%02d', MSZ_FORUM_LEADERBOARD_START_YEAR, MSZ_FORUM_LEADERBOARD_START_MONTH);
|
||||
$current = date('Ym');
|
||||
|
||||
return $combo >= $start && $combo <= $current;
|
||||
}
|
||||
|
||||
function forum_leaderboard_categories(): array
|
||||
{
|
||||
$categories = [
|
||||
MSZ_FORUM_LEADERBOARD_CATEGORY_ALL => 'All Time',
|
||||
];
|
||||
|
||||
$currentYear = date('Y');
|
||||
$currentMonth = date('m');
|
||||
|
||||
for ($i = MSZ_FORUM_LEADERBOARD_START_YEAR; $i <= $currentYear; $i++) {
|
||||
$categories[$i] = sprintf('Leaderboard %d', $i);
|
||||
}
|
||||
|
||||
for ($i = MSZ_FORUM_LEADERBOARD_START_YEAR, $j = MSZ_FORUM_LEADERBOARD_START_MONTH;;) {
|
||||
$categories[sprintf('%d%02d', $i, $j)] = sprintf('Leaderboard %d-%02d', $i, $j);
|
||||
|
||||
if ($j >= 12) {
|
||||
$i++; $j = 1;
|
||||
} else $j++;
|
||||
|
||||
if ($i >= $currentYear && $j > $currentMonth)
|
||||
break;
|
||||
}
|
||||
|
||||
return $categories;
|
||||
}
|
||||
|
||||
function forum_leaderboard_listing(?int $year = null, ?int $month = null): array
|
||||
{
|
||||
$hasYear = forum_leaderboard_year_valid($year);
|
||||
$hasMonth = $hasYear && forum_leaderboard_month_valid($year, $month);
|
||||
|
||||
$rawLeaderboard = db_fetch_all(db_query(sprintf(
|
||||
'
|
||||
SELECT
|
||||
u.`user_id`, u.`username`,
|
||||
COUNT(fp.`post_id`) as `posts`
|
||||
FROM `msz_users` AS u
|
||||
INNER JOIN `msz_forum_posts` AS fp
|
||||
ON fp.`user_id` = u.`user_id`
|
||||
WHERE fp.`post_deleted` IS NULL
|
||||
%s
|
||||
GROUP BY u.`user_id`
|
||||
HAVING `posts` > 0
|
||||
ORDER BY `posts` DESC
|
||||
',
|
||||
!$hasYear ? '' : sprintf(
|
||||
'AND DATE(fp.`post_created`) BETWEEN \'%1$04d-%2$02d-01\' AND \'%1$04d-%3$02d-31\'',
|
||||
$year,
|
||||
$hasMonth ? $month : 1,
|
||||
$hasMonth ? $month : 12
|
||||
)
|
||||
)));
|
||||
|
||||
$leaderboard = [];
|
||||
$ranking = 0;
|
||||
$lastPosts = null;
|
||||
|
||||
foreach ($rawLeaderboard as $entry) {
|
||||
if (is_null($lastPosts) || $lastPosts > $entry['posts']) {
|
||||
$ranking++;
|
||||
$lastPosts = $entry['posts'];
|
||||
}
|
||||
|
||||
$entry['rank'] = $ranking;
|
||||
$leaderboard[] = $entry;
|
||||
}
|
||||
|
||||
return $leaderboard;
|
||||
}
|
|
@ -282,6 +282,11 @@ function manage_perms_list(array $rawPerms): array
|
|||
'title' => 'Can manage forum sections.',
|
||||
'perm' => MSZ_PERM_FORUM_MANAGE_FORUMS,
|
||||
],
|
||||
[
|
||||
'section' => 'view-leaderboard',
|
||||
'title' => 'Can view the forum leaderboard live.',
|
||||
'perm' => MSZ_PERM_FORUM_VIEW_LEADERBOARD,
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
|
|
|
@ -202,7 +202,7 @@ function perms_check(int $perms, int $perm): bool
|
|||
return ($perms & $perm) > 0;
|
||||
}
|
||||
|
||||
function perms_check_user(string $prefix, int $userId, int $perm): bool
|
||||
function perms_check_user(string $prefix, ?int $userId, int $perm): bool
|
||||
{
|
||||
return perms_check(perms_get_user($prefix, $userId), $perm);
|
||||
return $userId > 0 && perms_check(perms_get_user($prefix, $userId), $perm);
|
||||
}
|
||||
|
|
21
src/url.php
21
src/url.php
|
@ -32,6 +32,7 @@ define('MSZ_URLS', [
|
|||
'news-category' => ['/news.php', ['c' => '<category>', 'page' => '<page>']],
|
||||
|
||||
'forum-index' => ['/forum'],
|
||||
'forum-leaderboard' => ['/forum/leaderboard.php', ['id' => '<id>', 'mode' => '<mode>']],
|
||||
'forum-mark-global' => ['/forum/index.php', ['m' => 'mark', 'c' => '{forum_mark}']],
|
||||
'forum-mark-single' => ['/forum/index.php', ['m' => 'mark', 'c' => '{forum_mark}', 'f' => '<forum>']],
|
||||
'forum-topic-new' => ['/forum/posting.php', ['f' => '<forum>']],
|
||||
|
@ -224,3 +225,23 @@ function url_proxy_media(?string $url): ?string
|
|||
|
||||
return url('media-proxy', compact('hash', 'url'));
|
||||
}
|
||||
|
||||
function url_prefix(bool $trailingSlash = true): string
|
||||
{
|
||||
return 'http' . (empty($_SERVER['HTTPS']) ? '' : 's') . '://' . $_SERVER['HTTP_HOST'] . ($trailingSlash ? '/' : '');
|
||||
}
|
||||
|
||||
function is_local_url(string $url): bool
|
||||
{
|
||||
$length = mb_strlen($url);
|
||||
|
||||
if ($length < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($url[0] === '/' && ($length > 1 ? $url[1] !== '/' : true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return starts_with($url, url_prefix());
|
||||
}
|
||||
|
|
45
templates/forum/leaderboard.twig
Normal file
45
templates/forum/leaderboard.twig
Normal file
|
@ -0,0 +1,45 @@
|
|||
{% extends 'forum/master.twig' %}
|
||||
{% from 'forum/macros.twig' import forum_header %}
|
||||
|
||||
{% set title = 'Forum Leaderboard » ' ~ leaderboard_name %}
|
||||
{% set canonical_url = url('forum-leaderboard', {
|
||||
'id': leaderboard_id,
|
||||
'mode': '',
|
||||
}) %}
|
||||
|
||||
{% block content %}
|
||||
{{ forum_header(title, [], false, canonical_url, [
|
||||
{
|
||||
'html': '<i class="fab fa-markdown fa-fw"></i> Markdown',
|
||||
'url': url('forum-leaderboard', {'id': leaderboard_id, 'mode': 'markdown'}),
|
||||
'display': leaderboard_mode != 'markdown',
|
||||
},
|
||||
{
|
||||
'html': '<i class="fas fa-table fa-fw"></i> Table',
|
||||
'url': url('forum-leaderboard', {'id': leaderboard_id}),
|
||||
'display': leaderboard_mode == 'markdown',
|
||||
},
|
||||
]) }}
|
||||
|
||||
<div class="container forum__leaderboard__categories">
|
||||
{% for id, name in leaderboard_categories %}
|
||||
<a href="{{ url('forum-leaderboard', {'id': id, 'mode': leaderboard_mode}) }}" class="forum__leaderboard__category{% if leaderboard_id == id %} forum__leaderboard__category--active{% endif %}">{{ name }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% if leaderboard_mode == 'markdown' %}
|
||||
<textarea class="input__textarea forum__leaderboard__markdown">{{ leaderboard_markdown }}</textarea>
|
||||
{% else %}
|
||||
{% for user in leaderboard_data %}
|
||||
<div class="container forum__leaderboard__user forum__leaderboard__user--rank-{{ user.rank }}">
|
||||
<a href="{{ url('user-profile', {'user': user.user_id}) }}" class="forum__leaderboard__user__background"></a>
|
||||
<div class="forum__leaderboard__user__content">
|
||||
<div class="forum__leaderboard__user__rank">{{ user.rank|number_format }}</div>
|
||||
<div class="avatar forum__leaderboard__user__avatar" style="background-image:url('{{ url('user-avatar', {'user': user.user_id, 'r': 80}) }}')"></div>
|
||||
<div class="forum__leaderboard__user__username">{{ user.username }}</div>
|
||||
<div class="forum__leaderboard__user__posts">{{ user.posts|number_format }} posts</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
16
utility.php
16
utility.php
|
@ -64,22 +64,6 @@ function pdo_prepare_array(array $keys, bool $useKeys = false, string $format =
|
|||
return implode(', ', $parts);
|
||||
}
|
||||
|
||||
function is_local_url(string $url): bool
|
||||
{
|
||||
$length = mb_strlen($url);
|
||||
|
||||
if ($length < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($url[0] === '/' && ($length > 1 ? $url[1] !== '/' : true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$prefix = 'http' . (empty($_SERVER['HTTPS']) ? '' : 's') . '://' . $_SERVER['HTTP_HOST'] . '/';
|
||||
return starts_with($url, $prefix);
|
||||
}
|
||||
|
||||
function render_error(int $code, string $template = 'errors.%d'): string
|
||||
{
|
||||
return render_info(null, $code, $template);
|
||||
|
|
Loading…
Add table
Reference in a new issue