Move ~94 root class shells and root *-traits into domain directories (core, auth, user, credits, content, payment/gateways, forum, shop, sms, ai, messages, extensions, widgets, settings, admin). Update bootstrap require paths, co-locate traits with owners, fix forum/user relative requires, drop duplicate shop controller requires, and wire home-modules load. Path-only; class names and init order unchanged.
243 lines
7.8 KiB
PHP
243 lines
7.8 KiB
PHP
<?php
|
|
/**
|
|
* User Restriction / Ban System
|
|
*
|
|
* Manages user restrictions (warn, mute, suspend, ban) with scope,
|
|
* expiration, and enforcement hooks.
|
|
*
|
|
* @package AKSRT
|
|
*/
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
class AKSRT_User_Restriction {
|
|
|
|
private static $instance = null;
|
|
|
|
const TYPE_WARN = 'warn';
|
|
const TYPE_MUTE = 'mute';
|
|
const TYPE_SUSPEND = 'suspend';
|
|
const TYPE_BAN = 'ban';
|
|
|
|
const SCOPE_GLOBAL = 'global';
|
|
const SCOPE_FORUM = 'forum';
|
|
const SCOPE_SHOP = 'shop';
|
|
const SCOPE_COMMENT = 'comment';
|
|
|
|
const TYPES = [self::TYPE_WARN, self::TYPE_MUTE, self::TYPE_SUSPEND, self::TYPE_BAN];
|
|
const SCOPES = [self::SCOPE_GLOBAL, self::SCOPE_FORUM, self::SCOPE_SHOP, self::SCOPE_COMMENT];
|
|
|
|
public static function get_instance(): self {
|
|
if (null === self::$instance) {
|
|
self::$instance = new self();
|
|
}
|
|
return self::$instance;
|
|
}
|
|
|
|
public function init(): void {
|
|
// Enforce bans on login
|
|
add_filter('authenticate', [$this, 'enforce_login_ban'], 999, 3);
|
|
// Enforce comment mute
|
|
add_filter('pre_comment_on_post', [$this, 'enforce_comment_mute']);
|
|
// Enforce forum mute
|
|
add_filter('aksrt_before_create_topic', [$this, 'enforce_forum_mute']);
|
|
}
|
|
|
|
/**
|
|
* Get the restriction table name.
|
|
*/
|
|
private function table(): string {
|
|
global $wpdb;
|
|
return $wpdb->prefix . 'aksrt_user_restriction';
|
|
}
|
|
|
|
/**
|
|
* Add a restriction to a user.
|
|
*/
|
|
public function restrict(int $user_id, string $type, string $reason, string $scope = self::SCOPE_GLOBAL, string $expires_at = '', int $created_by = 0): array {
|
|
global $wpdb;
|
|
|
|
if (!in_array($type, self::TYPES, true)) {
|
|
return ['success' => false, 'message' => 'Invalid restriction type.'];
|
|
}
|
|
if (!in_array($scope, self::SCOPES, true)) {
|
|
return ['success' => false, 'message' => 'Invalid scope.'];
|
|
}
|
|
if ($created_by <= 0) {
|
|
$created_by = get_current_user_id();
|
|
}
|
|
|
|
$data = [
|
|
'user_id' => $user_id,
|
|
'type' => $type,
|
|
'reason' => sanitize_textarea_field($reason),
|
|
'scope' => $scope,
|
|
'expires_at' => $expires_at ? gmdate('Y-m-d H:i:s', strtotime($expires_at)) : null,
|
|
'created_by' => $created_by,
|
|
'created_at' => current_time('mysql', true),
|
|
];
|
|
|
|
$result = $wpdb->insert($this->table(), $data);
|
|
if ($result === false) {
|
|
return ['success' => false, 'message' => 'Database error.'];
|
|
}
|
|
|
|
// Update user meta for quick lookup
|
|
$this->sync_user_restriction_meta($user_id);
|
|
|
|
return ['success' => true, 'id' => $wpdb->insert_id];
|
|
}
|
|
|
|
/**
|
|
* Remove a restriction by ID.
|
|
*/
|
|
public function remove_restriction(int $restriction_id): bool {
|
|
global $wpdb;
|
|
$restriction = $this->get_restriction($restriction_id);
|
|
if (!$restriction) return false;
|
|
|
|
$result = $wpdb->delete($this->table(), ['id' => $restriction_id]);
|
|
if ($result) {
|
|
$this->sync_user_restriction_meta((int) $restriction['user_id']);
|
|
}
|
|
return (bool) $result;
|
|
}
|
|
|
|
/**
|
|
* Get a single restriction by ID.
|
|
*/
|
|
public function get_restriction(int $restriction_id): ?array {
|
|
global $wpdb;
|
|
$row = $wpdb->get_row($wpdb->prepare(
|
|
"SELECT * FROM {$this->table()} WHERE id = %d",
|
|
$restriction_id
|
|
), ARRAY_A);
|
|
return $row ?: null;
|
|
}
|
|
|
|
/**
|
|
* Get all active restrictions for a user.
|
|
*/
|
|
public function get_user_restrictions(int $user_id, bool $active_only = true): array {
|
|
global $wpdb;
|
|
$now = current_time('mysql', true);
|
|
|
|
if ($active_only) {
|
|
$rows = $wpdb->get_results($wpdb->prepare(
|
|
"SELECT * FROM {$this->table()} WHERE user_id = %d AND (expires_at IS NULL OR expires_at > %s) ORDER BY created_at DESC",
|
|
$user_id, $now
|
|
), ARRAY_A);
|
|
} else {
|
|
$rows = $wpdb->get_results($wpdb->prepare(
|
|
"SELECT * FROM {$this->table()} WHERE user_id = %d ORDER BY created_at DESC",
|
|
$user_id
|
|
), ARRAY_A);
|
|
}
|
|
|
|
return $rows ?: [];
|
|
}
|
|
|
|
/**
|
|
* Check if a user has an active restriction of a given type and scope.
|
|
*/
|
|
public function is_restricted(int $user_id, string $type = '', string $scope = ''): bool {
|
|
$restrictions = $this->get_user_restrictions($user_id, true);
|
|
foreach ($restrictions as $r) {
|
|
if ($type && $r['type'] !== $type) continue;
|
|
if ($scope && $r['scope'] !== $scope && $r['scope'] !== self::SCOPE_GLOBAL) continue;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if a user is banned (global).
|
|
*/
|
|
public function is_banned(int $user_id): bool {
|
|
return $this->is_restricted($user_id, self::TYPE_BAN, self::SCOPE_GLOBAL);
|
|
}
|
|
|
|
/**
|
|
* Get the active ban restriction for a user (if any).
|
|
*/
|
|
public function get_active_ban(int $user_id): ?array {
|
|
$restrictions = $this->get_user_restrictions($user_id, true);
|
|
foreach ($restrictions as $r) {
|
|
if ($r['type'] === self::TYPE_BAN && $r['scope'] === self::SCOPE_GLOBAL) {
|
|
return $r;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Enforce ban on login.
|
|
*/
|
|
public function enforce_login_ban($user, string $username, string $password) {
|
|
if (is_wp_error($user) || !$user instanceof WP_User) {
|
|
return $user;
|
|
}
|
|
if ($this->is_banned($user->ID)) {
|
|
$ban = $this->get_active_ban($user->ID);
|
|
$message = '您的账号已被封禁。';
|
|
if (!empty($ban['reason'])) {
|
|
$message .= '原因:' . $ban['reason'];
|
|
}
|
|
return new WP_Error('user_banned', $message);
|
|
}
|
|
return $user;
|
|
}
|
|
|
|
/**
|
|
* Enforce comment mute.
|
|
*/
|
|
public function enforce_comment_mute($post_id) {
|
|
$user_id = get_current_user_id();
|
|
if ($user_id > 0 && $this->is_restricted($user_id, self::TYPE_MUTE, self::SCOPE_COMMENT)) {
|
|
wp_die('您已被限制评论。', '评论限制', ['response' => 403]);
|
|
}
|
|
return $post_id;
|
|
}
|
|
|
|
/**
|
|
* Enforce forum mute.
|
|
*/
|
|
public function enforce_forum_mute($data) {
|
|
$user_id = get_current_user_id();
|
|
if ($user_id > 0 && $this->is_restricted($user_id, self::TYPE_MUTE, self::SCOPE_FORUM)) {
|
|
return new WP_Error('forum_muted', '您已被限制在论坛发言。');
|
|
}
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* Sync restriction meta for quick lookup.
|
|
*/
|
|
private function sync_user_restriction_meta(int $user_id): void {
|
|
$active = $this->get_user_restrictions($user_id, true);
|
|
$types = array_unique(array_column($active, 'type'));
|
|
update_user_meta($user_id, '_aksrt_active_restrictions', $types);
|
|
update_user_meta($user_id, '_aksrt_is_banned', in_array(self::TYPE_BAN, $types, true) ? 1 : 0);
|
|
}
|
|
|
|
/**
|
|
* Get restriction stats for admin overview.
|
|
*/
|
|
public function get_stats(): array {
|
|
global $wpdb;
|
|
$now = current_time('mysql', true);
|
|
$table = $this->table();
|
|
|
|
$total = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$table}");
|
|
$active = (int) $wpdb->get_var($wpdb->prepare(
|
|
"SELECT COUNT(*) FROM {$table} WHERE expires_at IS NULL OR expires_at > %s", $now
|
|
));
|
|
$banned = (int) $wpdb->get_var($wpdb->prepare(
|
|
"SELECT COUNT(*) FROM {$table} WHERE type = %s AND (expires_at IS NULL OR expires_at > %s)",
|
|
self::TYPE_BAN, $now
|
|
));
|
|
|
|
return ['total' => $total, 'active' => $active, 'banned' => $banned];
|
|
}
|
|
}
|