Added ability to add redirects to deleted topic ids.

This commit is contained in:
flash 2023-04-30 00:18:14 +00:00
parent 6f679fc78c
commit 8038f61470
11 changed files with 275 additions and 24 deletions

View file

@ -0,0 +1,23 @@
<?php
use Index\Data\IDbConnection;
use Index\Data\Migration\IDbMigration;
final class CreateTopicRedirsTable_20230430_001226 implements IDbMigration {
public function migrate(IDbConnection $conn): void {
$conn->execute('
CREATE TABLE msz_forum_topics_redirects (
topic_id INT(10) UNSIGNED NOT NULL,
user_id INT(10) UNSIGNED NULL DEFAULT NULL,
topic_redir_url VARCHAR(255) NOT NULL,
topic_redir_created TIMESTAMP NOT NULL DEFAULT current_timestamp(),
PRIMARY KEY (topic_id),
KEY topics_redirs_user_foreign (user_id),
CONSTRAINT topics_redirs_user_foreign
FOREIGN KEY (user_id)
REFERENCES msz_users (user_id)
ON DELETE SET NULL
ON UPDATE CASCADE
) ENGINE=InnoDB COLLATE=utf8mb4_bin;
');
}
}

View file

@ -31,12 +31,21 @@ $perms = $topic
if(isset($topicUser) && $topicUser->hasActiveWarning()) if(isset($topicUser) && $topicUser->hasActiveWarning())
$perms &= ~MSZ_FORUM_PERM_SET_WRITE; $perms &= ~MSZ_FORUM_PERM_SET_WRITE;
$topicIsNuked = empty($topic['topic_id']);
$topicIsDeleted = !empty($topic['topic_deleted']); $topicIsDeleted = !empty($topic['topic_deleted']);
$canDeleteAny = perms_check($perms, MSZ_FORUM_PERM_DELETE_ANY_POST); $canDeleteAny = perms_check($perms, MSZ_FORUM_PERM_DELETE_ANY_POST);
if(!$topic || ($topicIsDeleted && !$canDeleteAny)) { if($topicIsNuked || $topicIsDeleted) {
echo render_error(404); $topicRedirectInfo = forum_topic_redir_info($topicId);
return; Template::set('topic_redir_info', $topicRedirectInfo);
if($topicIsNuked || !$canDeleteAny) {
if(empty($topicRedirectInfo))
echo render_error(404);
else
header('Location: ' . $topicRedirectInfo->topic_redir_url);
return;
}
} }
if(!perms_check($perms, MSZ_FORUM_PERM_VIEW_FORUM)) { if(!perms_check($perms, MSZ_FORUM_PERM_VIEW_FORUM)) {

View file

@ -0,0 +1,51 @@
<?php
namespace Misuzu;
use Misuzu\Users\User;
require_once '../../../misuzu.php';
if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_GENERAL, User::getCurrent()->getId(), MSZ_PERM_FORUM_TOPIC_REDIRS)) {
echo render_error(403);
return;
}
if($_SERVER['REQUEST_METHOD'] === 'POST') {
if(!CSRF::validateRequest())
throw new \Exception("Request verification failed.");
$rTopicId = (int)filter_input(INPUT_POST, 'topic_redir_id');
$rTopicURL = trim((string)filter_input(INPUT_POST, 'topic_redir_url'));
if($rTopicId < 1)
throw new \Exception("Invalid topic id.");
AuditLog::create($_SERVER['REMOTE_ADDR'], AuditLog::FORUM_TOPIC_REDIR_CREATE, [$rTopicId]);
forum_topic_redir_create($rTopicId, User::getCurrent()->getId(), $rTopicURL);
url_redirect('manage-forum-topic-redirs');
return;
}
if(filter_input(INPUT_GET, 'm') === 'explode') {
if(!CSRF::validateRequest())
throw new \Exception("Request verification failed.");
$rTopicId = (int)filter_input(INPUT_GET, 't');
AuditLog::create($_SERVER['REMOTE_ADDR'], AuditLog::FORUM_TOPIC_REDIR_REMOVE, [$rTopicId]);
forum_topic_redir_remove($rTopicId);
url_redirect('manage-forum-topic-redirs');
return;
}
$pagination = new Pagination(forum_topic_redir_count(), 20);
if(!$pagination->hasValidOffset()) {
echo render_error(404);
return;
}
$redirs = forum_topic_redir_all($pagination->getOffset(), $pagination->getRange());
Template::render('manage.forum.redirs', [
'manage_redirs' => $redirs,
'manage_redirs_pagination' => $pagination,
]);

View file

@ -40,6 +40,8 @@ class AuditLog {
public const FORUM_TOPIC_BUMP = 'FORUM_TOPIC_BUMP'; public const FORUM_TOPIC_BUMP = 'FORUM_TOPIC_BUMP';
public const FORUM_TOPIC_LOCK = 'FORUM_TOPIC_LOCK'; public const FORUM_TOPIC_LOCK = 'FORUM_TOPIC_LOCK';
public const FORUM_TOPIC_UNLOCK = 'FORUM_TOPIC_UNLOCK'; public const FORUM_TOPIC_UNLOCK = 'FORUM_TOPIC_UNLOCK';
public const FORUM_TOPIC_REDIR_CREATE = 'FORUM_TOPIC_REDIR_CREATE';
public const FORUM_TOPIC_REDIR_REMOVE = 'FORUM_TOPIC_REDIR_REMOVE';
public const FORUM_POST_EDIT = 'FORUM_POST_EDIT'; public const FORUM_POST_EDIT = 'FORUM_POST_EDIT';
public const FORUM_POST_DELETE = 'FORUM_POST_DELETE'; public const FORUM_POST_DELETE = 'FORUM_POST_DELETE';
@ -88,6 +90,8 @@ class AuditLog {
self::FORUM_TOPIC_BUMP => 'Manually bumped forum topic #%d.', self::FORUM_TOPIC_BUMP => 'Manually bumped forum topic #%d.',
self::FORUM_TOPIC_LOCK => 'Locked forum topic #%d.', self::FORUM_TOPIC_LOCK => 'Locked forum topic #%d.',
self::FORUM_TOPIC_UNLOCK => 'Unlocked forum topic #%d.', self::FORUM_TOPIC_UNLOCK => 'Unlocked forum topic #%d.',
self::FORUM_TOPIC_REDIR_CREATE => 'Created redirect for topic #%d.',
self::FORUM_TOPIC_REDIR_REMOVE => 'Removed redirect for topic #%d.',
self::CONFIG_CREATE => 'Created config value with name "%s".', self::CONFIG_CREATE => 'Created config value with name "%s".',
self::CONFIG_UPDATE => 'Updated config value with name "%s".', self::CONFIG_UPDATE => 'Updated config value with name "%s".',

View file

@ -108,6 +108,56 @@ function forum_topic_get(int $topicId, bool $allowDeleted = false): array {
return $getTopic->fetch(); return $getTopic->fetch();
} }
function forum_topic_redir_info(int $topicId): ?object {
$getTopicRedir = \Misuzu\DB::prepare('
SELECT topic_id, user_id, topic_redir_url,
UNIX_TIMESTAMP(topic_redir_created) AS topic_redir_created
FROM msz_forum_topics_redirects
WHERE topic_id = :topic_id
');
$getTopicRedir->bind('topic_id', $topicId);
return $getTopicRedir->fetchObject();
}
function forum_topic_redir_count(): int {
return \Misuzu\DB::query('SELECT COUNT(*) FROM msz_forum_topics_redirects')->fetchColumn() ?? 0;
}
function forum_topic_redir_all(int $offset, int $take): array {
$getTopicRedirs = \Misuzu\DB::prepare('
SELECT topic_id, user_id, topic_redir_url,
UNIX_TIMESTAMP(topic_redir_created) AS topic_redir_created
FROM msz_forum_topics_redirects
LIMIT :offset, :take
');
$getTopicRedirs->bind('offset', $offset);
$getTopicRedirs->bind('take', $take);
return $getTopicRedirs->fetchObjects();
}
function forum_topic_redir_create(int $topicId, int $userId, string $url): void {
if($topicId < 1 || empty($url)) return;
if($userId < 1) $userId = null;
$createTopicRedir = \Misuzu\DB::prepare('
INSERT INTO msz_forum_topics_redirects (topic_id, user_id, topic_redir_url)
VALUES (:topic_id, :user_id, :redir_url)
');
$createTopicRedir->bind('topic_id', $topicId);
$createTopicRedir->bind('user_id', $userId);
$createTopicRedir->bind('redir_url', $url);
$createTopicRedir->execute();
}
function forum_topic_redir_remove(int $topicId): void {
$removeTopicRedir = \Misuzu\DB::prepare('
DELETE FROM msz_forum_topics_redirects
WHERE topic_id = :topic_id
');
$removeTopicRedir->bind('topic_id', $topicId);
$removeTopicRedir->execute();
}
function forum_topic_bump(int $topicId): bool { function forum_topic_bump(int $topicId): bool {
$bumpTopic = \Misuzu\DB::prepare(' $bumpTopic = \Misuzu\DB::prepare('
UPDATE `msz_forum_topics` UPDATE `msz_forum_topics`

View file

@ -30,6 +30,8 @@ function manage_get_menu(int $userId): array {
if(perms_check_user(MSZ_PERMS_FORUM, $userId, MSZ_PERM_FORUM_MANAGE_FORUMS)) if(perms_check_user(MSZ_PERMS_FORUM, $userId, MSZ_PERM_FORUM_MANAGE_FORUMS))
$menu['Forum']['Categories'] = url('manage-forum-categories'); $menu['Forum']['Categories'] = url('manage-forum-categories');
if(perms_check_user(MSZ_PERMS_FORUM, $userId, MSZ_PERM_FORUM_TOPIC_REDIRS))
$menu['Forum']['Topic Redirects'] = url('manage-forum-topic-redirs');
if(perms_check_user(MSZ_PERMS_CHANGELOG, $userId, MSZ_PERM_CHANGELOG_MANAGE_CHANGES)) if(perms_check_user(MSZ_PERMS_CHANGELOG, $userId, MSZ_PERM_CHANGELOG_MANAGE_CHANGES))
$menu['Changelog']['Changes'] = url('manage-changelog-changes'); $menu['Changelog']['Changes'] = url('manage-changelog-changes');
@ -226,6 +228,11 @@ function manage_perms_list(array $rawPerms): array {
'title' => 'Can view the forum leaderboard live.', 'title' => 'Can view the forum leaderboard live.',
'perm' => MSZ_PERM_FORUM_VIEW_LEADERBOARD, 'perm' => MSZ_PERM_FORUM_VIEW_LEADERBOARD,
], ],
[
'section' => 'topic-redirs',
'title' => 'Can create redirects for deleted topics.',
'perm' => MSZ_PERM_FORUM_TOPIC_REDIRS,
],
], ],
], ],
[ [

View file

@ -34,6 +34,7 @@ define('MSZ_PERM_NEWS_MANAGE_CATEGORIES', 0x00000002);
define('MSZ_PERMS_FORUM', 'forum'); define('MSZ_PERMS_FORUM', 'forum');
define('MSZ_PERM_FORUM_MANAGE_FORUMS', 0x00000001); define('MSZ_PERM_FORUM_MANAGE_FORUMS', 0x00000001);
define('MSZ_PERM_FORUM_VIEW_LEADERBOARD', 0x00000002); define('MSZ_PERM_FORUM_VIEW_LEADERBOARD', 0x00000002);
define('MSZ_PERM_FORUM_TOPIC_REDIRS', 0x00000004);
define('MSZ_PERMS_COMMENTS', 'comments'); define('MSZ_PERMS_COMMENTS', 'comments');
define('MSZ_PERM_COMMENTS_CREATE', 0x00000001); define('MSZ_PERM_COMMENTS_CREATE', 0x00000001);

View file

@ -103,6 +103,9 @@ define('MSZ_URLS', [
'manage-forum-categories' => ['/manage/forum/index.php'], 'manage-forum-categories' => ['/manage/forum/index.php'],
'manage-forum-category' => ['/manage/forum/category.php', ['f' => '<forum>']], 'manage-forum-category' => ['/manage/forum/category.php', ['f' => '<forum>']],
'manage-forum-topic-redirs' => ['/manage/forum/redirs.php'],
'manage-forum-topic-redirs-create' => ['/manage/forum/redirs.php'],
'manage-forum-topic-redirs-nuke' => ['/manage/forum/redirs.php', ['m' => 'explode', 't' => '<topic>', 'csrf' => '{csrf}']],
'manage-changelog-changes' => ['/manage/changelog'], 'manage-changelog-changes' => ['/manage/changelog'],
'manage-changelog-change' => ['/manage/changelog/change.php', ['c' => '<change>']], 'manage-changelog-change' => ['/manage/changelog/change.php', ['c' => '<change>']],

View file

@ -209,24 +209,42 @@
</div> </div>
{% endmacro %} {% endmacro %}
{% macro forum_topic_locked(locked, archived) %} {% macro forum_topic_notice(icon, body) %}
{% if locked is not null or archived %} <div class="container forum__status">
<div class="container forum__status"> <div class="forum__status__icon">
<div class="forum__status__icon"> <div class="forum__status__icon__background"></div>
<div class="forum__status__icon__background"></div> <i class="fas fa-{{ icon }}"></i>
<i class="fas fa-{{ archived ? 'archive' : 'lock' }}"></i>
</div>
<div class="forum__status__text">
{% if archived %}
This topic has been <span class="forum__status__emphasis">archived</span>.
{% else %}
This topic was locked
<time class="forum__status__emphasis"
datetime="{{ locked|date('c') }}"
title="{{ locked|date('r') }}">{{ locked|time_diff }}</time>.
{% endif %}
</div>
</div> </div>
<div class="forum__status__text">
{{ body|raw }}
</div>
</div>
{% endmacro %}
{% macro forum_topic_redirect(redirect) %}
{% from _self import forum_topic_notice %}
{% if redirect is not empty %}
{% set body %}
This topic redirects to <span class="forum__status__emphasis"><a href="{{ redirect.topic_redir_url }}" class="link">{{ redirect.topic_redir_url }}</a></span>.
{% endset %}
{{ forum_topic_notice('share', body) }}
{% endif %}
{% endmacro %}
{% macro forum_topic_locked(locked, archived) %}
{% from _self import forum_topic_notice %}
{% if locked is not null or archived %}
{% set body %}
{% if archived %}
This topic has been <span class="forum__status__emphasis">archived</span>.
{% else %}
This topic was locked
<time class="forum__status__emphasis"
datetime="{{ locked|date('c') }}"
title="{{ locked|date('r') }}">{{ locked|time_diff }}</time>.
{% endif %}
{% endset %}
{{ forum_topic_notice(archived ? 'archive' : 'lock', body) }}
{% endif %} {% endif %}
{% endmacro %} {% endmacro %}

View file

@ -7,7 +7,8 @@
forum_topic_buttons, forum_topic_buttons,
forum_topic_locked, forum_topic_locked,
forum_header, forum_header,
forum_topic_tools forum_topic_tools,
forum_topic_redirect
%} %}
{% set title = topic_info.topic_title %} {% set title = topic_info.topic_title %}
@ -18,7 +19,7 @@
{% set forum_post_csrf = csrf_token() %} {% set forum_post_csrf = csrf_token() %}
{% set topic_tools = forum_topic_tools(topic_info, topic_pagination, can_reply) %} {% set topic_tools = forum_topic_tools(topic_info, topic_pagination, can_reply) %}
{% set topic_notice = forum_topic_locked(topic_info.topic_locked, topic_info.topic_archived) %} {% set topic_notice = forum_topic_locked(topic_info.topic_locked, topic_info.topic_archived) ~ forum_topic_redirect(topic_redir_info|default(null)) %}
{% set topic_actions = [ {% set topic_actions = [
{ {
'html': '<i class="far fa-trash-alt fa-fw"></i> Delete', 'html': '<i class="far fa-trash-alt fa-fw"></i> Delete',
@ -54,10 +55,10 @@
{% block content %} {% block content %}
{{ forum_header(topic_info.topic_title, topic_breadcrumbs, false, canonical_url, topic_actions) }} {{ forum_header(topic_info.topic_title, topic_breadcrumbs, false, canonical_url, topic_actions) }}
{{ topic_notice }} {{ topic_notice|raw }}
{{ topic_tools }} {{ topic_tools }}
{{ forum_post_listing(topic_posts, current_user.id|default(0), topic_perms) }} {{ forum_post_listing(topic_posts, current_user.id|default(0), topic_perms) }}
{{ topic_tools }} {{ topic_tools }}
{{ topic_notice }} {{ topic_notice|raw }}
{{ forum_header('', topic_breadcrumbs) }} {{ forum_header('', topic_breadcrumbs) }}
{% endblock %} {% endblock %}

View file

@ -0,0 +1,84 @@
{% extends 'manage/users/master.twig' %}
{% from 'macros.twig' import pagination, container_title %}
{% from '_layout/input.twig' import input_csrf, input_text %}
{% set redirs_pagination = pagination(manage_redirs_pagination, url('manage-forum-topic-redirs')) %}
{% block manage_content %}
<div class="container">
{{ container_title('<i class="fas fa-share fa-fw"></i> Topic Redirects') }}
<div class="manage__description">
Allows you to set redirects for deleted forum topics.
</div>
<form method="post" action="{{ url('manage-forum-topic-redirs-create') }}" class="manage-setting">
{{ input_csrf() }}
<label class="manage-setting-field">
<div class="manage-setting-field-name">Topic #</div>
{{ input_text('topic_redir_id', 'manage__emote__field__value', '', 'number') }}
</label>
<label class="manage-setting-field">
<div class="manage-setting-field-name">Target URL</div>
{{ input_text('topic_redir_url', 'manage__emote__field__value', '', 'text') }}
</label>
<div class="manage-setting-actions">
<button class="input__button input__button--save">Create</button>
</div>
</form>
{% if redirs_pagination|trim|length > 0 %}
<div class="manage__users__pagination">
{{ redirs_pagination }}
</div>
{% endif %}
<div class="manage-settings-list-container">
<table class="manage-settings-list">
<thead>
<tr class="manage-settings-list-header">
<th class="manage-settings-list-header-name">Topic #</th>
<th class="manage-settings-list-header-name">User #</th>
<th class="manage-settings-list-header-value">Target URL</th>
<th class="manage-settings-list-header-value">Created</th>
<th class="manage-settings-list-header-options">Options</th>
</tr>
</thead>
<tbody>
{% for redir in manage_redirs %}
<tr class="manage-list-setting">
<td class="manage-list-setting-key">
<div class="manage-list-setting-key-text">{{ redir.topic_id }}</div>
</td>
<td class="manage-list-setting-key">
<div class="manage-list-setting-key-text">{{ redir.user_id }}</div>
</td>
<td class="manage-list-setting-value">
<div class="manage-list-setting-value-text">{{ redir.topic_redir_url }}</div>
</td>
<td class="manage-list-setting-value">
<div class="manage-list-setting-value-text">
<time datetime="{{ redir.topic_redir_created|date('c') }}" title="{{ redir.topic_redir_created|date('r') }}">
{{ redir.topic_redir_created|time_diff }}
</time>
</div>
</td>
<td class="manage-list-setting-options">
<a class="input__button input__button--autosize input__button--destroy" href="{{ url('manage-forum-topic-redirs-nuke', {'topic': redir.topic_id}) }}" title="Delete"><i class="fas fa-times fa-fw"></i></a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% if redirs_pagination|trim|length > 0 %}
<div class="manage__users__pagination">
{{ redirs_pagination }}
</div>
{% endif %}
</div>
{% endblock %}