feat(admin): rebuild the restrictions tab on the reference ban modal
Replace the self-invented CRUD (warn/mute/suspend/ban + scope selector) with the reference-theme ban model: ban method (blackroom suspend / login ban), duration radios (1/7/14/30/100 days or permanent, default 7), preset reason chips with an other-reason input, ban note, delete-all- content switch (posts/comments to trash), and a no-appeal switch with a required notice that also gates the frontend appeal entry. Banned users render the status info view (status/start/end/reason) with an unban leave-a-message form; the record list uses the reference columns and per-user unban links. Bans notify the user in-site like the reference zib_updata_user_ban_msg.
This commit is contained in:
+256
-53
@@ -305,40 +305,141 @@ class UsersMenus {
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁封限制页 — 1:1 对齐参考主题 zib_get_set_user_ban_modal:
|
||||
* 禁封方式(拉入小黑屋/禁封用户)+ 禁封时间(1/7/14/30/100/永久)+
|
||||
* 选择禁封原因(预置徽章 + 其它原因)+ 禁封说明 + 删除全部内容 +
|
||||
* 禁止用户申诉(含说明);已禁封用户展示状态信息与解封留言表单。
|
||||
* 参考主题无 scope 维度,禁封一律全局。
|
||||
*/
|
||||
private function render_restrictions_tab(): void {
|
||||
if (!class_exists('\AKSRT\User\Restriction')) {
|
||||
echo '<div class="notice notice-error"><p>' . esc_html__('限制模块未初始化。', 'aksrt') . '</p></div>';
|
||||
return;
|
||||
}
|
||||
$svc = \AKSRT\User\Restriction::get_instance();
|
||||
$stats = $svc->get_stats();
|
||||
echo '<p>' . esc_html(sprintf(
|
||||
/* translators: 1 total 2 active 3 banned */
|
||||
__('限制记录 %1$d · 生效中 %2$d · 封禁中 %3$d', 'aksrt'),
|
||||
(int) ($stats['total'] ?? 0),
|
||||
(int) ($stats['active'] ?? 0),
|
||||
(int) ($stats['banned'] ?? 0)
|
||||
)) . '</p>';
|
||||
|
||||
echo '<h2>' . esc_html__('添加限制', 'aksrt') . '</h2>';
|
||||
echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '" style="margin-bottom:20px;display:flex;gap:8px;flex-wrap:wrap;align-items:end;">';
|
||||
echo '<input type="hidden" name="action" value="aksrt_users_add_restriction" />';
|
||||
wp_nonce_field('aksrt_users_add_restriction');
|
||||
echo '<p><label>' . esc_html__('用户 ID', 'aksrt') . '<br><input type="number" name="user_id" min="1" required value="' . esc_attr((string) (isset($_GET['user_id']) ? max(0, (int) $_GET['user_id']) : 0)) . '" /></label></p>';
|
||||
echo '<p><label>' . esc_html__('类型', 'aksrt') . '<br><select name="type">';
|
||||
foreach (['warn' => __('警告', 'aksrt'), 'mute' => __('禁言', 'aksrt'), 'suspend' => __('停权', 'aksrt'), 'ban' => __('封禁', 'aksrt')] as $key => $label) {
|
||||
printf('<option value="%s">%s</option>', esc_attr($key), esc_html($label));
|
||||
$page_url = admin_url('users.php?page=aksrt_user_ban&tab=restrictions');
|
||||
$target_id = isset($_GET['user_id']) ? max(0, (int) $_GET['user_id']) : 0;
|
||||
$unban = isset($_GET['action']) && sanitize_key((string) wp_unslash($_GET['action'])) === 'unban';
|
||||
$target = $target_id > 0 ? get_userdata($target_id) : null;
|
||||
|
||||
// 页面级样式(wp-admin 不加载前端 kit,就地声明参考主题同款外观)
|
||||
echo '<style>
|
||||
.aksrt-ban-modal .muted-2-color{color:#777;}
|
||||
.aksrt-ban-modal .author-set-left{min-width:80px;flex:0 0 auto;color:#777;}
|
||||
.aksrt-ban-modal .author-set-right{margin-top:0;}
|
||||
.aksrt-ban-modal .form-radio label{display:inline-block;margin:0 6px 6px 0;}
|
||||
.aksrt-ban-modal .form-radio input[type=radio]{display:none;}
|
||||
.aksrt-ban-modal .form-radio input[type=radio]+span{display:inline-block;padding:4px 10px;border:1px solid #dcdcde;border-radius:4px;background:#f6f7f7;cursor:pointer;}
|
||||
.aksrt-ban-modal .form-radio input[type=radio]:checked+span{background:#2271b1;border-color:#2271b1;color:#fff;}
|
||||
.aksrt-ban-modal .but-average.modal-buts{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:16px;max-width:480px;}
|
||||
.aksrt-ban-modal .but-average.modal-buts .but{min-height:40px;text-align:center;border-radius:10px;border:1px solid #dcdcde;background:#f6f7f7;font-weight:600;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;}
|
||||
.aksrt-ban-modal .but-average.modal-buts .but.c-blue{background:#2271b1;border-color:#2271b1;color:#fff;}
|
||||
.aksrt-ban-modal .but-average.modal-buts .but.c-yellow{background:#dba617;border-color:#dba617;color:#fff;}
|
||||
.aksrt-ban-modal .switch-row{display:flex;align-items:center;margin:0 0 14px;font-weight:400;}
|
||||
.aksrt-ban-modal .switch-row .switch-title{color:#777;margin-bottom:3px;}
|
||||
.aksrt-ban-modal .switch-row .switch-help{color:#a7aaad;font-size:12px;}
|
||||
.aksrt-ban-modal textarea,.aksrt-ban-modal input[type=text]{width:100%;max-width:560px;}
|
||||
</style>';
|
||||
|
||||
// 当前生效中的全局禁封(ban 优先于 suspend,对齐参考主题单一状态语义)
|
||||
$current = null;
|
||||
if ($target_id > 0) {
|
||||
foreach ($svc->get_user_restrictions($target_id, true) as $r) {
|
||||
if (($r['scope'] ?? '') !== 'global' || !in_array($r['type'], ['ban', 'suspend'], true)) {
|
||||
continue;
|
||||
}
|
||||
echo '</select></label></p>';
|
||||
echo '<p><label>' . esc_html__('范围', 'aksrt') . '<br><select name="scope">';
|
||||
foreach (['global' => __('全局', 'aksrt'), 'comment' => __('评论', 'aksrt')] as $key => $label) {
|
||||
printf('<option value="%s">%s</option>', esc_attr($key), esc_html($label));
|
||||
if ($current === null || ($r['type'] === 'ban' && $current['type'] !== 'ban')) {
|
||||
$current = $r;
|
||||
}
|
||||
echo '</select></label></p>';
|
||||
echo '<p><label>' . esc_html__('原因', 'aksrt') . '<br><input type="text" name="reason" class="regular-text" required /></label></p>';
|
||||
submit_button(__('添加', 'aksrt'), 'primary', '', false);
|
||||
}
|
||||
}
|
||||
|
||||
echo '<div class="table-box aksrt-ban-modal" style="max-width:760px;padding:12px 16px;">';
|
||||
|
||||
if (!$target) {
|
||||
echo '<p>' . esc_html__('请先通过“用户 ID”定位要禁封或解封的用户(也可从工单列表的“点击此处”进入)。', 'aksrt') . '</p>';
|
||||
} elseif ($current !== null) {
|
||||
// —— 已禁封视图(参考主题解封弹窗同构):状态信息 + 解封留言表单 ——
|
||||
$unban_title = $current['type'] === 'ban' ? __('解封用户', 'aksrt') : __('移出小黑屋', 'aksrt');
|
||||
$status_text = $current['type'] === 'ban' ? __('禁封中(禁止登录)', 'aksrt') : __('小黑屋禁封中', 'aksrt');
|
||||
$end_time = !empty($current['expires_at']) ? (string) $current['expires_at'] : __('永久', 'aksrt');
|
||||
echo '<h2 style="margin-top:0;">' . esc_html($unban_title) . '</h2>';
|
||||
echo '<div class="mb10 flex"><div class="author-set-left">' . esc_html__('用户', 'aksrt') . '</div><div class="author-set-right">' . esc_html($target->display_name) . '</div></div>';
|
||||
echo '<div class="mb10 flex"><div class="author-set-left">' . esc_html__('状态', 'aksrt') . '</div><div class="author-set-right">' . esc_html($status_text) . '</div></div>';
|
||||
echo '<div class="mb10 flex"><div class="author-set-left">' . esc_html__('开始时间', 'aksrt') . '</div><div class="author-set-right">' . esc_html((string) ($current['created_at'] ?? '')) . '</div></div>';
|
||||
echo '<div class="mb10 flex"><div class="author-set-left">' . esc_html__('结束时间', 'aksrt') . '</div><div class="author-set-right">' . esc_html($end_time) . '</div></div>';
|
||||
echo '<div class="mb10 flex"><div class="author-set-left">' . esc_html__('原因', 'aksrt') . '</div><div class="author-set-right">' . nl2br(esc_html((string) ($current['reason'] ?? ''))) . '</div></div>';
|
||||
echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '">';
|
||||
echo '<input type="hidden" name="action" value="aksrt_users_remove_restriction" />';
|
||||
echo '<input type="hidden" name="user_id" value="' . esc_attr((string) $target_id) . '" />';
|
||||
wp_nonce_field('aksrt_users_unban_' . $target_id);
|
||||
echo '<p><textarea class="large-text" name="desc" rows="2" placeholder="' . esc_attr__('给用户的留言', 'aksrt') . '"></textarea></p>';
|
||||
echo '<div class="but-average modal-buts">';
|
||||
echo '<a class="but" href="' . esc_url($page_url) . '">' . esc_html__('取消', 'aksrt') . '</a>';
|
||||
echo '<button type="submit" class="but c-yellow">' . esc_html(sprintf(__('确认%s', 'aksrt'), $unban_title)) . '</button>';
|
||||
echo '</div>';
|
||||
echo '</form>';
|
||||
} else {
|
||||
// —— 禁封表单(参考主题禁封弹窗同构) ——
|
||||
echo '<h2 style="margin-top:0;">' . esc_html__('禁封用户', 'aksrt') . '</h2>';
|
||||
echo '<form class="aksrt-ban-form" method="post" action="' . esc_url(admin_url('admin-post.php')) . '">';
|
||||
echo '<input type="hidden" name="action" value="aksrt_users_add_restriction" />';
|
||||
echo '<input type="hidden" name="user_id" value="' . esc_attr((string) $target_id) . '" />';
|
||||
wp_nonce_field('aksrt_users_add_restriction');
|
||||
|
||||
echo '<div class="mt10 mb20 flex ac mb6">' . get_avatar($target_id, 40, '', '', ['class' => 'avatar-mini mr6']) . '<b>' . esc_html($target->display_name) . '</b></div>';
|
||||
|
||||
// 禁封方式
|
||||
echo '<div class="mb6 muted-2-color">' . esc_html__('禁封方式', 'aksrt') . '</div>';
|
||||
echo '<div class="form-radio form-but-radio">';
|
||||
echo '<label><input type="radio" name="ban" value="1" checked="checked"><span class="p2-10 mr6">' . esc_html__('拉入小黑屋', 'aksrt') . '</span></label>';
|
||||
echo '<label><input type="radio" name="ban" value="2"><span class="p2-10 mr6">' . esc_html__('禁封用户', 'aksrt') . '</span></label>';
|
||||
echo '</div>';
|
||||
echo '<div class="em09 c-red opacity8 mb10">';
|
||||
echo '<div data-aksrt-ban-desc="1">' . esc_html__('将用户拉入小黑屋后,用户将失去所有的发布权限及大部分的操作权限,例如发帖、评论等', 'aksrt') . '</div>';
|
||||
echo '<div data-aksrt-ban-desc="2" style="display:none;">' . esc_html__('禁封的用户将不能登录', 'aksrt') . '</div>';
|
||||
echo '</div>';
|
||||
|
||||
// 禁封时间
|
||||
echo '<div class="mb6 muted-2-color">' . esc_html__('禁封时间', 'aksrt') . '</div>';
|
||||
echo '<div class="form-radio mb10 form-but-radio">';
|
||||
foreach ([1 => __('1天', 'aksrt'), 7 => __('7天', 'aksrt'), 14 => __('14天', 'aksrt'), 30 => __('30天', 'aksrt'), 100 => __('100天', 'aksrt'), 0 => __('永久', 'aksrt')] as $days => $label) {
|
||||
echo '<label><input type="radio" name="time_day" value="' . esc_attr((string) $days) . '"' . checked(7, $days, false) . '><span class="p2-10 mr6">' . esc_html($label) . '</span></label>';
|
||||
}
|
||||
echo '</div>';
|
||||
|
||||
// 选择禁封原因(预置原因 + 其它原因)
|
||||
echo '<div class="mb6 muted-2-color">' . esc_html__('选择禁封原因', 'aksrt') . '</div>';
|
||||
echo '<div class="form-radio mb10 form-but-radio">';
|
||||
foreach (\AKSRT\Settings\UserRuntime::ban_settings()['reasons'] ?? [] as $reason) {
|
||||
echo '<label><input type="radio" name="reason" value="' . esc_attr($reason['name']) . '"><span class="p2-10 mr6">' . esc_html($reason['name']) . '</span></label>';
|
||||
}
|
||||
echo '<label><input type="radio" name="reason" value="other"><span class="p2-10 mr6">' . esc_html__('其它原因', 'aksrt') . '</span></label>';
|
||||
echo '</div>';
|
||||
echo '<div class="aksrt-reason-other mb20" style="display:none;"><input type="text" class="regular-text" name="reason_other" placeholder="' . esc_attr__('请填写禁封原因', 'aksrt') . '"></div>';
|
||||
|
||||
// 禁封说明
|
||||
echo '<div class="mb6 muted-2-color">' . esc_html__('禁封说明', 'aksrt') . '</div>';
|
||||
echo '<p><textarea class="large-text" name="desc" rows="2" placeholder="' . esc_attr__('请输入禁封说明或给用户的留言', 'aksrt') . '"></textarea></p>';
|
||||
|
||||
// 删除全部内容
|
||||
echo '<div class="switch-row"><label><input type="checkbox" name="delete_content" value="1"> <span class="flex1 mr20"><span class="switch-title">' . esc_html__('删除全部内容', 'aksrt') . '</span><br><span class="switch-help">' . esc_html__('将该用户发布的全部文章、帖子、评论移至回收站', 'aksrt') . '</span></span></label></div>';
|
||||
|
||||
// 禁止用户申诉
|
||||
echo '<div class="switch-row"><label><input type="checkbox" name="no_appeal" value="1"> <span class="flex1 mr20"><span class="switch-title">' . esc_html__('禁止用户申诉', 'aksrt') . '</span><br><span class="switch-help">' . esc_html__('开启后用户将无法进行申诉', 'aksrt') . '</span></span></label></div>';
|
||||
echo '<div class="aksrt-no-appeal-desc mb20" style="display:none;"><textarea class="large-text" name="no_appeal_desc" rows="2" placeholder="' . esc_attr__('请填写禁止申诉说明', 'aksrt') . '"></textarea></div>';
|
||||
|
||||
echo '<div class="but-average modal-buts">';
|
||||
echo '<a class="but" href="' . esc_url($page_url) . '">' . esc_html__('取消', 'aksrt') . '</a>';
|
||||
echo '<button type="submit" class="but c-blue">' . esc_html__('确认提交', 'aksrt') . '</button>';
|
||||
echo '</div>';
|
||||
echo '</form>';
|
||||
}
|
||||
echo '</div>';
|
||||
|
||||
// —— 限制记录列表(参考主题列语义:状态/开始/结束/原因) ——
|
||||
global $wpdb;
|
||||
$table = class_exists('\AKSRT\Core\DBMigrator') ? \AKSRT\Core\DBMigrator::table('user_restriction') : '';
|
||||
if ($table === '') {
|
||||
@@ -346,31 +447,63 @@ class UsersMenus {
|
||||
return;
|
||||
}
|
||||
$items = $wpdb->get_results("SELECT * FROM {$table} ORDER BY id DESC LIMIT 100", ARRAY_A);
|
||||
$now = gmdate('Y-m-d H:i:s');
|
||||
echo '<h2>' . esc_html__('限制记录', 'aksrt') . '</h2>';
|
||||
echo '<table class="wp-list-table widefat fixed striped"><thead><tr>';
|
||||
echo '<th>ID</th><th>' . esc_html__('用户', 'aksrt') . '</th><th>' . esc_html__('类型', 'aksrt') . '</th><th>' . esc_html__('范围', 'aksrt') . '</th><th>' . esc_html__('原因', 'aksrt') . '</th><th>' . esc_html__('过期', 'aksrt') . '</th><th>' . esc_html__('操作', 'aksrt') . '</th>';
|
||||
echo '<th>' . esc_html__('用户', 'aksrt') . '</th><th>' . esc_html__('禁封状态', 'aksrt') . '</th><th>' . esc_html__('开始时间', 'aksrt') . '</th><th>' . esc_html__('结束时间', 'aksrt') . '</th><th>' . esc_html__('原因', 'aksrt') . '</th><th>' . esc_html__('操作', 'aksrt') . '</th>';
|
||||
echo '</tr></thead><tbody>';
|
||||
if (!$items) {
|
||||
echo '<tr><td colspan="7">' . esc_html__('暂无限制记录', 'aksrt') . '</td></tr>';
|
||||
echo '<tr><td colspan="6">' . esc_html__('暂无限制记录', 'aksrt') . '</td></tr>';
|
||||
}
|
||||
foreach ((array) $items as $row) {
|
||||
$id = (int) ($row['id'] ?? 0);
|
||||
$user_id = (int) ($row['user_id'] ?? 0);
|
||||
$user = $user_id > 0 ? get_userdata($user_id) : null;
|
||||
foreach ((array) $items as $r) {
|
||||
$type = (string) ($r['type'] ?? '');
|
||||
$expired = !empty($r['expires_at']) && (string) $r['expires_at'] <= $now;
|
||||
$is_global = ($r['scope'] ?? '') === 'global' && in_array($type, ['ban', 'suspend'], true);
|
||||
if ($expired) {
|
||||
$status_html = '<span style="color:#a7aaad;">' . esc_html__('已过期', 'aksrt') . '</span>';
|
||||
} elseif ($type === 'ban') {
|
||||
$status_html = '<span style="color:#fb4444;">' . esc_html__('禁封中(禁止登录)', 'aksrt') . '</span>';
|
||||
} elseif ($type === 'suspend') {
|
||||
$status_html = '<span style="color:#fd6a11;">' . esc_html__('小黑屋禁封中', 'aksrt') . '</span>';
|
||||
} elseif ($type === 'mute') {
|
||||
$status_html = '<span style="color:#fd6a11;">' . esc_html__('禁言中', 'aksrt') . '</span>';
|
||||
} else {
|
||||
$status_html = '<span>' . esc_html__('警告', 'aksrt') . '</span>';
|
||||
}
|
||||
$r_user_id = (int) ($r['user_id'] ?? 0);
|
||||
$r_user = $r_user_id > 0 ? get_userdata($r_user_id) : null;
|
||||
echo '<tr>';
|
||||
echo '<td>' . esc_html((string) $id) . '</td>';
|
||||
echo '<td>' . ($user ? esc_html($user->display_name) : esc_html((string) $user_id)) . '</td>';
|
||||
echo '<td>' . esc_html((string) ($row['type'] ?? '')) . '</td>';
|
||||
echo '<td>' . esc_html((string) ($row['scope'] ?? '')) . '</td>';
|
||||
echo '<td>' . esc_html((string) ($row['reason'] ?? '')) . '</td>';
|
||||
echo '<td>' . esc_html((string) ($row['expires_at'] ?? '—')) . '</td>';
|
||||
echo '<td><form method="post" action="' . esc_url(admin_url('admin-post.php')) . '">';
|
||||
echo '<input type="hidden" name="action" value="aksrt_users_remove_restriction" />';
|
||||
echo '<input type="hidden" name="restriction_id" value="' . esc_attr((string) $id) . '" />';
|
||||
wp_nonce_field('aksrt_users_remove_restriction_' . $id);
|
||||
submit_button(__('移除', 'aksrt'), 'small', '', false);
|
||||
echo '</form></td></tr>';
|
||||
echo '<td>' . ($r_user ? esc_html($r_user->display_name) : esc_html((string) $r_user_id)) . '</td>';
|
||||
echo '<td>' . $status_html . '</td>';
|
||||
echo '<td>' . esc_html((string) ($r['created_at'] ?? '')) . '</td>';
|
||||
echo '<td>' . esc_html(!empty($r['expires_at']) ? (string) $r['expires_at'] : __('永久', 'aksrt')) . '</td>';
|
||||
echo '<td>' . nl2br(esc_html((string) ($r['reason'] ?? ''))) . '</td>';
|
||||
echo '<td>';
|
||||
if ($is_global && !$expired) {
|
||||
echo '<a class="button" href="' . esc_url(add_query_arg(['action' => 'unban', 'user_id' => $r_user_id], $page_url)) . '">' . esc_html(($type === 'ban' ? __('解封', 'aksrt') : __('移出小黑屋', 'aksrt'))) . '</a>';
|
||||
}
|
||||
echo '</td></tr>';
|
||||
}
|
||||
echo '</tbody></table>';
|
||||
|
||||
// 依赖联动(参考主题 dependency-box 同语义):禁封方式说明/其它原因/禁止申诉说明
|
||||
echo '<script>
|
||||
(function ($) {
|
||||
function syncBanForm() {
|
||||
$(".aksrt-ban-modal").each(function () {
|
||||
var $box = $(this);
|
||||
var ban = $box.find("input[name=\\"ban\\"]:checked").val();
|
||||
$box.find("[data-aksrt-ban-desc]").each(function () {
|
||||
$(this).toggle($(this).attr("data-aksrt-ban-desc") === ban);
|
||||
});
|
||||
$box.find(".aksrt-reason-other").toggle($box.find("input[name=\\"reason\\"]:checked").val() === "other");
|
||||
$box.find(".aksrt-no-appeal-desc").toggle($box.find("input[name=\\"no_appeal\\"]").is(":checked"));
|
||||
});
|
||||
}
|
||||
$(document).on("change", ".aksrt-ban-modal input", syncBanForm);
|
||||
$(document).ready(syncBanForm);
|
||||
})(jQuery);
|
||||
</script>';
|
||||
}
|
||||
|
||||
public function handle_update_report(): void {
|
||||
@@ -390,26 +523,96 @@ class UsersMenus {
|
||||
wp_die(esc_html__('权限不足', 'aksrt'));
|
||||
}
|
||||
check_admin_referer('aksrt_users_add_restriction');
|
||||
|
||||
$user_id = isset($_POST['user_id']) ? (int) $_POST['user_id'] : 0;
|
||||
$type = isset($_POST['type']) ? sanitize_key((string) wp_unslash($_POST['type'])) : 'warn';
|
||||
$scope = isset($_POST['scope']) ? sanitize_key((string) wp_unslash($_POST['scope'])) : 'global';
|
||||
$reason = isset($_POST['reason']) ? sanitize_text_field((string) wp_unslash($_POST['reason'])) : '';
|
||||
$ok = false;
|
||||
if ($user_id > 0 && $reason !== '' && class_exists('\AKSRT\User\Restriction')) {
|
||||
$result = \AKSRT\User\Restriction::get_instance()->restrict($user_id, $type, $reason, $scope, '', get_current_user_id());
|
||||
$ok = !empty($result['id']) || !empty($result['success']) || is_array($result);
|
||||
if ($user_id <= 0 || !get_userdata($user_id)) {
|
||||
$this->redirect('aksrt_user_ban', 'restriction_failed', ['tab' => 'restrictions']);
|
||||
}
|
||||
$this->redirect('aksrt_user_ban', $ok ? 'restriction_added' : 'restriction_failed', ['tab' => 'restrictions']);
|
||||
|
||||
// 禁封方式(参考主题语义):1=拉入小黑屋(suspend) / 2=禁封用户(ban,禁止登录)
|
||||
$ban = isset($_POST['ban']) ? (int) $_POST['ban'] : 1;
|
||||
$type = $ban === 2 ? 'ban' : 'suspend';
|
||||
$time_day = isset($_POST['time_day']) ? (int) $_POST['time_day'] : 0;
|
||||
$desc = isset($_POST['desc']) ? sanitize_textarea_field((string) wp_unslash($_POST['desc'])) : '';
|
||||
|
||||
// 原因:预置徽章值或“其它原因”自定义文本
|
||||
$reason = isset($_POST['reason']) ? sanitize_text_field((string) wp_unslash($_POST['reason'])) : '';
|
||||
if ($reason === '' || $reason === 'other') {
|
||||
$reason = isset($_POST['reason_other']) ? sanitize_text_field((string) wp_unslash($_POST['reason_other'])) : '';
|
||||
}
|
||||
if ($reason === '') {
|
||||
$this->redirect('aksrt_user_ban', 'restriction_failed', ['tab' => 'restrictions', 'user_id' => $user_id]);
|
||||
}
|
||||
if ($desc !== '') {
|
||||
$reason .= "\n" . sprintf(__('禁封说明:%s', 'aksrt'), $desc);
|
||||
}
|
||||
|
||||
$no_appeal = !empty($_POST['no_appeal']);
|
||||
$no_appeal_desc = isset($_POST['no_appeal_desc']) ? sanitize_textarea_field((string) wp_unslash($_POST['no_appeal_desc'])) : '';
|
||||
if ($no_appeal && $no_appeal_desc === '') {
|
||||
// 参考主题同校验:勾选禁止申诉必须填写说明
|
||||
$this->redirect('aksrt_user_ban', 'restriction_failed', ['tab' => 'restrictions', 'user_id' => $user_id]);
|
||||
}
|
||||
|
||||
$expires = $time_day > 0 ? date('Y-m-d H:i:s', strtotime('+' . $time_day . ' day', current_time('timestamp'))) : '';
|
||||
$result = \AKSRT\User\Restriction::get_instance()->restrict($user_id, $type, $reason, 'global', $expires, get_current_user_id());
|
||||
$ok = !empty($result['success']);
|
||||
if ($ok) {
|
||||
// 禁封状态变更站内信(参考主题 zib_updata_user_ban_msg 同语义)
|
||||
$msg = $type === 'ban' ? __('您的账号已被禁封,将无法登录。', 'aksrt') : __('您已被拉入小黑屋,发布等相关权限已被限制。', 'aksrt');
|
||||
if ($time_day > 0) {
|
||||
$msg .= ' ' . sprintf(__('期限:%1$d 天,%2$s 起自动解封。', 'aksrt'), $time_day, $expires);
|
||||
}
|
||||
\AKSRT\Messages\Message::get_instance()->send($user_id, 'system', $msg, ['title' => __('账号限制', 'aksrt')]);
|
||||
|
||||
if ($no_appeal) {
|
||||
update_user_meta($user_id, '_aksrt_no_appeal', [
|
||||
'desc' => $no_appeal_desc,
|
||||
'at' => current_time('mysql'),
|
||||
]);
|
||||
}
|
||||
|
||||
// 删除全部内容:文章/帖子/评论移至回收站(参考主题同行为)
|
||||
if (!empty($_POST['delete_content'])) {
|
||||
$post_ids = get_posts([
|
||||
'author' => $user_id,
|
||||
'post_type' => get_post_types(['public' => true]),
|
||||
'post_status' => 'publish',
|
||||
'numberposts' => -1,
|
||||
'fields' => 'ids',
|
||||
]);
|
||||
foreach ($post_ids as $pid) {
|
||||
wp_trash_post((int) $pid);
|
||||
}
|
||||
foreach (get_comments(['user_id' => $user_id, 'status' => 'approve', 'number' => 500]) as $comment) {
|
||||
wp_trash_comment((int) $comment->comment_ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->redirect('aksrt_user_ban', $ok ? 'restriction_added' : 'restriction_failed', ['tab' => 'restrictions', 'user_id' => $user_id]);
|
||||
}
|
||||
|
||||
public function handle_remove_restriction(): void {
|
||||
if (!current_user_can(self::CAPABILITY)) {
|
||||
wp_die(esc_html__('权限不足', 'aksrt'));
|
||||
}
|
||||
$id = isset($_POST['restriction_id']) ? (int) $_POST['restriction_id'] : 0;
|
||||
check_admin_referer('aksrt_users_remove_restriction_' . $id);
|
||||
$ok = $id > 0 && class_exists('\AKSRT\User\Restriction') && \AKSRT\User\Restriction::get_instance()->remove_restriction($id);
|
||||
$this->redirect('aksrt_user_ban', $ok ? 'restriction_removed' : 'restriction_failed', ['tab' => 'restrictions']);
|
||||
$user_id = isset($_POST['user_id']) ? (int) $_POST['user_id'] : 0;
|
||||
check_admin_referer('aksrt_users_unban_' . $user_id);
|
||||
$desc = isset($_POST['desc']) ? sanitize_textarea_field((string) wp_unslash($_POST['desc'])) : '';
|
||||
|
||||
$removed = $user_id > 0 && class_exists('\AKSRT\User\Restriction')
|
||||
? \AKSRT\User\Restriction::get_instance()->lift_user_restriction($user_id)
|
||||
: 0;
|
||||
delete_user_meta($user_id, '_aksrt_no_appeal');
|
||||
|
||||
// 解封站内信(含给用户的留言)
|
||||
$msg = __('您的账号限制已解除。', 'aksrt');
|
||||
if ($desc !== '') {
|
||||
$msg .= ' ' . sprintf(__('留言:%s', 'aksrt'), $desc);
|
||||
}
|
||||
\AKSRT\Messages\Message::get_instance()->send($user_id, 'system', $msg, ['title' => __('限制解除', 'aksrt')]);
|
||||
|
||||
$this->redirect('aksrt_user_ban', $removed > 0 ? 'restriction_removed' : 'restriction_failed', ['tab' => 'restrictions', 'user_id' => $user_id]);
|
||||
}
|
||||
|
||||
public function handle_process_appeal(): void {
|
||||
|
||||
@@ -97,6 +97,11 @@ class BanAppeal {
|
||||
if (!$banned) {
|
||||
wp_send_json(['error' => 1, 'msg' => __('当前账号未处于禁封状态', 'aksrt')]);
|
||||
}
|
||||
// 禁封时勾选“禁止用户申诉”的门禁(参考主题 no_appeal 同语义)。
|
||||
$no_appeal = get_user_meta($user_id, '_aksrt_no_appeal', true);
|
||||
if (is_array($no_appeal) && $no_appeal['desc'] !== '') {
|
||||
wp_send_json(['error' => 1, 'msg' => sprintf(__('当前账号已被限制申诉:%s', 'aksrt'), (string) $no_appeal['desc'])]);
|
||||
}
|
||||
if (self::get_status($user_id) === 'pending') {
|
||||
wp_send_json(['error' => 1, 'msg' => __('申诉正在处理中,请勿重复提交', 'aksrt')]);
|
||||
}
|
||||
|
||||
@@ -251,8 +251,31 @@ test('comments expose a report entry for other users when reporting is enabled',
|
||||
assert.doesNotMatch(commentItem, /\$report\s*=\s*aksrt_get_comment_report_html\(\$comment\)/)
|
||||
})
|
||||
|
||||
test('restrictions tab mirrors the reference ban modal 1:1', () => {
|
||||
// 禁封方式/禁封时间/预置原因徽章/禁封说明/删除全部内容/禁止用户申诉,
|
||||
// 以及已禁封用户的状态信息与解封留言表单(zib_get_set_user_ban_modal 同构)。
|
||||
for (const label of ['拉入小黑屋', '禁封用户', '禁封方式', '禁封时间', '选择禁封原因', '其它原因', '禁封说明', '删除全部内容', '禁止用户申诉', '请填写禁止申诉说明', '解封用户', '移出小黑屋', '小黑屋禁封中', '禁封中(禁止登录)', '给用户的留言', '开始时间', '结束时间']) {
|
||||
assert.ok(usersMenus.includes(label), `restrictions tab missing reference label: ${label}`)
|
||||
}
|
||||
// 时长选项 1/7/14/30/100/永久(默认 7 天);类型映射:小黑屋→suspend,禁封→ban。
|
||||
assert.match(usersMenus, /1 => __\('1天', 'aksrt'\)/)
|
||||
assert.match(usersMenus, /7 => __\('7天', 'aksrt'\)/)
|
||||
assert.match(usersMenus, /100 => __\('100天', 'aksrt'\)/)
|
||||
assert.match(usersMenus, /checked\(7, \$days, false\)/)
|
||||
assert.match(usersMenus, /\$type\s*=\s*\$ban === 2 \? 'ban' : 'suspend'/)
|
||||
// 勾选禁止申诉必须填写说明(参考主题同校验),落用户 meta 供申诉入口拦截。
|
||||
assert.match(usersMenus, /_aksrt_no_appeal/)
|
||||
assert.match(usersMenus, /请填写禁止申诉说明/)
|
||||
const appeal = read('src/User/BanAppeal.php')
|
||||
assert.match(appeal, /_aksrt_no_appeal/)
|
||||
// 解封流程:按用户解封 + 留言站内信(旧 restriction_id 通道退役)。
|
||||
assert.match(usersMenus, /wp_nonce_field\('aksrt_users_unban_' \. \$target_id\)/)
|
||||
assert.match(usersMenus, /lift_user_restriction\(\$user_id\)/)
|
||||
assert.ok(!usersMenus.includes('name="restriction_id"'), 'per-record removal superseded by per-user unban')
|
||||
})
|
||||
|
||||
test('uninstall cleans up every ban/report meta key written by the theme', () => {
|
||||
for (const key of ['_aksrt_active_restrictions', '_aksrt_is_banned', 'aksrt_user_ban_state']) {
|
||||
for (const key of ['_aksrt_active_restrictions', '_aksrt_is_banned', '_aksrt_no_appeal', 'aksrt_user_ban_state']) {
|
||||
assert.ok(uninstall.includes(`'${key}'`), `missing uninstall cleanup: ${key}`)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -67,6 +67,7 @@ $meta_keys = [
|
||||
'aksrt_unread_message_count',
|
||||
'_aksrt_active_restrictions',
|
||||
'_aksrt_is_banned',
|
||||
'_aksrt_no_appeal',
|
||||
'aksrt_user_ban_state',
|
||||
'_aksrt_favorite_posts',
|
||||
'aksrt_wechat_openid',
|
||||
|
||||
Reference in New Issue
Block a user