feat(ban): align ban prompts with the reference theme modals and block page
对照参考主题(Zibll)修正四项偏差,申诉链路从页面整体迁移至弹窗:
- feat(ban): 新增三个 1:1 复刻弹窗(REST /user-ban/{info,appeal,log}-modal):
查看禁封状态(多彩头 c-gray + 信息行 + 申诉按钮)、禁封申诉(edit-header
gavel/c-blue + 信息框 + 资料项 data[key] 输入 + 审核中态 + 禁止申诉态)、
禁封记录(多彩头 c-yellow + 计数 + 逐条卡片);user-ban.js 增加
data-aksrt-ban-info/appeal/log 委托与 admin-ajax 申诉提交
- feat(ban): 禁封/解封弹窗的「当前用户已有N次禁封记录」静态文案改为可点击
黄链(N>1),打开禁封记录弹窗;解封视图信息行改复用统一数据源
- refactor(ban): 治理展示态收敛至 Restriction::state_badges()(封号=c-red
违规已封号 / 小黑屋=c-yellow 小黑屋禁封中 / 禁言=c-gray 禁言中,颜色与
字段统一管理)+ get_ban_info()(状态/起止时间/原因/说明/申诉权限,
三弹窗与禁封页共用)
- feat(ban): 登录行为对齐参考主题——移除登录期拦截(enforce_login_ban)
与 complete_login 禁封闸门,封号用户可正常登录;新增 template_redirect
前台禁封页(1:1 zib_user_ban_restrict_login/zib_die_page:红盒提示 +
信息行 + 申诉权限 + 退出登录/申诉按钮,模板 templates/parts/user/ban-block.php)
- feat(profile): 公开主页禁封状态从资料卡下方提示框改为占据身份行元信息位
的 badg 徽章(参考主题 author_header_identity 语义);用户中心元信息改为
but 按钮(徽章+箭头)打开查看禁封状态弹窗;评论拒绝态链接同源
- refactor: 移除申诉页面模板(page-ban-appeal.php)及其资产/注册/入队、
get_profile_notice/profile_notice 链、state_labels/state_notices/
login_ban_message、UserRuntime 的 public_notice/ban_notice_text 死配置、
report_settings 死键、无消费方的 aksrt_ban_appeal_status 端点
- feat(ban): BanAppeal::ajax_submit 兼容弹窗 data[key] 表单结构
(逐项清洗入库,申诉说明取 data['申诉说明'],旧平铺字段保持兼容)
- chore: 重新构建 public.css/public.min.css(三个新弹窗几何与头部样式)
- test: 契约测试重写(徽章元信息位、三弹窗与记录链接、禁封页、允许登录 +
前台拦截、死代码移除断言),全量 362 项通过
This commit is contained in:
@@ -325,6 +325,28 @@ class UserController extends ControllerBase {
|
||||
'callback' => [$this, 'set_user_ban'],
|
||||
'permission_callback' => [$this, 'check_permission'],
|
||||
]);
|
||||
|
||||
// 前台查看禁封状态弹窗(1:1 复刻参考主题 zib_get_ban_info_modal;
|
||||
// 本人或管理员可见,权限在 helper 内判定)。
|
||||
register_rest_route(self::API_NAMESPACE, '/user-ban/info-modal', [
|
||||
'methods' => 'GET',
|
||||
'callback' => [$this, 'get_user_ban_info_modal'],
|
||||
'permission_callback' => static function () { return is_user_logged_in(); },
|
||||
]);
|
||||
|
||||
// 前台禁封申诉弹窗(1:1 复刻参考主题 zib_get_user_ban_appeal_modal;仅本人)。
|
||||
register_rest_route(self::API_NAMESPACE, '/user-ban/appeal-modal', [
|
||||
'methods' => 'GET',
|
||||
'callback' => [$this, 'get_user_ban_appeal_modal'],
|
||||
'permission_callback' => static function () { return is_user_logged_in(); },
|
||||
]);
|
||||
|
||||
// 前台禁封记录弹窗(1:1 复刻参考主题 zib_get_ban_log_modal;仅管理员)。
|
||||
register_rest_route(self::API_NAMESPACE, '/user-ban/log-modal', [
|
||||
'methods' => 'GET',
|
||||
'callback' => [$this, 'get_user_ban_log_modal'],
|
||||
'permission_callback' => static function () { return is_user_logged_in(); },
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -263,10 +263,6 @@ trait UserControllerAuthPhoneOperations {
|
||||
$user = $this->auth_find_user($target, $channel);
|
||||
if (!$user || !$this->auth_consume_code('login', $target, sanitize_text_field((string) $payload['code']), $channel)) {
|
||||
return $this->error(__('账号或验证码错误', 'aksrt'), 401);
|
||||
}
|
||||
// 禁封用户禁止登录(与密码登录 enforce_login_ban 同语义:封号=无法登录)。
|
||||
if (class_exists('\AKSRT\User\Restriction') && \AKSRT\User\Restriction::get_instance()->is_banned((int) $user->ID)) {
|
||||
return $this->error(\AKSRT\User\Restriction::get_instance()->login_ban_message((int) $user->ID), 403);
|
||||
}
|
||||
if ($oauth_data) {
|
||||
$oauth_data = \AKSRT\Auth\Service::claim_oauth_bind_context($obk);
|
||||
@@ -297,9 +293,9 @@ trait UserControllerAuthPhoneOperations {
|
||||
$resolved_login = \AKSRT\Auth\Service::resolve_email_to_username($target);
|
||||
$user = wp_authenticate($resolved_login, (string) ($payload['password'] ?? $payload['pwd'] ?? ''));
|
||||
if (is_wp_error($user) || !$user instanceof \WP_User) {
|
||||
// 透传具体失败原因(禁封等),不得泛化为“账号或密码错误”。
|
||||
// 透传具体失败原因,不得泛化为“账号或密码错误”。
|
||||
$bind_error = $user instanceof \WP_Error
|
||||
? \AKSRT\Auth\Service::friendly_login_error($user->get_error_message(), (string) $user->get_error_code())
|
||||
? \AKSRT\Auth\Service::friendly_login_error($user->get_error_message())
|
||||
: '';
|
||||
return $this->error($bind_error !== '' ? $bind_error : __('账号或密码错误', 'aksrt'), 401);
|
||||
}
|
||||
|
||||
@@ -99,6 +99,63 @@ trait UserControllerRestrictionOperations {
|
||||
return $this->success(['data' => ['html' => $html]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 前台查看禁封状态弹窗内容(1:1 复刻参考主题 zib_get_ban_info_modal,
|
||||
* 经 aksrt_get_user_ban_info_modal 渲染;本人或管理员可见)。
|
||||
*/
|
||||
public function get_user_ban_info_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_info_modal')) {
|
||||
return $this->error('禁封组件未加载', 501);
|
||||
}
|
||||
$html = aksrt_get_user_ban_info_modal($user_id);
|
||||
if ($html === '') {
|
||||
return $this->error('抱歉,您暂时没有此权限', 403);
|
||||
}
|
||||
return $this->success(['data' => ['html' => $html]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 前台禁封申诉弹窗内容(1:1 复刻参考主题 zib_get_user_ban_appeal_modal,
|
||||
* 经 aksrt_get_user_ban_appeal_modal 渲染;仅本人可见)。
|
||||
*/
|
||||
public function get_user_ban_appeal_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_appeal_modal')) {
|
||||
return $this->error('申诉组件未加载', 501);
|
||||
}
|
||||
$html = aksrt_get_user_ban_appeal_modal($user_id);
|
||||
if ($html === '') {
|
||||
return $this->error('抱歉,您暂时没有此权限', 403);
|
||||
}
|
||||
return $this->success(['data' => ['html' => $html]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 前台禁封记录弹窗内容(1:1 复刻参考主题 zib_get_ban_log_modal,
|
||||
* 经 aksrt_get_user_ban_log_modal 渲染;仅具备禁封权限的管理员可见)。
|
||||
*/
|
||||
public function get_user_ban_log_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_log_modal')) {
|
||||
return $this->error('禁封组件未加载', 501);
|
||||
}
|
||||
$html = aksrt_get_user_ban_log_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 禁封用户,
|
||||
@@ -173,13 +230,6 @@ trait UserControllerRestrictionOperations {
|
||||
if ($time_day > 0) {
|
||||
$notice .= ' ' . sprintf(__('期限:%1$d 天,%2$s 起自动解封。', 'aksrt'), $time_day, $expires);
|
||||
}
|
||||
// 申诉指引(参考主题「您可以登录后在用户中心发起申诉」同语义)。
|
||||
if (!$no_appeal) {
|
||||
$appeal_url = function_exists('aksrt_get_ban_appeal_page_url') ? aksrt_get_ban_appeal_page_url() : '';
|
||||
if ($appeal_url !== '') {
|
||||
$notice .= ' ' . sprintf(__('如有异议,可在禁封申诉页提交申诉:%s', 'aksrt'), $appeal_url);
|
||||
}
|
||||
}
|
||||
$this->send_ban_notice($user_id, $notice, __('账号限制', 'aksrt'), $desc);
|
||||
|
||||
// 删除全部内容:全部公开内容与已审核评论移至回收站(参考主题同行为)。
|
||||
|
||||
+1
-4
@@ -467,10 +467,7 @@ final class OAuth {
|
||||
if (!$user instanceof \WP_User) {
|
||||
$this->redirect_error('account_match_failed', $provider, 'login');
|
||||
}
|
||||
$login_error = OAuthAccountService::complete_login($user, true);
|
||||
if (is_wp_error($login_error)) {
|
||||
$this->redirect_error('account_banned', $provider, 'login');
|
||||
}
|
||||
OAuthAccountService::complete_login($user, true);
|
||||
$this->redirect_success('login', $provider, OAuthUrlPolicy::validated_redirect($redirect, home_url('/')));
|
||||
}
|
||||
|
||||
|
||||
@@ -97,27 +97,10 @@ final class OAuthAccountService {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 完成登录(设置会话与 Cookie)。
|
||||
*
|
||||
* 禁封用户禁止登录:与密码登录的 Restriction::enforce_login_ban 同语义
|
||||
* (封号=无法登录),覆盖短信验证码、公众号扫码、第三方 OAuth 等
|
||||
* 非密码登录路径。返回 WP_Error 时调用方须中止登录并透出原因。
|
||||
*/
|
||||
public static function complete_login(\WP_User $user, bool $remember = true): ?\WP_Error {
|
||||
if (
|
||||
class_exists('\AKSRT\User\Restriction')
|
||||
&& \AKSRT\User\Restriction::get_instance()->is_banned((int) $user->ID)
|
||||
) {
|
||||
return new \WP_Error(
|
||||
'user_banned',
|
||||
\AKSRT\User\Restriction::get_instance()->login_ban_message((int) $user->ID)
|
||||
);
|
||||
}
|
||||
public static function complete_login(\WP_User $user, bool $remember = true): void {
|
||||
wp_set_current_user($user->ID);
|
||||
wp_set_auth_cookie($user->ID, $remember);
|
||||
do_action('wp_login', $user->user_login, $user);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function bindings(int $user_id): array {
|
||||
|
||||
@@ -209,10 +209,7 @@ final class OAuthProxyClient {
|
||||
$this->redirect_error('account_match_failed', $provider, $action);
|
||||
}
|
||||
|
||||
$login_error = OAuthAccountService::complete_login($user, true);
|
||||
if (is_wp_error($login_error)) {
|
||||
$this->redirect_error('account_banned', $provider, $action);
|
||||
}
|
||||
OAuthAccountService::complete_login($user, true);
|
||||
|
||||
$this->redirect_success(
|
||||
'login',
|
||||
|
||||
+2
-11
@@ -67,13 +67,7 @@ final class Service {
|
||||
return sanitize_user($login, true);
|
||||
}
|
||||
|
||||
public static function friendly_login_error(string $raw_message, string $error_code = ''): string {
|
||||
// 禁封提示已是完整语义文案(无法登录 + 期限 + 原因),直接透出,
|
||||
// 不得泛化为“用户名或密码错误”。
|
||||
if ('user_banned' === $error_code) {
|
||||
return wp_strip_all_tags($raw_message);
|
||||
}
|
||||
|
||||
public static function friendly_login_error(string $raw_message): string {
|
||||
$msg_lower = wp_strip_all_tags(strtolower($raw_message));
|
||||
|
||||
if (false !== strpos($msg_lower, 'incorrect password') || false !== strpos($msg_lower, '密码不正确')) {
|
||||
@@ -141,10 +135,7 @@ final class Service {
|
||||
}
|
||||
|
||||
if (is_wp_error($user)) {
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => self::friendly_login_error($user->get_error_message(), (string) $user->get_error_code()),
|
||||
];
|
||||
return ['success' => false, 'error' => self::friendly_login_error($user->get_error_message())];
|
||||
}
|
||||
|
||||
// REST API 上下文中 wp_signon 可能无法正确设置 Cookie
|
||||
|
||||
@@ -442,10 +442,7 @@ final class WeixinGzh {
|
||||
if (!$user instanceof \WP_User) {
|
||||
return $this->error_response(is_wp_error($user) ? $user->get_error_message() : __('微信账号匹配失败', 'aksrt'), 400);
|
||||
}
|
||||
$login_error = OAuthAccountService::complete_login($user, true);
|
||||
if (is_wp_error($login_error)) {
|
||||
return $this->error_response($login_error->get_error_message(), 403);
|
||||
}
|
||||
OAuthAccountService::complete_login($user, true);
|
||||
$redirect = OAuthUrlPolicy::validated_redirect((string) ($payload['redirect_to'] ?? ''), home_url('/'));
|
||||
return new \WP_REST_Response([
|
||||
'success' => true,
|
||||
|
||||
@@ -527,29 +527,6 @@ trait ScriptsPart1b {
|
||||
}
|
||||
}
|
||||
|
||||
// 禁封申诉页
|
||||
if (is_page_template('templates/pages/page-ban-appeal.php')) {
|
||||
$ba_css = get_template_directory() . '/assets/css/routes/ban-appeal.css';
|
||||
if (file_exists($ba_css)) {
|
||||
wp_enqueue_style(
|
||||
'aksrt-route-ban-appeal',
|
||||
$base_uri . '/assets/css/routes/ban-appeal.css',
|
||||
['aksrt-public'],
|
||||
(string) filemtime($ba_css)
|
||||
);
|
||||
}
|
||||
$ba_js = get_template_directory() . '/assets/js/ban-appeal-page.js';
|
||||
if (file_exists($ba_js)) {
|
||||
wp_enqueue_script(
|
||||
'aksrt-ban-appeal-page',
|
||||
$base_uri . '/assets/js/ban-appeal-page.js',
|
||||
['loader_js'],
|
||||
(string) filemtime($ba_js),
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 消息中心页
|
||||
if (get_query_var('aksrt_message_view')) {
|
||||
$messages_css = get_template_directory() . '/assets/css/frontend/messages.css';
|
||||
|
||||
@@ -45,7 +45,6 @@ class Templates {
|
||||
'templates/pages/page-submit.php' => __('AKSRT - 写文章/投稿', 'aksrt'),
|
||||
'templates/pages/page-posts-navs.php' => __('AKSRT - 文章导航', 'aksrt'),
|
||||
'templates/pages/page-friends.php' => __('AKSRT - 友情链接', 'aksrt'),
|
||||
'templates/pages/page-ban-appeal.php' => __('AKSRT - 禁封申诉', 'aksrt'),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -577,7 +577,7 @@ class Settings {
|
||||
* verify:array{enabled:bool,public_display:bool,badge_text:string,accept_email_verified:bool,require_manual_review:bool},
|
||||
* level:array{enabled:bool,public_display:bool,source:string,label_prefix:string,thresholds:array<int,int>},
|
||||
* badge:array{enabled:bool,public_display:bool,limit:int,dictionary:array<int,array{slug:string,label:string,tone:string}>},
|
||||
* report:array{enabled:bool,public_entry:bool,public_notice:bool,ban_notice_text:string,categories:array<int,array{slug:string,label:string}>}
|
||||
* report:array{enabled:bool,public_entry:bool,categories:array<int,array{slug:string,label:string}>}
|
||||
* }
|
||||
*/
|
||||
public static function get_user_identity_settings(): array {
|
||||
|
||||
@@ -109,12 +109,11 @@ class UserRuntime {
|
||||
* level:array{enabled:bool,public_display:bool,source:string,label_prefix:string,thresholds:array<int,int>},
|
||||
* medal:array{enabled:bool,public_display:bool,limit:int,categories:array<int,array{cat_name:string,items:array<int,array{slug:string,name:string,desc:string,icon:string,get_type:string,get_val:int}>}>,items_by_slug:array<string,array{slug:string,name:string,desc:string,icon:string,get_type:string,get_val:int,cat_name:string}>},
|
||||
* badge:array{enabled:bool,public_display:bool,limit:int,dictionary:array<int,array{slug:string,label:string,tone:string,desc:string,icon_url?:string}>},
|
||||
* report:array{enabled:bool,public_entry:bool,public_notice:bool,ban_notice_text:string,categories:array<int,array{slug:string,label:string}>}
|
||||
* report:array{enabled:bool,public_entry:bool,categories:array<int,array{slug:string,label:string}>}
|
||||
* }
|
||||
*/
|
||||
public static function get_user_identity_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
$ban_notice_text = trim((string) ($settings['user_report_ban_notice_text'] ?? ''));
|
||||
$verify_types = [
|
||||
'personal' => [
|
||||
'slug' => 'personal',
|
||||
@@ -174,13 +173,8 @@ class UserRuntime {
|
||||
],
|
||||
'report' => [
|
||||
// 默认开启:对齐后台 schema default true 与参考主题 _pz('user_report_s', true)。
|
||||
'enabled' => (bool) ($settings['user_report_s'] ?? $settings['user_report_enabled'] ?? true),
|
||||
'public_entry' => !isset($settings['user_report_public_entry']) || !empty($settings['user_report_public_entry']),
|
||||
'public_notice' => !isset($settings['user_report_public_notice']) || !empty($settings['user_report_public_notice']),
|
||||
// 原样返回配置值:缺省时由 Home::get_profile_notice() 按治理展示态
|
||||
// 取分级默认文案(封号=全面限制/小黑屋=部分限制/禁言=评论域),
|
||||
// 不再用「部分互动能力已关闭」一刀切描述封号账号。
|
||||
'ban_notice_text' => $ban_notice_text,
|
||||
'enabled' => (bool) ($settings['user_report_s'] ?? $settings['user_report_enabled'] ?? true),
|
||||
'public_entry' => !isset($settings['user_report_public_entry']) || !empty($settings['user_report_public_entry']),
|
||||
],
|
||||
];
|
||||
}
|
||||
@@ -278,12 +272,10 @@ class UserRuntime {
|
||||
$settings = self::read_report_section();
|
||||
return [
|
||||
// 默认开启:对齐后台 schema default true 与参考主题 _pz('user_report_s', true)。
|
||||
'enabled' => (bool) ($settings['user_report_s'] ?? $settings['user_report_enabled'] ?? true),
|
||||
'public_entry' => !isset($settings['user_report_public_entry']) || !empty($settings['user_report_public_entry']),
|
||||
'public_notice' => !isset($settings['user_report_public_notice']) || !empty($settings['user_report_public_notice']),
|
||||
'ban_notice_text' => sanitize_text_field((string) ($settings['user_report_ban_notice_text'] ?? '')),
|
||||
'img_enabled' => !empty($settings['user_report_img_s']),
|
||||
'desc' => wp_kses_post((string) ($settings['user_report_desc'] ?? '')),
|
||||
'enabled' => (bool) ($settings['user_report_s'] ?? $settings['user_report_enabled'] ?? true),
|
||||
'public_entry' => !isset($settings['user_report_public_entry']) || !empty($settings['user_report_public_entry']),
|
||||
'img_enabled' => !empty($settings['user_report_img_s']),
|
||||
'desc' => wp_kses_post((string) ($settings['user_report_desc'] ?? '')),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
+25
-18
@@ -26,7 +26,6 @@ class BanAppeal {
|
||||
|
||||
public function init(): void {
|
||||
add_action('wp_ajax_aksrt_ban_appeal_submit', [$this, 'ajax_submit']);
|
||||
add_action('wp_ajax_aksrt_ban_appeal_status', [$this, 'ajax_status']);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,23 +61,6 @@ class BanAppeal {
|
||||
return is_array($p) ? $p : [];
|
||||
}
|
||||
|
||||
public function ajax_status(): void {
|
||||
if (!is_user_logged_in()) {
|
||||
wp_send_json(['error' => 1, 'msg' => __('请先登录', 'aksrt')]);
|
||||
}
|
||||
$user_id = get_current_user_id();
|
||||
$ban = class_exists('\AKSRT\User\Restriction')
|
||||
? \AKSRT\User\Restriction::get_instance()->get_active_ban($user_id)
|
||||
: null;
|
||||
wp_send_json([
|
||||
'error' => 0,
|
||||
'banned' => (bool) $ban,
|
||||
'ban' => $ban,
|
||||
'status' => self::get_status($user_id),
|
||||
'payload'=> self::get_payload($user_id),
|
||||
]);
|
||||
}
|
||||
|
||||
public function ajax_submit(): void {
|
||||
if (!is_user_logged_in()) {
|
||||
wp_send_json(['error' => 1, 'msg' => __('请先登录', 'aksrt')]);
|
||||
@@ -114,6 +96,28 @@ class BanAppeal {
|
||||
|
||||
$reason_key = isset($_POST['reason_key']) ? sanitize_text_field(wp_unslash((string) $_POST['reason_key'])) : '';
|
||||
$reason = isset($_POST['reason']) ? sanitize_textarea_field(wp_unslash((string) $_POST['reason'])) : '';
|
||||
$data_rows = null;
|
||||
|
||||
// 申诉弹窗表单(1:1 参考主题 zib_get_user_ban_appeal_modal):资料项以
|
||||
// data[<key>] 逐项提交,申诉说明取 data['申诉说明'];旧版平铺字段保持兼容。
|
||||
if (isset($_POST['data']) && is_array($_POST['data'])) {
|
||||
$clean = [];
|
||||
foreach ($_POST['data'] as $k => $v) {
|
||||
$clean[sanitize_text_field(wp_unslash((string) $k))] = sanitize_textarea_field(wp_unslash((string) $v));
|
||||
}
|
||||
$data_rows = $clean;
|
||||
$reason_key = '';
|
||||
$reason = (string) ($clean[__('申诉说明', 'aksrt')] ?? '');
|
||||
if ($reason === '') {
|
||||
foreach ($clean as $v) {
|
||||
if (trim((string) $v) !== '') {
|
||||
$reason = (string) $v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($reason === '') {
|
||||
wp_send_json(['error' => 1, 'msg' => __('请填写申诉说明', 'aksrt')]);
|
||||
}
|
||||
@@ -123,6 +127,9 @@ class BanAppeal {
|
||||
'reason' => $reason,
|
||||
'time' => current_time('Y-m-d H:i'),
|
||||
];
|
||||
if ($data_rows !== null) {
|
||||
$payload['data'] = $data_rows;
|
||||
}
|
||||
update_user_meta($user_id, self::META_PAYLOAD, $payload);
|
||||
update_user_meta($user_id, self::META_STATUS, 'pending');
|
||||
|
||||
|
||||
@@ -340,49 +340,6 @@ class Home {
|
||||
return ['state' => $type, 'label' => $label];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取公开治理提示。
|
||||
*
|
||||
* 状态标识对齐参考主题公开主页禁封徽章(zib_ban_author_header_identity_filter):
|
||||
* 封号(ban) → "违规已封号",小黑屋(suspend) → "小黑屋禁封中";
|
||||
* 禁言(mute) 为 AKSRT 扩展状态 → "禁言中"。text 为后台可配置说明文案
|
||||
* (未配置时回退默认文案,见 UserRuntime::get_user_identity_settings)。
|
||||
*
|
||||
* @return array{state:string,label:string,text:string}|array{}
|
||||
*/
|
||||
public function get_profile_notice(int $user_id): array {
|
||||
if ($user_id <= 0 || !class_exists('\AKSRT\Settings\Settings')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$settings = \AKSRT\Settings\Settings::get_user_identity_settings();
|
||||
if (empty($settings['report']['enabled']) || empty($settings['report']['public_notice'])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$state = '';
|
||||
if (class_exists('\AKSRT\User\Restriction')) {
|
||||
$state = \AKSRT\User\Restriction::get_instance()->get_display_state($user_id);
|
||||
}
|
||||
if ($state === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 提示尾句:后台配置优先;缺省按治理展示态取分级文案
|
||||
// (封号=全面限制,小黑屋=部分限制,禁言=评论域限制)。
|
||||
$text = trim((string) ($settings['report']['ban_notice_text'] ?? ''));
|
||||
if ($text === '') {
|
||||
$state_notices = \AKSRT\User\Restriction::state_notices();
|
||||
$text = (string) ($state_notices[$state] ?? '');
|
||||
}
|
||||
|
||||
return [
|
||||
'state' => $state,
|
||||
'label' => \AKSRT\User\Restriction::state_labels()[$state] ?? '',
|
||||
'text' => $text,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 公开主页是否显示举报入口。
|
||||
*/
|
||||
|
||||
+66
-55
@@ -38,8 +38,10 @@ class Restriction {
|
||||
}
|
||||
|
||||
public function init(): void {
|
||||
// Enforce bans on login
|
||||
add_filter('authenticate', [$this, 'enforce_login_ban'], 999, 3);
|
||||
// 禁封用户前台拦截(对齐参考主题 zib_user_ban_restrict_login:
|
||||
// 封号用户可正常登录,但前台任何页面均展示禁封状态页;禁封中
|
||||
// 不得拦截登录本身——登录后的落地页即禁封页)。
|
||||
add_action('template_redirect', [$this, 'restrict_frontend_access'], 1);
|
||||
// Enforce comment mute
|
||||
add_filter('pre_comment_on_post', [$this, 'enforce_comment_mute']);
|
||||
}
|
||||
@@ -193,8 +195,8 @@ class Restriction {
|
||||
/**
|
||||
* 治理展示态(空串 = 无治理状态;ban 优先于 suspend,对齐后台单一状态语义)。
|
||||
*
|
||||
* 供资料卡提示框(Home::get_profile_notice)、用户中心页头、评论拒绝态、
|
||||
* 昵称徽章共用,文案见 state_labels()。
|
||||
* 供公开主页身份行徽章、用户中心元信息、评论拒绝态、昵称徽章共用,
|
||||
* 徽章字段(文案/颜色/图标)见 state_badges()。
|
||||
*/
|
||||
public function get_display_state(int $user_id): string {
|
||||
if ($user_id <= 0) {
|
||||
@@ -213,60 +215,62 @@ class Restriction {
|
||||
}
|
||||
|
||||
/**
|
||||
* 治理展示态徽章文案 — 对齐参考主题公开主页禁封标识
|
||||
* (zib_ban_author_header_identity_filter:封号 → 违规已封号,
|
||||
* 小黑屋 → 小黑屋禁封中);禁言为 AKSRT 扩展状态。
|
||||
* 治理展示态徽章字段(颜色 / 文案 / 图标统一管理,全前端提示面共用):
|
||||
* 封号(ban) → c-red 违规已封号(最严重:无法登录);
|
||||
* 小黑屋(suspend) → c-yellow 小黑屋禁封中(部分限制);
|
||||
* 禁言(mute) → c-gray 禁言中(评论域限制)。
|
||||
* 对齐参考主题 zib_ban_author_header_identity_filter 的红/默认双色语义,
|
||||
* 禁言为 AKSRT 扩展状态。
|
||||
*
|
||||
* @return array<string,string> 展示态 => 文案
|
||||
* @return array<string,array{label:string,tone:string,icon:string}> 展示态 => 徽章字段
|
||||
*/
|
||||
public static function state_labels(): array {
|
||||
public static function state_badges(): array {
|
||||
return [
|
||||
self::STATE_BANNED => __('违规已封号', 'aksrt'),
|
||||
self::STATE_RESTRICTED => __('小黑屋禁封中', 'aksrt'),
|
||||
self::STATE_MUTED => __('禁言中', 'aksrt'),
|
||||
self::STATE_BANNED => ['label' => __('违规已封号', 'aksrt'), 'tone' => 'c-red', 'icon' => 'ban'],
|
||||
self::STATE_RESTRICTED => ['label' => __('小黑屋禁封中', 'aksrt'), 'tone' => 'c-yellow', 'icon' => 'ban'],
|
||||
self::STATE_MUTED => ['label' => __('禁言中', 'aksrt'), 'tone' => 'c-gray', 'icon' => 'comment-slash'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 治理展示态公开提示尾句(资料卡提示框,接在徽章文案之后):
|
||||
* 封号 = 全面限制(无法登录、功能停用);
|
||||
* 小黑屋 = 部分限制(发布、评论等操作受限);
|
||||
* 禁言 = 仅评论域受限。
|
||||
* 后台 user_report_ban_notice_text 配置后覆盖全部状态。
|
||||
* 生效禁封信息行(查看禁封状态弹窗 / 申诉弹窗 / 登录后禁封页 / 管理端
|
||||
* 禁封解封弹窗共用;对齐参考主题 zib_get_ban_info_modal 的字段集)。
|
||||
*
|
||||
* @return array<string,string> 展示态 => 提示文案
|
||||
* @return array<string,mixed>|array{} 空数组表示无生效禁封/小黑屋。
|
||||
*/
|
||||
public static function state_notices(): array {
|
||||
return [
|
||||
self::STATE_BANNED => __('禁封期间无法登录,账号功能全面停用。', 'aksrt'),
|
||||
self::STATE_RESTRICTED => __('发布、评论等操作已受限制。', 'aksrt'),
|
||||
self::STATE_MUTED => __('暂时无法发表评论。', 'aksrt'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录禁封提示文案(登录拦截 / 免密登录 / Toast 共用)。
|
||||
* 对齐参考主题登录拦截页语义:封号 = 全面限制(无法登录),附期限与原因。
|
||||
*/
|
||||
public function login_ban_message(int $user_id): string {
|
||||
$msg = __('您的账号已被封禁,禁封期间无法登录。', 'aksrt');
|
||||
$ban = $this->get_active_ban($user_id);
|
||||
if (is_array($ban)) {
|
||||
$msg .= !empty($ban['expires_at'])
|
||||
? ' ' . sprintf(__('解封时间:%s。', 'aksrt'), (string) $ban['expires_at'])
|
||||
: ' ' . __('本次封禁为永久封禁。', 'aksrt');
|
||||
$reason = (string) ($ban['reason'] ?? '');
|
||||
$marker = "\n" . __('禁封说明:', 'aksrt');
|
||||
$pos = strpos($reason, $marker);
|
||||
if (false !== $pos) {
|
||||
$reason = substr($reason, 0, $pos);
|
||||
}
|
||||
$reason = trim($reason);
|
||||
if ($reason !== '') {
|
||||
$msg .= ' ' . sprintf(__('原因:%s', 'aksrt'), $reason);
|
||||
}
|
||||
public function get_ban_info(int $user_id): array {
|
||||
if ($user_id <= 0) {
|
||||
return [];
|
||||
}
|
||||
return $msg;
|
||||
$ban = $this->get_active_ban($user_id) ?: $this->get_active_suspend($user_id);
|
||||
if (!is_array($ban)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$type = (string) ($ban['type'] ?? '');
|
||||
$raw = (string) ($ban['reason'] ?? '');
|
||||
$reason = $raw;
|
||||
$desc = '';
|
||||
$marker = "\n" . __('禁封说明:', 'aksrt');
|
||||
$pos = strpos($raw, $marker);
|
||||
if (false !== $pos) {
|
||||
$reason = substr($raw, 0, $pos);
|
||||
$desc = trim(substr($raw, $pos + strlen($marker)));
|
||||
}
|
||||
|
||||
$no_appeal = get_user_meta($user_id, '_aksrt_no_appeal', true);
|
||||
$no_appeal_desc = is_array($no_appeal) ? trim((string) ($no_appeal['desc'] ?? '')) : '';
|
||||
|
||||
return [
|
||||
'type' => $type,
|
||||
'status' => $type === self::TYPE_BAN ? __('禁封中(禁止登录)', 'aksrt') : __('小黑屋禁封中', 'aksrt'),
|
||||
'start' => (string) ($ban['created_at'] ?? ''),
|
||||
'end' => !empty($ban['expires_at']) ? (string) $ban['expires_at'] : __('永久', 'aksrt'),
|
||||
'reason' => trim($reason),
|
||||
'desc' => $desc,
|
||||
'no_appeal' => $no_appeal_desc !== '',
|
||||
'no_appeal_desc' => $no_appeal_desc,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -305,16 +309,23 @@ class Restriction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforce ban on login.
|
||||
* 前台禁封拦截页(1:1 复刻参考主题 zib_user_ban_restrict_login /
|
||||
* zib_die_page):封号(ban)用户登录后访问任何前台页面,均展示禁封状态页
|
||||
* (红盒提示 + 禁封信息行 + 申诉权限 + 退出登录/申诉按钮)。
|
||||
* 小黑屋/禁言为部分限制,可正常浏览站点,不走此拦截。
|
||||
*/
|
||||
public function enforce_login_ban($user, string $username, string $password) {
|
||||
if (is_wp_error($user) || !$user instanceof \WP_User) {
|
||||
return $user;
|
||||
public function restrict_frontend_access(): void {
|
||||
if (is_admin() || wp_doing_cron() || wp_doing_ajax()) {
|
||||
return;
|
||||
}
|
||||
if ($this->is_banned($user->ID)) {
|
||||
return new \WP_Error('user_banned', $this->login_ban_message($user->ID));
|
||||
$user_id = get_current_user_id();
|
||||
if ($user_id <= 0 || !$this->is_banned($user_id)) {
|
||||
return;
|
||||
}
|
||||
return $user;
|
||||
if (!function_exists('aksrt_render_user_ban_block_page')) {
|
||||
require_once AKSRT_DIR . '/inc/helpers/user-ban.php';
|
||||
}
|
||||
aksrt_render_user_ban_block_page($user_id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user