Files
wordpress-theme-aksrt/inc/classes/user/class-aksrt-user-restriction.php
T
kate522 ce1c13b947 refactor(classes): organize inc/classes into domain folders
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.
2026-07-17 11:11:57 +08:00

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];
}
}