feat(user-ban): frontend ban modal replaces the backend restrictions tab
1:1 replicate the reference theme user-ban flow on the frontend: - Ban/unban modal rendered by inc/helpers/user-ban.php, opened via AksrtModalRuntime.openRemote (600px desktop dialog, 360px initial height, mobile bottom drawer, c-yellow colorful unban header). - Three entry points wired: user homepage cover three-dot menu, comment section menu, article author card menu (ban item takes priority over report, matching the reference hook order). - REST endpoints /user-ban/modal and /user-ban/set under aksrt/v1, guarded by check_permission, persisted through User\Restriction. - Submit semantics match zib_ajax_set_user_ban: ban reloads the page, unban only closes the modal. Cleanup (no dual-track): the backend ban-restrictions tab, its form handlers and flash keys are removed; ticket processing links to the frontend user homepage as the reference theme does; admin/report and appeal notification URLs move to type/status query args. Verification: 337/337 widget-system contract tests, 41/41 admin and front-submit tests, php -l clean on all changed PHP files.
This commit is contained in:
@@ -79,4 +79,135 @@ trait UserControllerRestrictionOperations {
|
||||
$stats = \AKSRT\User\Restriction::get_instance()->get_stats();
|
||||
return $this->success(['data' => $stats]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 前台禁封弹窗内容(1:1 复刻参考主题 zib_get_set_user_ban_modal,
|
||||
* 经 aksrt_get_user_ban_modal 渲染;参考主题 refresh_modal 每次刷新同语义)。
|
||||
*/
|
||||
public function get_user_ban_modal(\WP_REST_Request $request): \WP_REST_Response {
|
||||
$user_id = (int) $request->get_param('user_id');
|
||||
if ($user_id <= 0 || !get_userdata($user_id)) {
|
||||
return $this->error('用户不存在', 404);
|
||||
}
|
||||
if (!function_exists('aksrt_get_user_ban_modal')) {
|
||||
return $this->error('禁封组件未加载', 501);
|
||||
}
|
||||
$html = aksrt_get_user_ban_modal($user_id);
|
||||
if ($html === '') {
|
||||
return $this->error('抱歉,您暂时没有此权限', 403);
|
||||
}
|
||||
return $this->success(['data' => ['html' => $html]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 前台禁封 / 解封提交(1:1 复刻参考主题 zib_ajax_set_user_ban 语义):
|
||||
* ban=0 解封(留言站内信);ban=1 拉入小黑屋 / ban=2 禁封用户,
|
||||
* 支持禁封时长、预置/其它原因、禁封说明、删除全部内容、禁止申诉(含说明)。
|
||||
*/
|
||||
public function set_user_ban(\WP_REST_Request $request): \WP_REST_Response {
|
||||
$params = $request->get_json_params() ?? [];
|
||||
$user_id = (int) ($params['user_id'] ?? 0);
|
||||
if ($user_id <= 0 || !get_userdata($user_id)) {
|
||||
return $this->error('用户不存在或参数传入错误', 404);
|
||||
}
|
||||
if (!function_exists('aksrt_current_user_can_ban') || !aksrt_current_user_can_ban($user_id)) {
|
||||
return $this->error('抱歉,您暂时没有此权限', 403);
|
||||
}
|
||||
if (!class_exists('\AKSRT\User\Restriction')) {
|
||||
return $this->error('限制系统未启用', 501);
|
||||
}
|
||||
|
||||
$svc = \AKSRT\User\Restriction::get_instance();
|
||||
$ban = (int) ($params['ban'] ?? 0);
|
||||
$desc = isset($params['desc']) ? sanitize_textarea_field((string) wp_unslash($params['desc'])) : '';
|
||||
|
||||
// ── 解封 ──
|
||||
if (0 === $ban) {
|
||||
$svc->lift_user_restriction($user_id);
|
||||
delete_user_meta($user_id, '_aksrt_no_appeal');
|
||||
$this->send_ban_notice($user_id, __('您的账号限制已解除。', 'aksrt'), __('限制解除', 'aksrt'), $desc);
|
||||
return $this->success(['message' => __('已解封此用户', 'aksrt'), 'data' => ['banned' => false]]);
|
||||
}
|
||||
|
||||
// ── 禁封 ──
|
||||
$type = 2 === $ban ? \AKSRT\User\Restriction::TYPE_BAN : \AKSRT\User\Restriction::TYPE_SUSPEND;
|
||||
|
||||
$reason = isset($params['reason']) ? sanitize_text_field((string) wp_unslash($params['reason'])) : '';
|
||||
if ($reason === '' || $reason === 'other') {
|
||||
$reason = isset($params['reason_other']) ? sanitize_text_field((string) wp_unslash($params['reason_other'])) : '';
|
||||
}
|
||||
if ($reason === '') {
|
||||
return $this->error(__('请输入禁封原因', 'aksrt'));
|
||||
}
|
||||
|
||||
$time_day = isset($params['time_day']) ? (int) $params['time_day'] : 0;
|
||||
$expires = $time_day > 0 ? date('Y-m-d H:i:s', strtotime('+' . $time_day . ' day', current_time('timestamp'))) : '';
|
||||
|
||||
$no_appeal = !empty($params['no_appeal']);
|
||||
$no_appeal_desc = isset($params['no_appeal_desc']) ? sanitize_textarea_field((string) wp_unslash($params['no_appeal_desc'])) : '';
|
||||
if ($no_appeal && $no_appeal_desc === '') {
|
||||
return $this->error(__('请输入禁止用户申诉的说明或原因', 'aksrt'));
|
||||
}
|
||||
|
||||
// 禁封说明并入原因列(与后台工单禁封表单同存储语义)。
|
||||
if ($desc !== '') {
|
||||
$reason .= "\n" . sprintf(__('禁封说明:%s', 'aksrt'), $desc);
|
||||
}
|
||||
|
||||
$result = $svc->restrict($user_id, $type, $reason, \AKSRT\User\Restriction::SCOPE_GLOBAL, $expires, get_current_user_id());
|
||||
if (empty($result['success'])) {
|
||||
return $this->error((string) ($result['message'] ?? __('操作失败', 'aksrt')));
|
||||
}
|
||||
|
||||
if ($no_appeal) {
|
||||
update_user_meta($user_id, '_aksrt_no_appeal', [
|
||||
'desc' => $no_appeal_desc,
|
||||
'at' => current_time('mysql'),
|
||||
]);
|
||||
}
|
||||
|
||||
// 站内信(后台禁封表单 / 参考主题 zib_updata_user_ban_msg 同语义)。
|
||||
$notice = $type === \AKSRT\User\Restriction::TYPE_BAN
|
||||
? __('您的账号已被禁封,将无法登录。', 'aksrt')
|
||||
: __('您已被拉入小黑屋,发布等相关权限已被限制。', 'aksrt');
|
||||
if ($time_day > 0) {
|
||||
$notice .= ' ' . sprintf(__('期限:%1$d 天,%2$s 起自动解封。', 'aksrt'), $time_day, $expires);
|
||||
}
|
||||
$this->send_ban_notice($user_id, $notice, __('账号限制', 'aksrt'), $desc);
|
||||
|
||||
// 删除全部内容:全部公开内容与已审核评论移至回收站(参考主题同行为)。
|
||||
if (!empty($params['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);
|
||||
}
|
||||
}
|
||||
|
||||
$send_msg = 2 === $ban ? __('已禁封此用户', 'aksrt') : __('已将此用户拉入小黑屋', 'aksrt');
|
||||
return $this->success(['message' => $send_msg, 'data' => ['banned' => true]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁封 / 解封站内信(留言拼附在正文之后)。
|
||||
*/
|
||||
private function send_ban_notice(int $user_id, string $notice, string $title, string $desc = ''): void
|
||||
{
|
||||
if (!class_exists('\AKSRT\Messages\Message')) {
|
||||
return;
|
||||
}
|
||||
$msg = $notice;
|
||||
if ($desc !== '') {
|
||||
$msg .= ' ' . sprintf(__('留言:%s', 'aksrt'), $desc);
|
||||
}
|
||||
\AKSRT\Messages\Message::get_instance()->send($user_id, 'system', $msg, ['title' => $title]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user