Started centralising URLs.

This commit is contained in:
flash 2019-01-24 21:54:24 +01:00
parent 7252a7f4cb
commit d146cbae61
33 changed files with 361 additions and 175 deletions

View file

@ -46,6 +46,7 @@ require_once 'src/pagination.php';
require_once 'src/perms.php';
require_once 'src/string.php';
require_once 'src/tpl.php';
require_once 'src/url.php';
require_once 'src/zalgo.php';
require_once 'src/Forum/forum.php';
require_once 'src/Forum/perms.php';

View file

@ -66,26 +66,26 @@ switch ($authMode) {
case 'reset':
// If we're logged in, redirect to the password/e-mail change part in settings instead.
if (user_session_active()) {
header('Location: /settings.php#account');
header(sprintf('Location: %s', url('settings-mode', ['mode' => 'account'])));
break;
}
if (!$canResetPassword) {
header('Location: /');
header(sprintf('Location: %s', url('index')));
return;
}
$resetUserId = (int)($_POST['user'] ?? $_GET['u'] ?? 0);
if (empty($resetUserId)) {
header('Location: /auth.php?m=forgot');
header(sprintf('Location: %s', url('auth-forgot')));
break;
}
$resetUsername = user_username_from_id($resetUserId);
if (empty($resetUsername)) {
header('Location: /auth.php');
header(sprintf('Location: %s', url('auth-login')));
break;
}
@ -124,7 +124,7 @@ switch ($authMode) {
user_recovery_token_invalidate($resetUserId, $authVerification);
header("Location: /auth.php?m=login&u={$resetUserId}");
header(sprintf('Location: %s', url('auth-login')));
break;
}
@ -192,7 +192,7 @@ MSG;
}
}
header("Location: ?m=reset&u={$forgotUser['user_id']}");
header(sprintf('Location: %s', url('auth-reset', ['user' => $forgotUser['user_id']])));
break;
}
@ -201,7 +201,7 @@ MSG;
case 'login':
if (user_session_active()) {
header('Location: /');
header('Location: ' . url('index'));
break;
}
@ -272,7 +272,7 @@ MSG;
set_cookie_m('sid', $sessionKey, $cookieLife);
if (!is_local_url($authRedirect)) {
$authRedirect = '/';
$authRedirect = url('index');
}
header("Location: {$authRedirect}");
@ -290,7 +290,7 @@ MSG;
case 'register':
if (user_session_active()) {
header('Location: /');
header('Location: ' . url('index'));
}
$authRegistrationError = '';

View file

@ -11,7 +11,7 @@ switch ($_GET['m'] ?? '') {
$markAction = forum_mark_read($markEntireForum ? null : $forumId, user_session_current('user_id', 0));
}
header('Location: /forum' . (!$markAction || $markEntireForum ? '' : url_construct('/forum.php', ['f' => $forumId])));
header('Location: /forum' . (!$markAction || $markEntireForum ? '' : url('forum-category', ['forum' => $forumId])));
break;
default:

View file

