feat(users): add native VIP management
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
/**
|
||||
* VIP membership event persistence.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Content;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
final class VipMembershipEventRepository {
|
||||
|
||||
private string $table;
|
||||
|
||||
public function __construct() {
|
||||
$this->table = \AKSRT\Core\DBMigrator::table('vip_membership_event');
|
||||
}
|
||||
|
||||
/** @param array<string,mixed> $event */
|
||||
public function begin(array $event): string|\WP_Error {
|
||||
global $wpdb;
|
||||
if ($this->table === '') {
|
||||
return new \WP_Error('aksrt_vip_audit_unavailable', __('会员变更审计表不可用。', 'aksrt'));
|
||||
}
|
||||
$uuid = wp_generate_uuid4();
|
||||
$inserted = $wpdb->insert($this->table, [
|
||||
'event_uuid' => $uuid,
|
||||
'batch_uuid' => sanitize_text_field((string) ($event['batch_uuid'] ?? '')),
|
||||
'user_id' => (int) ($event['user_id'] ?? 0),
|
||||
'actor_user_id' => !empty($event['actor_user_id']) ? (int) $event['actor_user_id'] : null,
|
||||
'operation' => sanitize_key((string) ($event['operation'] ?? '')),
|
||||
'source' => sanitize_key((string) ($event['source'] ?? 'admin')),
|
||||
'reason' => sanitize_text_field((string) ($event['reason'] ?? '')),
|
||||
'request_json' => wp_json_encode((array) ($event['request'] ?? [])),
|
||||
'before_json' => wp_json_encode((array) ($event['before'] ?? [])),
|
||||
'status' => 'pending',
|
||||
'created_at' => current_time('mysql', true),
|
||||
]);
|
||||
return $inserted === 1 ? $uuid : new \WP_Error('aksrt_vip_audit_begin_failed', __('无法创建会员变更审计记录。', 'aksrt'));
|
||||
}
|
||||
|
||||
/** @param array<string,mixed> $after */
|
||||
public function complete(string $uuid, string $status, array $after = [], string $error_code = '', string $error_message = ''): bool {
|
||||
global $wpdb;
|
||||
return $wpdb->update($this->table, [
|
||||
'status' => in_array($status, ['succeeded', 'failed'], true) ? $status : 'failed',
|
||||
'after_json' => wp_json_encode($after),
|
||||
'error_code' => sanitize_key($error_code),
|
||||
'error_message' => sanitize_text_field($error_message),
|
||||
'completed_at' => current_time('mysql', true),
|
||||
], ['event_uuid' => $uuid]) !== false;
|
||||
}
|
||||
|
||||
/** @return array{items:array<int,array<string,mixed>>,total:int,pages:int} */
|
||||
public function query(int $page, int $per_page): array {
|
||||
global $wpdb;
|
||||
if ($this->table === '') {
|
||||
return ['items' => [], 'total' => 0, 'pages' => 1];
|
||||
}
|
||||
$total = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$this->table}");
|
||||
$items = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT e.*, u.display_name, u.user_login, a.display_name AS actor_name FROM {$this->table} e LEFT JOIN {$wpdb->users} u ON u.ID = e.user_id LEFT JOIN {$wpdb->users} a ON a.ID = e.actor_user_id ORDER BY e.id DESC LIMIT %d OFFSET %d",
|
||||
$per_page,
|
||||
max(0, $page - 1) * $per_page
|
||||
), ARRAY_A);
|
||||
return ['items' => is_array($items) ? $items : [], 'total' => $total, 'pages' => max(1, (int) ceil(max(1, $total) / $per_page))];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user