@ -116,7 +116,10 @@ switch ($postMode) {
if (!$isXHR) {
if ($postRequestVerified && isset($_GET['confirm']) && $_GET['confirm'] !== '1') {
header("Location: /forum/topic.php?p={$postInfo['post_id']}#p{$postInfo['post_id']}");
header("Location: " . url('forum_post', [
'post' => $postInfo['post_id'],
'post_fragment' => 'p' . $postInfo['post_id'],
]));
break;
} elseif (!$postRequestVerified) {
echo tpl_render('forum.confirm', [
@ -152,7 +155,7 @@ switch ($postMode) {
break;
}
header('Location: /forum/topic.php?t=' . $postInfo['topic_id']);
header("Location: " . url('forum_topic', ['topic' => $postInfo['topic_id']]));
break;
case 'nuke':
@ -163,7 +166,10 @@ switch ($postMode) {
if (!$isXHR) {
if ($postRequestVerified && isset($_GET['confirm']) && $_GET['confirm'] !== '1') {
header("Location: /forum/topic.php?p={$postInfo['post_id']}#p{$postInfo['post_id']}");
header("Location: " . url('forum_post', [
'post' => $postInfo['post_id'],
'post_fragment' => 'p' . $postInfo['post_id'],
]));
break;
} elseif (!$postRequestVerified) {
echo tpl_render('forum.confirm', [
@ -190,7 +196,7 @@ switch ($postMode) {
http_response_code(204);
if (!$isXHR) {
header('Location: /forum/topic.php?t=' . $postInfo['topic_id']);
header("Location: " . url('forum_topic', ['topic' => $postInfo['topic_id']]));
}
break;
@ -202,7 +208,10 @@ switch ($postMode) {
if (!$isXHR) {
if ($postRequestVerified && isset($_GET['confirm']) && $_GET['confirm'] !== '1') {
header("Location: /forum/topic.php?p={$postInfo['post_id']}#p{$postInfo['post_id']}");
header("Location: " . url('forum_post', [
'post' => $postInfo['post_id'],
'post_fragment' => 'p' . $postInfo['post_id'],
]));
break;
} elseif (!$postRequestVerified) {
echo tpl_render('forum.confirm', [
@ -229,7 +238,7 @@ switch ($postMode) {
http_response_code(204);
if (!$isXHR) {
header('Location: /forum/topic.php?t=' . $postInfo['topic_id']);
header("Location: " . url('forum_topic', ['topic' => $postInfo['topic_id']]));
}
break;
@ -252,8 +261,8 @@ switch ($postMode) {
break;
}
header('Location: ' . url_construct('/forum/topic.php', [
't' => $postFind['topic_id'],
'p' => floor($postFind['preceeding_post_count'] / MSZ_FORUM_POSTS_PER_PAGE) + 1,
header('Location: ' . url('forum-topic', [
'topic' => $postFind['topic_id'],
'page' => floor($postFind['preceeding_post_count'] / MSZ_FORUM_POSTS_PER_PAGE) + 1,
]));
}

View file

@ -203,7 +203,11 @@ if (!empty($_POST)) {
}
if (empty($notices)) {
$redirect = '/forum/topic.php' . (empty($topic) ? "?t={$topicId}" : "?p={$postId}#p{$postId}");
$redirect = url(empty($topic) ? 'forum-topic' : 'forum-post', [
'topic' => $topicId ?? 0,
'post' => $postId ?? 0,
'post_fragment' => 'p' . ($postId ?? 0),
]);
header("Location: {$redirect}");
return;
}

View file

@ -151,7 +151,10 @@ if (in_array($moderationMode, $validModerationModes, true)) {
if (!$isXHR) {
if (isset($_GET['confirm']) && $_GET['confirm'] !== '1') {
header("Location: /forum/topic.php?t={$topic['topic_id']}");
header("Location: " . url(
'forum-topic',
['topic' => $topic['topic_id']]
));
break;
} elseif (!isset($_GET['confirm'])) {
echo tpl_render('forum.confirm', [
@ -187,7 +190,9 @@ if (in_array($moderationMode, $validModerationModes, true)) {
break;
}
header('Location: /forum/forum.php?f=' . $topic['forum_id']);
header('Location: ' . url('forum-category', [
'forum' => $topic['forum_id'],
]));
break;
case 'restore':
@ -198,7 +203,9 @@ if (in_array($moderationMode, $validModerationModes, true)) {
if (!$isXHR) {
if (isset($_GET['confirm']) && $_GET['confirm'] !== '1') {
header("Location: /forum/topic.php?t={$topic['topic_id']}");
header("Location: " . url('forum-topic', [
'topic' => $topic['topic_id'],
]));
break;
} elseif (!isset($_GET['confirm'])) {
echo tpl_render('forum.confirm', [
@ -225,7 +232,9 @@ if (in_array($moderationMode, $validModerationModes, true)) {
http_response_code(204);
if (!$isXHR) {
header('Location: /forum/forum.php?f=' . $topic['forum_id']);
header('Location: ' . url('forum-category', [
'forum' => $topic['forum_id'],
]));
}
break;
@ -237,7 +246,9 @@ if (in_array($moderationMode, $validModerationModes, true)) {
if (!$isXHR) {
if (isset($_GET['confirm']) && $_GET['confirm'] !== '1') {
header("Location: /forum/topic.php?t={$topic['topic_id']}");
header('Location: ' . url('forum-topic', [
'topic' => $topic['topic_id'],
]));
break;
} elseif (!isset($_GET['confirm'])) {
echo tpl_render('forum.confirm', [
@ -264,7 +275,9 @@ if (in_array($moderationMode, $validModerationModes, true)) {
http_response_code(204);
if (!$isXHR) {
header('Location: /forum/forum.php?f=' . $topic['forum_id']);
header('Location: ' . url('forum-category', [
'forum' => $topic['forum_id'],
]));
}
break;
@ -273,7 +286,9 @@ if (in_array($moderationMode, $validModerationModes, true)) {
audit_log(MSZ_AUDIT_FORUM_TOPIC_BUMP, $topicUserId, [$topic['topic_id']]);
}
header('Location: /forum/topic.php?t=' . $topic['topic_id']);
header('Location: ' . url('forum-topic', [
'topic' => $topic['topic_id'],
]));
break;
case 'lock':
@ -281,7 +296,9 @@ if (in_array($moderationMode, $validModerationModes, true)) {
audit_log(MSZ_AUDIT_FORUM_TOPIC_LOCK, $topicUserId, [$topic['topic_id']]);
}
header('Location: /forum/topic.php?t=' . $topic['topic_id']);
header('Location: ' . url('forum-topic', [
'topic' => $topic['topic_id'],
]));
break;
case 'unlock':
@ -289,7 +306,9 @@ if (in_array($moderationMode, $validModerationModes, true)) {
audit_log(MSZ_AUDIT_FORUM_TOPIC_UNLOCK, $topicUserId, [$topic['topic_id']]);
}
header('Location: /forum/topic.php?t=' . $topic['topic_id']);
header('Location: ' . url('forum-topic', [
'topic' => $topic['topic_id'],
]));
break;
}
return;

View file

@ -355,7 +355,7 @@ switch ($mode) {
// If there are no notices, redirect to regular profile.
if (empty($notices)) {
header("Location: /profile.php?u={$userId}");
header('Location: ' . url('user-profile', ['user' => $userId]));
return;
}
}
@ -370,7 +370,7 @@ switch ($mode) {
if ($backgroundInfo) {
tpl_var('site_background', [
'url' => "/profile.php?m=background&u={$userId}",
'url' => url('user-background', ['user' => $userId]),
'width' => $backgroundInfo[0],
'height' => $backgroundInfo[1],
'settings' => $profile['user_background_settings'],

View file

@ -41,6 +41,8 @@ final class TwigMisuzu extends Twig_Extension
new Twig_Function('url_construct', 'url_construct'),
new Twig_Function('warning_has_duration', 'user_warning_has_duration'),
new Twig_Function('get_csrf_tokens', 'csrf_get_list'),
new Twig_Function('url', 'url'),
new Twig_Function('url_list', 'url_list'),
new Twig_Function('startup_time', function (float $time = MSZ_STARTUP) {
return microtime(true) - $time;
}),

View file

@ -85,6 +85,13 @@ function csrf_init(string $secretKey, string $identity): void
$GLOBALS[MSZ_CSRF_TOKEN_STORE] = [];
}
function csrf_is_ready(): bool
{
return !empty($GLOBALS[MSZ_CSRF_SECRET_STORE])
&& !empty($GLOBALS[MSZ_CSRF_IDENTITY_STORE])
&& is_array($GLOBALS[MSZ_CSRF_TOKEN_STORE]);
}
function csrf_token(string $realm): string
{
if (array_key_exists($realm, $GLOBALS[MSZ_CSRF_TOKEN_STORE])) {

188
src/url.php Normal file
View file

@ -0,0 +1,188 @@
<?php
// URL FORMATTING
// [0] => Path part of URL.
// [1] => Query part of URL.
// [2] => Fragment part of URL.
//
// text surrounded by < and > will be replaced accordingly to an array of variables supplied to the format function
// text surrounded by [ and ] will be replaced by the constant/define of that name
// text surrounded by { and } will be replaced by a CSRF token with the given text as its realm, this will have no effect in a sessionless environment
define('MSZ_URLS', [
'index' => ['/'],
'info' => ['/info.php/{title}'],
'auth-login' => ['/auth.php', ['m' => 'login']],
'auth-register' => ['/auth.php', ['m' => 'register']],
'auth-forgot' => ['/auth.php', ['m' => 'forgot']],
'auth-reset' => ['/auth.php', ['m' => 'reset', 'u' => '<user>']],
'auth-logout' => ['/auth.php', ['m' => 'logout', 's' => '{logout}']],
'changelog-index' => ['/changelog.php'],
'changelog-date' => ['/changelog.php', ['d' => '<date>']],
'changelog-tag' => ['/changelog.php', ['t' => '<tag>']],
'news-post' => ['/news.php', ['p' => '<post>']],
'news-post-comments' => ['/news.php', ['p' => '<post>'], 'comments'],
'news-category' => ['/news.php', ['c' => '<category>', 'page' => '<page>']],
'news-index' => ['/news.php', ['page' => '<page>']],
'forum-index' => ['/forum'],
'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>']],
'forum-reply-new' => ['/forum/posting.php', ['t' => '<topic>']],
'forum-category' => ['/forum/forum.php', ['f' => '<forum>', 'p' => '<page>']],
'forum-topic' => ['/forum/topic.php', ['t' => '<topic>', 'page' => '<page>']],
'forum-post' => ['/forum/topic.php', ['p' => '<post>'], '<post_fragment>'],
'forum-post-delete' => ['/forum/post.php', ['p' => '<post>', 'm' => 'delete']],
'forum-post-restore' => ['/forum/post.php', ['p' => '<post>', 'm' => 'restore']],
'forum-post-nuke' => ['/forum/post.php', ['p' => '<post>', 'm' => 'nuke']],
'forum-post-quote' => ['/forum/posting.php', ['q' => '<post>']],
'forum-post-edit' => ['/forum/posting.php', ['p' => '<post>', 'm' => 'edit']],
'user-profile' => ['/profile.php', ['u' => '<user>']],
'user-profile-edit' => ['/profile.php', ['u' => '<user>', 'm' => 'edit']],
'user-avatar' => ['/profile.php', ['u' => '<user>', 'm' => 'avatar']],
'user-background' => ['/profile.php', ['u' => '<user>', 'm' => 'background']],
'user-account-standing' => ['/profile.php', ['u' => '<user>'], 'account-standing'],
'guest-avatar' => ['/profile.php', ['m' => 'avatar']],
'user-relation-none' => ['/relations.php', ['u' => '<user>', 'm' => '[MSZ_USER_RELATION_NONE]', 'c' => '{user_relation}']],
'user-relation-follow' => ['/relations.php', ['u' => '<user>', 'm' => '[MSZ_USER_RELATION_FOLLOW]', 'c' => '{user_relation}']],
'members-role' => ['/members.php', ['r' => '<role>']],
'settings-index' => ['/settings.php'],
'settings-mode' => ['/settings.php', [], '<mode>'],
'comment-vote' => ['/comments.php', ['c' => '<comment>', 'csrf' => '{comments}', 'm' => 'vote', 'v' => '<vote>']],
'comment-delete' => ['/comments.php', ['c' => '<comment>', 'csrf' => '{comments}', 'm' => 'delete']],
'comment-restore' => ['/comments.php', ['c' => '<comment>', 'csrf' => '{comments}', 'm' => 'restore']],
'comment-pin' => ['/comments.php', ['c' => '<comment>', 'csrf' => '{comments}', 'm' => 'pin']],
'comment-unpin' => ['/comments.php', ['c' => '<comment>', 'csrf' => '{comments}', 'm' => 'unpin']],
'manage-changelog-tag-create' => ['/manage/changelog.php', ['v' => 'tag']],
'manage-changelog-tag-edit' => ['/manage/changelog.php', ['v' => 'tag', 't' => '<tag>']],
'manage-changelog-action-create' => ['/manage/changelog.php', ['v' => 'action']],
'manage-changelog-action-edit' => ['/manage/changelog.php', ['v' => 'action', 'a' => '<action>']],
'manage-changelog-change-create' => ['/manage/changelog.php', ['v' => 'change']],
'manage-changelog-change-edit' => ['/manage/changelog.php', ['v' => 'change', 'c' => '<change>']],
'manage-forum-category-view' => ['/manage/forum.php', ['v' => 'forum', 'f' => '<forum>']],
'manage-news-category-create' => ['/manage/news.php', ['v' => 'category']],
'manage-news-category-edit' => ['/manage/news.php', ['v' => 'category', 'c' => '<category>']],
'manage-news-post-create' => ['/manage/news.php', ['v' => 'post']],
'manage-news-post-edit' => ['/manage/news.php', ['v' => 'post', 'p' => '<post>']],
'manage-user-index' => ['/manage/users.php', ['v' => 'listing']],
'manage-user-edit' => ['/manage/users.php', ['v' => 'view', 'u' => '<user>']],
'manage-role-index' => ['/manage/users.php', ['v' => 'roles']],
'manage-role-create' => ['/manage/users.php', ['v' => 'role']],
'manage-role-edit' => ['/manage/users.php', ['v' => 'role', 'r' => '<role>']],
'manage-warning-delete' => ['/manage/users.php', ['v' => 'warnings', 'u' => '<user>', 'w' => '<warning>', 'm' => 'delete', 'c' => '<token>']],
]);
function url(string $name, array $variables = []): string
{
if (!array_key_exists($name, MSZ_URLS)) {
return '';
}
$info = MSZ_URLS[$name];
$url = $info[0];
if (!is_string($url)) {
return '';
}
if (!empty($info[1]) && is_array($info[1])) {
$url .= '?';
foreach ($info[1] as $key => $value) {
$value = url_variable($value, $variables);
if (empty($value) || ($key === 'page' && $value < 2)) {
continue;
}
$url .= sprintf('%s=%s&', $key, $value);
}
$url = trim($url, '?&');
}
if (!empty($info[2]) && is_string($info[2])) {
$url .= rtrim(sprintf('#%s', url_variable($info[2], $variables)), '#');
}
return $url;
}
function url_variable(string $value, array $variables): string
{
if (starts_with($value, '<') && ends_with($value, '>')) {
return $variables[trim($value, '<>')] ?? '';
}
if (starts_with($value, '[') && ends_with($value, ']')) {
return constant(trim($value, '[]'));
}
if (starts_with($value, '{') && ends_with($value, '}') && csrf_is_ready()) {
return csrf_token(trim($value, '{}'));
}
return $value;
}
function url_list(): array
{
$collection = [];
foreach (MSZ_URLS as $name => $urlInfo) {
$item = [
'name' => $name,
'path' => $urlInfo[0],
'query' => [],
'fragment' => $urlInfo[2] ?? '',
];
if (!empty($urlInfo[1]) && is_array($urlInfo[1])) {
foreach ($urlInfo[1] as $name => $value) {
$item['query'][] = [
'name' => $name,
'value' => $value,
];
}
}
$collection[] = $item;
}
return $collection;
}
function url_construct(string $url, array $query = [], ?string $fragment = null): string
{
if (count($query)) {
$url .= mb_strpos($url, '?') !== false ? '&' : '?';
foreach ($query as $key => $value) {
if ($value) {
$url .= rawurlencode($key) . '=' . rawurlencode($value) . '&';
}
}
$url = mb_substr($url, 0, -1);
}
if (!empty($fragment)) {
$url .= "#{$fragment}";
}
return $url;
}

View file

@ -53,15 +53,15 @@
<div class="avatar comment__avatar" style="background-image:url('/profile.php?m=avatar')"></div>
{% else %}
<a class="avatar comment__avatar"
href="/profile.php?u={{ comment.user_id }}"
style="background-image:url('/profile.php?m=avatar&amp;u={{ comment.user_id }}')">
href="{{ url('user-profile', {'user':comment.user_id}) }}"
style="background-image:url('{{ url('user-avatar', {'user':comment.user_id}) }}')">
</a>
{% endif %}
<div class="comment__content">
<div class="comment__info">
{% if not hide_details %}
<a class="comment__user comment__user--link"
href="/profile.php?u={{ comment.user_id }}"
href="{{ url('user-profile', {'user':comment.user_id}) }}"
style="{{ comment.user_colour|html_colour }}">{{ comment.username }}</a>
{% endif %}
<a class="comment__link" href="#comment-{{ comment.comment_id }}">
@ -90,7 +90,7 @@
{% if not is_deleted and user is not null %}
{% if perms.can_vote %}
<a class="comment__action comment__action--link comment__action--vote comment__action--like{% if comment.comment_user_vote == 'Like' %} comment__action--voted{% endif %}" data-comment-id="{{ comment.comment_id }}" data-comment-vote="{{ comment.comment_user_vote == 'Like' ? '0' : '1' }}"
href="/comments.php?m=vote&amp;c={{ comment.comment_id }}&amp;v={{ comment.comment_user_vote == 'Like' ? '0' : '1' }}&amp;csrf={{ csrf_token('comments') }}">
href="{{ url('comment-vote', {'comment':comment.comment_id,'vote':comment.comment_user_vote == 'Like' ? '0' : '1'}) }}">
<!--i class="fas fa-thumbs-up"></i-->
Like
{% if comment.comment_likes > 0 %}
@ -98,7 +98,7 @@
{% endif %}
</a>
<a class="comment__action comment__action--link comment__action--vote comment__action--dislike{% if comment.comment_user_vote == 'Dislike' %} comment__action--voted{% endif %}" data-comment-id="{{ comment.comment_id }}" data-comment-vote="{{ comment.comment_user_vote == 'Dislike' ? '0' : '-1' }}"
href="/comments.php?m=vote&amp;c={{ comment.comment_id }}&amp;v={{ comment.comment_user_vote == 'Dislike' ? '0' : '-1' }}&amp;csrf={{ csrf_token('comments') }}">
href="{{ url('comment-vote', {'comment':comment.comment_id,'vote':comment.comment_user_vote == 'Dislike' ? '0' : '-1'}) }}">
<!--i class="fas fa-thumbs-down"></i-->
Dislike
{% if comment.comment_dislikes > 0 %}
@ -110,16 +110,16 @@
<label class="comment__action comment__action--link" for="comment-reply-toggle-{{ comment.comment_id }}">Reply</label>
{% endif %}
{% if perms.can_delete_any or (comment.user_id == user.user_id and perms.can_delete) %}
<a class="comment__action comment__action--link comment__action--hide comment__action--delete" data-comment-id="{{ comment.comment_id }}" href="/comments.php?m=delete&amp;c={{ comment.comment_id }}&amp;csrf={{ csrf_token('comments') }}">Delete</a>
<a class="comment__action comment__action--link comment__action--hide comment__action--delete" data-comment-id="{{ comment.comment_id }}" href="{{ url('comment-delete', {'comment':comment.comment_id}) }}">Delete</a>
{% endif %}
{# if user is not null %}
<a class="comment__action comment__action--link comment__action--hide" href="#">Report</a>
{% endif #}
{% if comment.comment_reply_to is null and perms.can_pin %}
<a class="comment__action comment__action--link comment__action--hide comment__action--pin" data-comment-id="{{ comment.comment_id }}" data-comment-pinned="{{ is_pinned ? '1' : '0' }}" href="/comments.php?m={{ is_pinned ? 'unpin' : 'pin' }}&amp;c={{ comment.comment_id }}&amp;csrf={{ csrf_token('comments') }}">{{ is_pinned ? 'Unpin' : 'Pin' }}</a>
<a class="comment__action comment__action--link comment__action--hide comment__action--pin" data-comment-id="{{ comment.comment_id }}" data-comment-pinned="{{ is_pinned ? '1' : '0' }}" href="{{ url('comment-' ~ (is_pinned ? 'unpin' : 'pin'), {'comment':comment.comment_id}) }}">{{ is_pinned ? 'Unpin' : 'Pin' }}</a>
{% endif %}
{% elseif perms.can_delete_any %}
<a class="comment__action comment__action--link comment__action--restore" data-comment-id="{{ comment.comment_id }}" href="/comments.php?m=restore&amp;c={{ comment.comment_id }}&amp;csrf={{ csrf_token('comments') }}">Restore</a>
<a class="comment__action comment__action--link comment__action--restore" data-comment-id="{{ comment.comment_id }}" href="{{ url('comment-restore', {'comment':comment.comment_id}) }}">Restore</a>
{% endif %}
</div>
</div>
@ -146,7 +146,7 @@
<div class="comments__input">
{% if user|default(null) is null %}
<div class="comments__notice">
Please <a href="/auth.php?m=login" class="comments__notice__link">login</a> to comment.
Please <a href="{{ url('auth-login') }}" class="comments__notice__link">login</a> to comment.
</div>
{% elseif category|default(null) is null or perms|default(null) is null %}
<div class="comments__notice">

View file

@ -90,7 +90,7 @@
<div class="header__background"></div>
<div class="header__desktop">
<a class="header__desktop__logo" href="/" title="{{ globals.site_name }}">
<a class="header__desktop__logo" href="{{ url('index') }}" title="{{ globals.site_name }}">
{{ globals.site_name }}
</a>
@ -123,11 +123,11 @@
{% endfor %}
{% if current_user is defined %}
<a href="/profile.php?u={{ current_user.user_id }}" class="avatar header__desktop__user__avatar" title="{{ current_user.username }}"
style="background-image:url('/profile.php?u={{ current_user.user_id }}&amp;m=avatar');{{ current_user.user_colour|html_colour }}"></a>
<a href="{{ url('user-profile', {'user': current_user.user_id}) }}" class="avatar header__desktop__user__avatar" title="{{ current_user.username }}"
style="background-image:url('{{ url('user-avatar', {'user': current_user.user_id}) }}');{{ current_user.user_colour|html_colour }}"></a>
{% else %}
<a href="/auth.php?m=login" class="avatar header__desktop__user__avatar"
style="background-image:url('/profile.php?m=avatar');"></a>
<a href="{{ url('auth-login') }}" class="avatar header__desktop__user__avatar"
style="background-image:url('{{ url('guest-avatar') }}');"></a>
{% endif %}
</div>
</div>
@ -138,7 +138,7 @@
<i class="fas fa-bars"></i>
</label>
<a class="header__mobile__logo header__mobile__icon" href="/">
<a class="header__mobile__logo header__mobile__icon" href="{{ url('index') }}">
{{ globals.site_name }}
</a>

View file

@ -23,9 +23,9 @@
<div class="warning auth__warning">
<div class="warning__content">
{% if auth_restricted == 2 %}
A user is currently in a banned and/or silenced state from the same IP address you're currently visiting the site from. If said user isn't you and you wish to create an account, please <a href="/info.php/contact" class="warning__link">contact us</a>!
A user is currently in a banned and/or silenced state from the same IP address you're currently visiting the site from. If said user isn't you and you wish to create an account, please <a href="{{ url('info', {'title': 'contact'}) }}" class="warning__link">contact us</a>!
{% else %}
The IP address from which you are visiting the website appears on our blacklist, you are not allowed to register from this address but if you already have an account you can log in just fine using the form above. If you think this blacklisting is a mistake, please <a href="/info.php/contact" class="warning__link">contact us</a>!
The IP address from which you are visiting the website appears on our blacklist, you are not allowed to register from this address but if you already have an account you can log in just fine using the form above. If you think this blacklisting is a mistake, please <a href="{{ url('info', {'title': 'contact'}) }}" class="warning__link">contact us</a>!
{% endif %}
</div>
</div>

View file

@ -9,7 +9,7 @@
<p class="auth__paragraph">We couldn't verify that you were actually the person attempting to log out.</p>
<p class="auth__paragraph">Press the button below to verify the logout request, otherwise click back in your browser or close this tab.</p>
<p class="auth__paragraph">This error is usually caused by pressing the logout button on a page that's been loaded for a while.</p>
<a href="?m=logout&amp;s={{ csrf_token('logout') }}" class="input__button">Log out</a>
<a href="{{ url('auth-logout') }}" class="input__button">Log out</a>
</div>
</div>
{% endblock %}

View file

@ -27,18 +27,18 @@
{% if change.user_id is not null %}
<div class="changelog__change__user">
<a class="avatar changelog__change__avatar"
style="background-image:url('/profile.php?u={{ change.user_id }}&amp;m=avatar');"
href="/profile.php?u={{ change.user_id }}">
style="background-image:url('{{ url('user-avatar', {'user': change.user_id}) }}');"
href="{{ url('user-profile', {'user': change.user_id}) }}">
</a>
<div class="changelog__change__user__details">
<a class="changelog__change__username" href="/profile.php?u={{ change.user_id }}">{{ change.username }}</a>
<a class="changelog__change__userrole" href="/members.php?r={{ change.user_role }}">{{ change.user_title }}</a>
<a class="changelog__change__username" href="{{ url('user-profile', {'user': change.user_id}) }}">{{ change.username }}</a>
<a class="changelog__change__userrole" href="{{ url('members-role', {'user': change.user_role}) }}">{{ change.user_title }}</a>
</div>
</div>
{% endif %}
<a class="changelog__change__date" href="/changelog.php?d={{ change.change_date }}">
<a class="changelog__change__date" href="{{ url('changelog-date', {'date': change.change_date}) }}">
Created
<time datetime="{{ change.change_created|date('c') }}" title="{{ change.change_created|date('r') }}">
{{ change.change_created|time_diff }}
@ -49,7 +49,7 @@
<ul class="changelog__change__tags">
{% for tag in tags %}
<li class="changelog__change__tag" title="{{ tag.tag_description }}">
<a href="/changelog.php?t={{ tag.tag_id }}" class="changelog__change__tag__link">
<a href="{{ url('changelog-tag', {'tag': tag.tag_id}) }}" class="changelog__change__tag__link">
{{ tag.tag_name }}
</a>
</li>

View file

@ -22,7 +22,7 @@
{% if current_user is defined %}
<div class="container forum__actions">
<a href="?m=mark&amp;c={{ csrf_token('forum_mark') }}" class="input__button forum__actions__button">Mark All Read</a>
<a href="{{ url('forum-mark-global') }}" class="input__button forum__actions__button">Mark All Read</a>
</div>
{% endif %}
{% else %}

View file

@ -76,7 +76,7 @@
<div class="container forum__actions">
<div class="forum__actions__buttons">
{% if can_topic %}
<a href="{{ url_construct('/forum/posting.php', {'f':info.forum_id}) }}" class="input__button forum__actions__button">New Topic</a>
<a href="{{ url('forum-topic-new', {'forum': info.forum_id}) }}" class="input__button forum__actions__button">New Topic</a>
{% endif %}
</div>
@ -96,7 +96,7 @@
<div class="container forum__actions">
<div class="forum__actions__buttons">
{% if can_reply %}
<a href="/forum/posting.php?t={{ info.topic_id }}" class="input__button">Reply</a>
<a href="{{ url('forum-reply-new', {'topic': info.topic_id}) }}" class="input__button">Reply</a>
{% endif %}
</div>
@ -126,7 +126,7 @@
{% endif %}
<div class="forum__category">
<a href="/forum/forum.php?f={{ forum.forum_id }}" class="forum__category__link"></a>
<a href="{{ url('forum-category', {'forum': forum.forum_id}) }}" class="forum__category__link"></a>
<div class="forum__category__container">
<div class="forum__category__icon forum__category__icon--{{ forum_unread }}">
@ -145,7 +145,7 @@
{% if forum.forum_subforums is defined and forum.forum_subforums|length > 0 %}
<div class="forum__category__subforums">
{% for subforum in forum.forum_subforums %}
<a href="/forum/forum.php?f={{ subforum.forum_id }}"
<a href="{{ url('forum-category', {'forum': subforum.forum_id}) }}"
class="forum__category__subforum{% if subforum.forum_unread %} forum__category__subforum--unread{% endif %}">
{{ subforum.forum_name }}
</a>
@ -177,7 +177,7 @@
{% else %}
<div class="forum__category__activity__details">
<a class="forum__category__activity__post"
href="/forum/topic.php?p={{ forum.recent_post_id }}#p{{ forum.recent_post_id }}">
href="{{ url('forum-post', {'post': forum.recent_post_id, 'post_fragment': 'p' ~ forum.recent_post_id}) }}">
{{ forum.recent_topic_title }}
</a>
@ -186,7 +186,7 @@
title="{{ forum.recent_post_created|date('r') }}">{{ forum.recent_post_created|time_diff }}</time>
{% if forum.recent_post_user_id is not null %}
by
<a href="/profile.php?u={{ forum.recent_post_user_id }}" class="forum__category__username"
<a href="{{ url('user-profile', {'user': forum.recent_post_user_id}) }}" class="forum__category__username"
style="{{ forum.recent_post_user_colour|html_colour }}">
{{ forum.recent_post_username }}
</a>
@ -195,9 +195,9 @@
</div>
{% if forum.recent_post_user_id is not null %}
<a href="/profile.php?u={{ forum.recent_post_user_id }}"
<a href="{{ url('user-profile', {'user': forum.recent_post_user_id}) }}"
class="avatar forum__category__avatar"
style="background-image:url('/profile.php?u={{ forum.recent_post_user_id }}&amp;m=avatar')">
style="background-image:url('{{ url('user-avatar', {'user': forum.recent_post_user_id}) }}')">
</a>
{% endif %}
{% endif %}
@ -272,7 +272,7 @@
{% endif %}
<div class="forum__topic{% if topic.topic_deleted is not null %} forum__topic--deleted{% elseif topic.topic_locked is not null and not topic_important %} forum__topic--locked{% endif %}">
<a href="/forum/topic.php?t={{ topic.topic_id }}" class="forum__topic__link"></a>
<a href="{{ url('forum-topic', {'topic': topic.topic_id}) }}" class="forum__topic__link"></a>
<div class="forum__topic__container">
<div class="forum__topic__icon forum__topic__icon--{{ topic_unread ? 'unread' : 'read' }}">
@ -293,7 +293,7 @@
<div class="forum__topic__info">
{% if topic.author_id is not null %}
by <a
href="/profile.php?u={{ topic.author_id }}"
href="{{ url('user-profile', {'user': topic.author_id}) }}"
class="forum__topic__username"
style="{{ topic.author_colour|html_colour }}">{{ topic.author_name }}</a>,
@ -308,7 +308,7 @@
</div>
{% for i in 1..topic.topic_pages|clamp(0, 3) %}
<a href="/forum/topic.php?t={{ topic.topic_id }}{% if i > 1 %}&amp;page={{ i }}{% endif %}" class="forum__topic__pagination__item">
<a href="{{ url('forum-topic', {'topic': topic.topic_id, 'page': i}) }}" class="forum__topic__pagination__item">
{{ i }}
</a>
{% endfor %}
@ -320,7 +320,7 @@
{% endif %}
{% for i in (topic.topic_pages - 2)|clamp(4, topic.topic_pages)..topic.topic_pages %}
<a href="/forum/topic.php?t={{ topic.topic_id }}{% if i > 1 %}&amp;page={{ i }}{% endif %}" class="forum__topic__pagination__item">
<a href="{{ url('forum-topic', {'topic': topic.topic_id, 'page': i}) }}" class="forum__topic__pagination__item">
{{ i }}
</a>
{% endfor %}
@ -337,21 +337,21 @@
<div class="forum__topic__activity">
<div class="forum__topic__activity__details">
{% if topic.respondent_id is not null %}
<a href="/profile.php?u={{ topic.respondent_id }}" class="forum__topic__username"
<a href="{{ url('user-profile', {'user': topic.respondent_id}) }}" class="forum__topic__username"
style="{{ topic.respondent_colour|html_colour }}">{{ topic.respondent_name }}</a>
{% endif %}
<a class="forum__topic__activity__post"
href="/forum/topic.php?p={{ topic.response_id }}#p{{ topic.response_id }}">
href="{{ url('forum-post', {'post': topic.response_id, 'post_fragment': 'p' ~ topic.response_id}) }}">
<time datetime="{{ topic.response_created|date('c') }}"
title="{{ topic.response_created|date('r') }}">{{ topic.response_created|time_diff }}</time>
</a>
</div>
{% if topic.respondent_id is not null %}
<a href="/profile.php?u={{ topic.respondent_id }}"
<a href="{{ url('user-profile', {'user': topic.respondent_id}) }}"
class="avatar forum__topic__avatar"
style="background-image:url('/profile.php?u={{ topic.respondent_id }}&amp;m=avatar')">
style="background-image:url('{{ url('user-avatar', {'user': topic.respondent_id}) }}')">
</a>
{% endif %}
</div>
@ -388,11 +388,11 @@
<div class="forum__post__info__content">
{% if post.poster_id is not null %}
<a class="avatar forum__post__avatar"
style="background-image:url('/profile.php?u={{ post.poster_id }}&amp;m=avatar');"
href="/profile.php?u={{ post.poster_id }}">
style="background-image:url('{{ url('user-avatar', {'user': post.poster_id}) }}');"
href="{{ url('user-profile', {'user': post.poster_id}) }}">
</a>
<a class="forum__post__username" href="/profile.php?u={{ post.poster_id }}">{{ post.poster_name }}</a>
<a class="forum__post__username" href="{{ url('user-profile', {'user': post.poster_id}) }}">{{ post.poster_name }}</a>
{% if post.poster_title|length > 0 %}
<div class="forum__post__usertitle">{{ post.poster_title }}</div>
@ -420,7 +420,7 @@
</div>
<div class="forum__post__content">
{% set post_link = url_construct('/forum/topic.php', post.is_opening_post ? {'t':post.topic_id} : {'p':post.post_id}, post.is_opening_post ? '' : 'p%d'|format(post.post_id)) %}
{% set post_link = url(post.is_opening_post ? 'forum-topic' : 'forum-post', {'topic': post.topic_id, 'post': post.post_id, 'post_fragment': 'p%d'|format(post.post_id)}) %}
<div class="forum__post__details">
<a class="forum__post__datetime" href="{{ post_link }}">
@ -442,17 +442,17 @@
{% if can_post or can_edit or can_delete %}
<div class="forum__post__actions">
{% if is_deleted %}
<a href="/forum/post.php?p={{ post.post_id }}&amp;m=restore" class="forum__post__action forum__post__action--restore"><i class="fas fa-magic fa-fw"></i> Restore</a>
<a href="/forum/post.php?p={{ post.post_id }}&amp;m=nuke" class="forum__post__action forum__post__action--nuke"><i class="fas fa-radiation-alt fa-fw"></i> Permanently Delete</a>
<a href="{{ url('forum-post-restore', {'post': post.post_id}) }}" class="forum__post__action forum__post__action--restore"><i class="fas fa-magic fa-fw"></i> Restore</a>
<a href="{{ url('forum-post-nuke', {'post': post.post_id}) }}" class="forum__post__action forum__post__action--nuke"><i class="fas fa-radiation-alt fa-fw"></i> Permanently Delete</a>
{% else %}
{# if can_post %}
<a href="/forum/posting.php?p={{ post.post_id }}&amp;m=quote" class="forum__post__action forum__post__action--quote"><i class="fas fa-quote-left fa-fw"></i> Quote</a>
<a href="{{ url('forum-post-quote', {'post': post.post_id}) }}" class="forum__post__action forum__post__action--quote"><i class="fas fa-quote-left fa-fw"></i> Quote</a>
{% endif #}
{% if can_edit %}
<a href="/forum/posting.php?p={{ post.post_id }}&amp;m=edit" class="forum__post__action forum__post__action--edit"><i class="fas fa-edit fa-fw"></i> Edit</a>
<a href="{{ url('forum-post-edit', {'post': post.post_id}) }}" class="forum__post__action forum__post__action--edit"><i class="fas fa-edit fa-fw"></i> Edit</a>
{% endif %}
{% if can_delete %}
<a href="/forum/post.php?p={{ post.post_id }}&amp;m=delete" class="forum__post__action forum__post__action--delete"><i class="far fa-trash-alt fa-fw"></i> Delete</a>
<a href="{{ url('forum-post-delete', {'post': post.post_id}) }}" class="forum__post__action forum__post__action--delete"><i class="far fa-trash-alt fa-fw"></i> Delete</a>
{% endif %}
{% endif %}
</div>

View file

@ -2,20 +2,12 @@
{% from 'macros.twig' import container_title %}
{% from 'news/macros.twig' import news_preview %}
{% from 'changelog/macros.twig' import changelog_listing %}
{% from 'home/macros.twig' import chat_quote_display %}
{% set canonical_url = '/' %}
{% block content %}
<div class="index">
<div class="index__sidebar">
{% if chat_quote is defined and chat_quote is iterable and chat_quote|length > 0 %}
<div class="container index__container">
{{ container_title('<i class="fas fa-quote-left fa-fw"></i> Chat quote from ' ~ (chat_quote[0].quote_timestamp|date('Y-m-d'))) }}
{{ chat_quote_display(chat_quote) }}
</div>
{% endif %}
<div class="container index__container">
{{ container_title('<i class="fas fa-chart-bar fa-fw"></i> Statistics') }}
@ -84,7 +76,7 @@
<div class="index__online">
{% for user in online_users %}
<a href="/profile.php?u={{ user.user_id }}" class="avatar index__online__user" style="{{ user.user_colour|html_colour }};--avatar-url: url('/profile.php?m=avatar&amp;u={{ user.user_id }}');" title="{{ user.username }}">
<a href="{{ url('user-profile', {'user': user.user_id}) }}" class="avatar index__online__user" style="{{ user.user_colour|html_colour }};--avatar-url: url('{{ url('user-avatar', {'user': user.user_id}) }}');" title="{{ user.username }}">
{{ user.username }}
</a>
{% endfor %}
@ -97,8 +89,8 @@
{{ container_title('<i class="fas fa-birthday-cake fa-fw"></i> Happy Birthday!') }}
{% for birthday in birthdays %}
<a class="index__latest" style="{# birthday.user_colour|html_colour #}" href="/profile.php?u={{ birthday.user_id }}">
<div class="avatar index__latest__avatar" style="--avatar-url: url('/profile.php?m=avatar&amp;u={{ birthday.user_id }}')"></div>
<a class="index__latest" style="{# birthday.user_colour|html_colour #}" href="{{ url('user-profile', {'user': birthday.user_id}) }}">
<div class="avatar index__latest__avatar" style="--avatar-url: url('{{ url('user-avatar', {'user': birthday.user_id}) }}')"></div>
<div class="index__latest__content">
<div class="index__latest__username">
{{ birthday.username }}
@ -116,8 +108,8 @@
<div class="container index__container">
{{ container_title('<i class="fas fa-user-plus fa-fw"></i> Newest User') }}
<a class="index__latest" style="{{ latest_user.user_colour|html_colour }}" href="/profile.php?u={{ latest_user.user_id }}">
<div class="avatar index__latest__avatar" style="--avatar-url: url('/profile.php?m=avatar&amp;u={{ latest_user.user_id }}')"></div>
<a class="index__latest" style="{{ latest_user.user_colour|html_colour }}" href="{{ url('user-profile', {'user': latest_user.user_id}) }}">
<div class="avatar index__latest__avatar" style="--avatar-url: url('{{ url('user-avatar', {'user': latest_user.user_id}) }}')"></div>
<div class="index__latest__content">
<div class="index__latest__username">
{{ latest_user.username }}
@ -131,7 +123,7 @@
{% endif %}
<div class="container index__container">
{{ container_title('<i class="fas fa-wrench fa-fw"></i> Changelog', false, '/changelog.php') }}
{{ container_title('<i class="fas fa-wrench fa-fw"></i> Changelog', false, url('changelog-index')) }}
<div class="changelog__content">
{{ changelog_listing(featured_changelog, false, false, null, null, null, null, true) }}
</div>

View file

@ -1,18 +0,0 @@
{# the HTML looks a bit odd, but it's to make copying the text work as expected #}
{% macro chat_quote_display(lines) %}
<div class="chat-quote">{% spaceless %}
{% for line in lines %}
<div class="chat-quote__line">
<span class="chat-quote__time">({{ line.quote_timestamp|date('H:i:s') }}) </span>
<span><a class="chat-quote__username" style="{{ line.quote_user_colour|html_colour }}"
{% if line.quote_user_id is not null %}href="/profile.php?u={{ line.quote_user_id }}"{% endif %}>{% spaceless %}
{{ line.quote_username }}
{% endspaceless %}</a></span>
<span class="chat-quote__separator">: </span>
<span class="chat-quote__text">{% spaceless %}
{{ line.quote_text }}
{% endspaceless %}</span>
</div>
{% endfor %}
{% endspaceless %}</div>
{% endmacro %}

View file

@ -11,13 +11,13 @@
<p>Here's a listing of a few informational pages that'll probably come in handy during your Flashii Experience&trade;.</p>
<h2>Flashii</h2>
<ul>
<li><a href="/info.php/rules">Rules</a></li>
<li><a href="{{ url('info', {'title': 'rules'}) }}">Rules</a></li>
</ul>
<h2>Misuzu Project</h2>
<ul>
<li><a href="/info.php/misuzu">Read me</a></li>
<li><a href="/info.php/misuzu/license">License</a></li>
<li><a href="/info.php/misuzu/code_of_conduct">Code of Conduct</a></li>
<li><a href="{{ url('info', {'title': 'misuzu'}) }}">Read me</a></li>
<li><a href="{{ url('info', {'title': 'misuzu/license'}) }}">License</a></li>
<li><a href="{{ url('info', {'title': 'misuzu/code_of_conduct'}) }}">Code of Conduct</a></li>
</ul>
</div>
</div>

View file

@ -7,11 +7,11 @@
<div class="container changelog-actions-tags__panel changelog-actions-tags__panel--tags">
{{ container_title('Tags') }}
<a href="?v=tag" class="input__button">Create new tag</a>
<a href="{{ url('manage-changelog-tag-create') }}" class="input__button">Create new tag</a>
<div class="changelog-actions-tags__list">
{% for tag in changelog_tags %}
<a href="?v=tag&amp;t={{ tag.tag_id }}" class="changelog-actions-tags__entry">
<a href="{{ url('manage-changelog-tag-edit', {'tag': tag.tag_id}) }}" class="changelog-actions-tags__entry">
<div class="listing__entry__content changelog-tags__content">
<div class="changelog-tags__text">
{{ tag.tag_name }} ({{ tag.tag_count }})
@ -31,11 +31,11 @@
<div class="container changelog-actions-tags__panel changelog-actions-tags__panel--actions">
{{ container_title('Actions') }}
<a href="?v=action" class="input__button">Create new action</a>
<a href="{{ url('manage-changelog-action-create') }}" class="input__button">Create new action</a>
<div class="changelog-actions-tags__list">
{% for action in changelog_actions %}
<a href="?v=action&amp;a={{ action.action_id }}" class="changelog-actions-tags__entry"
<a href="{{ url('manage-changelog-action-edit', {'action': action.action_id}) }}" class="changelog-actions-tags__entry"
style="{{ action.action_colour|html_colour('border-color') }}">
<div class="listing__entry__content changelog-tags__content">
<div class="changelog-tags__text">

View file

@ -3,7 +3,7 @@
{% from 'changelog/macros.twig' import changelog_listing %}
{% block manage_content %}
<a href="?v=change" class="input__button">Create new change</a>
<a href="{{ url('manage-changelog-change-create') }}" class="input__button">Create new change</a>
<div class="container">
{{ container_title('Changelog') }}
@ -11,9 +11,9 @@
<div class="changelog__content">
{{ changelog_listing(
changelog_changes, false, true,
'?v=change&c=%d', '#cd-%s',
'?v=tag&t=%d',
'/manage/user.php?v=view&u=%d'
url('manage-changelog-change-edit', {'change': '%d'}), '#cd-%s',
url('manage-changelog-tag-edit', {'tag': '%d'}),
url('manage-user-edit', {'user': '%d'})
) }}
<div class="changelog__pagination">

View file

@ -8,7 +8,7 @@
<div class="container__content">
{% for forum in forums %}
<a href="?v=forum&amp;f={{ forum.forum_id }}" class="warning__link">{{ forum.forum_name }}</a><br>
<a href="{{ url('manage-forum-category-view', {'forum': forum.forum_id}) }}" class="warning__link">{{ forum.forum_name }}</a><br>
{% endfor %}
</div>
</div>

View file

@ -5,11 +5,11 @@
<div class="container">
{{ container_title('Categories') }}
<a href="?v=category" class="input__button">New Category</a>
<a href="{{ url('manage-news-category-create') }}" class="input__button">New Category</a>
{% for cat in news_categories %}
<p>
<a href="?v=category&amp;c={{ cat.category_id }}" class="input__button">{{ cat.category_id }}</a>
<a href="{{ url('manage-news-category-edit', {'category': cat.category_id}) }}" class="input__button">{{ cat.category_id }}</a>
{{ cat.category_name }},
{{ cat.category_is_hidden }},
{{ cat.category_created }}

View file

@ -5,12 +5,12 @@
<div class="container">
{{ container_title('News Posts') }}
<a href="?v=post" class="input__button">New Post</a>
<a href="{{ url('manage-news-post-create') }}" class="input__button">New Post</a>
{% for post in news_posts %}
<p>
<a href="?v=post&amp;p={{ post.post_id }}" class="input__button">{{ post.post_id }}</a>
<a href="?v=category&amp;c={{ post.category_id }}" class="input__button">Cat: {{ post.category_id }}</a>
<a href="{{ url('manage-news-post-edit', {'post': post.post_id}) }}" class="input__button">{{ post.post_id }}</a>
<a href="{{ url('manage-news-category-edit', {'category': post.category_id}) }}" class="input__button">Cat: {{ post.category_id }}</a>
{{ post.post_is_featured }},
{{ post.user_id }},
{{ post.post_title }},

View file

@ -3,7 +3,7 @@
{% block manage_content %}
{% if can_manage_roles %}
<a href="?v=role" class="input__button">Create new Role</a>
<a href="{{ url('manage-role-create') }}" class="input__button">Create new Role</a>
{% endif %}
<div class="userlist">
@ -11,7 +11,7 @@
<div class="userlist__item">
<div class="usercard">
<a href="?v=role&amp;r={{ role.role_id }}"
<a href="{{ url('manage-role-edit', {'role': role.role_id}) }}"
class="usercard__background"></a>
<div class="usercard__container">
@ -38,7 +38,7 @@
</div>
<div class="usercard__actions">
<a class="usercard__action" href="/members.php?r={{ role.role_id }}">
<a class="usercard__action" href="{{ url('members-role', {'role': role.role_id}) }}">
Members
</a>
</div>

View file

@ -32,7 +32,7 @@
{% if current_user.ban_expiration|default(0) > 0 or current_user.silence_expiration|default(0) > 0 %}
<div class="warning">
<div class="warning__content">
You have been {{ current_user.silence_expiration ? 'silenced' : 'banned' }} until <strong>{{ (current_user.silence_expiration ? current_user.silence_expiration : current_user.ban_expiration)|date('r') }}</strong>, view the account standing table on <a href="/profile.php?u={{ current_user.user_id }}#account-standing" class="warning__link">your profile</a> to view why.
You have been {{ current_user.silence_expiration ? 'silenced' : 'banned' }} until <strong>{{ (current_user.silence_expiration ? current_user.silence_expiration : current_user.ban_expiration)|date('r') }}</strong>, view the account standing table on <a href="{{ url('user-account-standing', {'user': current_user.user_id}) }}" class="warning__link">your profile</a> to view why.
</div>
</div>
{% endif %}
@ -52,6 +52,9 @@
<script type="application/json" id="js-csrf-tokens">
{{ get_csrf_tokens()|json_encode|raw }}
</script>
<script type="application/json" id="js-urls-list">
{{ url_list()|json_encode|raw }}
</script>
<script src="{{ '/js/libraries.js'|asset_url }}"></script>
<script src="{{ '/js/misuzu.js'|asset_url }}"></script>
</body>

View file

@ -17,7 +17,7 @@
{% endfor %}
<div class="container" style="padding: 4px; display: {{ news_pagination.pages > 1 ? 'block' : 'none' }}">
{{ pagination(news_pagination, '/news.php', null, {'c':category.category_id}, 'page') }}
{{ pagination(news_pagination, url('news-index'), null, {'c':category.category_id}, 'page') }}
</div>
</div>
@ -36,7 +36,7 @@
<div class="container__content">
{% for featured_post in featured %}
<a class="news__list__item" href="/news.php?p={{ featured_post.post_id }}">{{ featured_post.post_title }}</a>
<a class="news__list__item" href="{{ url('news-post', {'post': featured_post.post_id}) }}">{{ featured_post.post_title }}</a>
{% endfor %}
</div>
</div>

View file

@ -16,7 +16,7 @@
{% endfor %}
<div class="container" style="padding: 4px; display: {{ news_pagination.pages > 1 ? 'block' : 'none' }}">
{{ pagination(news_pagination, '/news.php', null, null, 'page') }}
{{ pagination(news_pagination, url('news-index'), null, null, 'page') }}
</div>
</div>
@ -26,7 +26,7 @@
<div class="container__content">
{% for category in categories %}
<a class="news__list__item news__list__item--kvp" href="/news.php?c={{ category.category_id }}">
<a class="news__list__item news__list__item--kvp" href="{{ url('news-category', {'category': category.category_id}) }}">
<div class="news__list__name">
{{ category.category_name }}
</div>

View file

@ -11,8 +11,8 @@
</div>
{% if post.user_id is not null %}
<a class="news__preview__user" href="/profile.php?u={{ post.user_id }}">
<div class="avatar news__preview__user__avatar" style="background-image:url('/profile.php?u={{ post.user_id }}&amp;m=avatar')"></div>
<a class="news__preview__user" href="{{ url('user-profile', {'user': post.user_id}) }}">
<div class="avatar news__preview__user__avatar" style="background-image:url('{{ url('user-avatar', {'user': post.user_id}) }}')"></div>
<div class="news__preview__user__name" style="{{ post.user_colour|html_colour }}">
{{ post.username }}
</div>
@ -21,13 +21,13 @@
</div>
<div class="news__preview__info">
<a href="/news.php?p={{ post.post_id }}" class="news__preview__link">
<a href="{{ url('news-post', {'post': post.post_id}) }}" class="news__preview__link">
<time class="news__preview__date" datetime="{{ post.post_created|date('c') }}" title="{{ post.post_created|date('r') }}">
{{ post.post_created|time_diff }}
</time>
</a>
<a href="/news.php?p={{ post.post_id }}#comments" class="news__preview__link">
<a href="{{ url('news-post-comments', {'post': post.post_id}) }}" class="news__preview__link">
{{ post.post_comments < 1 ? 'No' : post.post_comments|number_format }} comment{{ post.post_comments != 1 ? 's' : '' }}
</a>
</div>
@ -43,17 +43,17 @@
{% if post.user_id is not null %}
<div class="news__post__user">
<a class="avatar news__post__avatar"
style="background-image:url('/profile.php?u={{ post.user_id }}&amp;m=avatar');"
href="/profile.php?u={{ post.user_id }}">
style="background-image:url('{{ url('user-avatar', {'user': post.user_id}) }}');"
href="{{ url('user-profile', {'user': post.user_id}) }}">
</a>
<div class="news__post__user__details">
<a class="news__post__username" href="/profile.php?u={{ post.user_id }}">{{ post.username }}</a>
<a class="news__post__username" href="{{ url('user-profile', {'user': post.user_id}) }}">{{ post.username }}</a>
</div>
</div>
{% endif %}
<a class="news__post__category" href="/news.php?c={{ post.category_id }}">
<a class="news__post__category" href="{{ url('news-category', {'category': post.category_id}) }}">
{{ post.category_name }}
</a>

View file

@ -63,17 +63,17 @@
<div class="profile__header__actions">
{% if is_editing %}
<button class="input__button input__button--save profile__header__action">Save</button>
<a href="/profile.php?u={{ profile.user_id }}" class="input__button input__button--destroy profile__header__action">Discard</a>
<a href="/settings.php" class="input__button profile__header__action">Settings</a>
<a href="{{ url('user-profile', {'user': profile.user_id}) }}" class="input__button input__button--destroy profile__header__action">Discard</a>
<a href="{{ url('settings-index') }}" class="input__button profile__header__action">Settings</a>
{% elseif can_edit %}
<a href="/profile.php?u={{ profile.user_id }}&amp;m=edit" class="input__button profile__header__action">Edit Profile</a>
<a href="{{ url('user-profile-edit', {'user': profile.user_id}) }}" class="input__button profile__header__action">Edit Profile</a>
{% endif %}
{% if current_user is defined and current_user.user_id != profile.user_id and not is_editing %}
{% if friend_info.user_relation == constant('MSZ_USER_RELATION_FOLLOW') %}
<a href="/relations.php?u={{ profile.user_id }}&amp;m={{ constant('MSZ_USER_RELATION_NONE') }}&amp;c={{ csrf_token('user_relation') }}" class="input__button input__button--destroy profile__header__action js-user-relation-action" data-relation-user="{{ profile.user_id }}" data-relation-type="{{ constant('MSZ_USER_RELATION_NONE') }}">Unfollow</a>
<a href="{{ url('user-relation-none', {'user': profile.user_id}) }}" class="input__button input__button--destroy profile__header__action js-user-relation-action" data-relation-user="{{ profile.user_id }}" data-relation-type="{{ constant('MSZ_USER_RELATION_NONE') }}">Unfollow</a>
{% else %}
<a href="/relations.php?u={{ profile.user_id }}&amp;m={{ constant('MSZ_USER_RELATION_FOLLOW') }}&amp;c={{ csrf_token('user_relation') }}" class="input__button profile__header__action js-user-relation-action" data-relation-user="{{ profile.user_id }}" data-relation-type="{{ constant('MSZ_USER_RELATION_FOLLOW') }}">Follow</a>
<a href="{{ url('user-relation-follow', {'user': profile.user_id}) }}" class="input__button profile__header__action js-user-relation-action" data-relation-user="{{ profile.user_id }}" data-relation-type="{{ constant('MSZ_USER_RELATION_FOLLOW') }}">Follow</a>
{% endif %}
{% endif %}
</div>

View file

@ -78,7 +78,7 @@
<ul class="profile__guidelines__section">
<li class="profile__guidelines__line profile__guidelines__line--header">General</li>
<li class="profile__guidelines__line">Keep things sane and generally suitable for all ages.</li>
<li class="profile__guidelines__line">Make sure to adhere to the <a href="/info.php/rules" class="profile__guidelines__link">rules</a>.</li>
<li class="profile__guidelines__line">Make sure to adhere to the <a href="{{ url('info', {'title': 'rules'}) }}" class="profile__guidelines__link">rules</a>.</li>
</ul>
{% if perms.edit_avatar %}
@ -140,7 +140,7 @@
{% if current_user is not defined %}
<div class="container profile__container">
<div class="profile__accounts__notice">
You must <a href="/auth.php?m=login" class="profile__accounts__link">log in</a> to view full profiles!
You must <a href="{{ url('auth-login') }}" class="profile__accounts__link">log in</a> to view full profiles!
</div>
</div>
{% elseif show_profile_fields %}

View file

@ -316,27 +316,6 @@ function html_colour(?int $colour, $attribs = '--user-colour'): string
return $css;
}
function url_construct(string $url, array $query = [], ?string $fragment = null): string
{
if (count($query)) {
$url .= mb_strpos($url, '?') !== false ? '&' : '?';
foreach ($query as $key => $value) {
if ($value) {
$url .= rawurlencode($key) . '=' . rawurlencode($value) . '&';
}
}
$url = mb_substr($url, 0, -1);
}
if (!empty($fragment)) {
$url .= "#{$fragment}";
}
return $url;
}
function is_user_int($value): bool
{
return ctype_digit(strval($value));