导入 AKSRT 主题开发源码
This commit is contained in:
@@ -0,0 +1,471 @@
|
||||
<?php
|
||||
/**
|
||||
* AKSRT admin report operations support.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
trait AKSRT_Admin_User_Controller_Report_Operations {
|
||||
|
||||
public function get_report_list(WP_REST_Request $request): WP_REST_Response {
|
||||
if (!class_exists('AKSRT_Report_Center')) {
|
||||
return $this->success([
|
||||
'data' => [
|
||||
'items' => [],
|
||||
'reports' => [],
|
||||
'counts' => ['pending' => 0, 'reviewing' => 0, 'resolved' => 0, 'dismissed' => 0, 'total' => 0],
|
||||
'total' => 0,
|
||||
'page' => 1,
|
||||
'options' => [
|
||||
'statuses' => $this->get_report_status_options(),
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$table = AKSRT_DB_Migrator::table('report');
|
||||
if (!$table) {
|
||||
return $this->success([
|
||||
'data' => [
|
||||
'items' => [],
|
||||
'reports' => [],
|
||||
'counts' => ['pending' => 0, 'reviewing' => 0, 'resolved' => 0, 'dismissed' => 0, 'total' => 0],
|
||||
'total' => 0,
|
||||
'page' => 1,
|
||||
'options' => [
|
||||
'statuses' => $this->get_report_status_options(),
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
$page = max(1, (int) ($request->get_param('page') ?: 1));
|
||||
$per_page = max(1, min(100, (int) ($request->get_param('per_page') ?: $request->get_param('limit') ?: 20)));
|
||||
$status = sanitize_key((string) $request->get_param('status'));
|
||||
$category = sanitize_key((string) $request->get_param('category'));
|
||||
$target_type = sanitize_key((string) $request->get_param('target_type'));
|
||||
$keyword = trim(sanitize_text_field((string) $request->get_param('keyword')));
|
||||
$date_from = sanitize_text_field((string) $request->get_param('date_from'));
|
||||
$date_to = sanitize_text_field((string) $request->get_param('date_to'));
|
||||
|
||||
$where = [];
|
||||
$params = [];
|
||||
|
||||
if ($status !== '') {
|
||||
$where[] = 'status = %s';
|
||||
$params[] = $status;
|
||||
}
|
||||
if ($category !== '') {
|
||||
$where[] = 'category = %s';
|
||||
$params[] = $category;
|
||||
}
|
||||
if ($target_type !== '') {
|
||||
$where[] = 'target_type = %s';
|
||||
$params[] = $target_type;
|
||||
}
|
||||
if ($date_from !== '') {
|
||||
$where[] = 'created_at >= %s';
|
||||
$params[] = $date_from . ' 00:00:00';
|
||||
}
|
||||
if ($date_to !== '') {
|
||||
$where[] = 'created_at <= %s';
|
||||
$params[] = $date_to . ' 23:59:59';
|
||||
}
|
||||
|
||||
$where_sql = $where ? 'WHERE ' . implode(' AND ', $where) : '';
|
||||
$sql = "SELECT * FROM {$table} {$where_sql} ORDER BY created_at DESC LIMIT 500";
|
||||
$rows = $params ? $wpdb->get_results($wpdb->prepare($sql, $params), ARRAY_A) : $wpdb->get_results($sql, ARRAY_A);
|
||||
|
||||
$items = [];
|
||||
foreach ((array) $rows as $row) {
|
||||
$item = $this->build_report_admin_item($row);
|
||||
if ($keyword !== '' && !$this->report_matches_keyword($item, $keyword)) {
|
||||
continue;
|
||||
}
|
||||
$items[] = $item;
|
||||
}
|
||||
|
||||
$total = count($items);
|
||||
$offset = ($page - 1) * $per_page;
|
||||
$paged = array_slice($items, $offset, $per_page);
|
||||
$counts = AKSRT_Report_Center::get_instance()->get_status_counts();
|
||||
$categories = [];
|
||||
foreach ((array) $rows as $row) {
|
||||
$cat = sanitize_key((string) ($row['category'] ?? ''));
|
||||
if ($cat !== '') {
|
||||
$categories[$cat] = $cat;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success([
|
||||
'data' => [
|
||||
'items' => array_values($paged),
|
||||
'reports' => array_values($paged),
|
||||
'total' => $total,
|
||||
'page' => $page,
|
||||
'per_page' => $per_page,
|
||||
'counts' => $counts,
|
||||
'options' => [
|
||||
'statuses' => $this->get_report_status_options(),
|
||||
'actions' => $this->get_report_action_options(),
|
||||
'targets' => $this->get_report_target_type_options(),
|
||||
'categories' => array_map(static function ($item) {
|
||||
return ['label' => $item, 'value' => $item];
|
||||
}, array_values($categories)),
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function update_report_status(WP_REST_Request $request): WP_REST_Response {
|
||||
if (!class_exists('AKSRT_Report_Center')) {
|
||||
return $this->error(__('举报系统未启用', 'aksrt'));
|
||||
}
|
||||
|
||||
$params = $this->get_json_params($request);
|
||||
$report_id = (int) ($params['report_id'] ?? 0);
|
||||
if ($report_id <= 0) {
|
||||
return $this->error(__('参数无效', 'aksrt'));
|
||||
}
|
||||
|
||||
return $this->handle_report_process($report_id, $params);
|
||||
}
|
||||
|
||||
public function get_report_counts(): WP_REST_Response {
|
||||
if (!class_exists('AKSRT_Report_Center')) {
|
||||
return $this->success(['pending' => 0, 'reviewing' => 0, 'resolved' => 0, 'dismissed' => 0, 'total' => 0]);
|
||||
}
|
||||
return $this->success(AKSRT_Report_Center::get_instance()->get_status_counts());
|
||||
}
|
||||
|
||||
public function get_report_detail(WP_REST_Request $request): WP_REST_Response {
|
||||
global $wpdb;
|
||||
|
||||
$report_id = (int) $request->get_param('id');
|
||||
$table = AKSRT_DB_Migrator::table('report');
|
||||
|
||||
if ($report_id <= 0 || !$table) {
|
||||
return $this->error(__('举报工单不存在', 'aksrt'), 404);
|
||||
}
|
||||
|
||||
$row = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$table} WHERE id = %d", $report_id), ARRAY_A);
|
||||
if (!$row) {
|
||||
return $this->error(__('举报工单不存在', 'aksrt'), 404);
|
||||
}
|
||||
|
||||
$related = (int) $wpdb->get_var($wpdb->prepare(
|
||||
"SELECT COUNT(*) FROM {$table} WHERE target_type = %s AND target_id = %d",
|
||||
sanitize_key((string) $row['target_type']),
|
||||
(int) $row['target_id']
|
||||
));
|
||||
|
||||
return $this->success([
|
||||
'data' => [
|
||||
'report' => $this->build_report_admin_item($row),
|
||||
'related' => ['same_target_count' => $related],
|
||||
'options' => [
|
||||
'statuses' => $this->get_report_status_options(),
|
||||
'actions' => $this->get_report_action_options(sanitize_key((string) $row['target_type'])),
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function process_report(WP_REST_Request $request): WP_REST_Response {
|
||||
$report_id = (int) $request->get_param('id');
|
||||
if ($report_id <= 0) {
|
||||
return $this->error(__('参数无效', 'aksrt'));
|
||||
}
|
||||
|
||||
return $this->handle_report_process($report_id, $this->get_json_params($request));
|
||||
}
|
||||
|
||||
private function handle_report_process(int $report_id, array $payload): WP_REST_Response {
|
||||
global $wpdb;
|
||||
|
||||
$table = AKSRT_DB_Migrator::table('report');
|
||||
if (!$table) {
|
||||
return $this->error(__('举报系统未启用', 'aksrt'));
|
||||
}
|
||||
|
||||
$status = sanitize_key((string) ($payload['status'] ?? ''));
|
||||
$action_taken = sanitize_key((string) ($payload['action_taken'] ?? 'none'));
|
||||
$note = sanitize_textarea_field((string) ($payload['note'] ?? ''));
|
||||
|
||||
$valid_statuses = array_column($this->get_report_status_options(), 'value');
|
||||
$valid_actions = array_column($this->get_report_action_options(), 'value');
|
||||
|
||||
if ($status === '' || !in_array($status, $valid_statuses, true)) {
|
||||
return $this->error(__('处理状态无效', 'aksrt'));
|
||||
}
|
||||
if (!in_array($action_taken, $valid_actions, true)) {
|
||||
$action_taken = 'none';
|
||||
}
|
||||
|
||||
$row = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$table} WHERE id = %d", $report_id), ARRAY_A);
|
||||
if (!$row) {
|
||||
return $this->error(__('举报工单不存在', 'aksrt'), 404);
|
||||
}
|
||||
|
||||
$effect = $this->apply_report_action(
|
||||
sanitize_key((string) $row['target_type']),
|
||||
(int) $row['target_id'],
|
||||
$action_taken
|
||||
);
|
||||
|
||||
$notes = json_decode((string) ($row['notes_json'] ?? '[]'), true);
|
||||
if (!is_array($notes)) {
|
||||
$notes = [];
|
||||
}
|
||||
$notes[] = [
|
||||
'note' => $note,
|
||||
'status' => $status,
|
||||
'action_taken' => $action_taken,
|
||||
'operator' => get_current_user_id(),
|
||||
'timestamp' => current_time('mysql'),
|
||||
'effect' => $effect,
|
||||
];
|
||||
|
||||
$updated = $wpdb->update(
|
||||
$table,
|
||||
[
|
||||
'status' => $status,
|
||||
'updated_at' => current_time('mysql'),
|
||||
'notes_json' => wp_json_encode($notes),
|
||||
],
|
||||
['id' => $report_id],
|
||||
['%s', '%s', '%s'],
|
||||
['%d']
|
||||
);
|
||||
|
||||
if ($updated === false) {
|
||||
return $this->error(__('处理失败', 'aksrt'));
|
||||
}
|
||||
|
||||
return $this->success([
|
||||
'message' => __('举报工单已处理', 'aksrt'),
|
||||
]);
|
||||
}
|
||||
|
||||
private function build_report_admin_item(array $row): array {
|
||||
$reporter = get_userdata((int) ($row['reporter_id'] ?? 0));
|
||||
$notes = json_decode((string) ($row['notes_json'] ?? '[]'), true);
|
||||
if (!is_array($notes)) {
|
||||
$notes = [];
|
||||
}
|
||||
|
||||
$normalized_notes = [];
|
||||
foreach ($notes as $entry) {
|
||||
$operator_id = (int) ($entry['operator'] ?? 0);
|
||||
$operator_user = $operator_id > 0 ? get_userdata($operator_id) : null;
|
||||
$normalized_notes[] = [
|
||||
'note' => (string) ($entry['note'] ?? ''),
|
||||
'status' => sanitize_key((string) ($entry['status'] ?? '')),
|
||||
'action_taken' => sanitize_key((string) ($entry['action_taken'] ?? 'none')),
|
||||
'operator' => $operator_id,
|
||||
'operator_name' => $operator_user ? $operator_user->display_name : '',
|
||||
'timestamp' => (string) ($entry['timestamp'] ?? ''),
|
||||
'effect' => (string) ($entry['effect'] ?? ''),
|
||||
];
|
||||
}
|
||||
|
||||
$last_note = !empty($normalized_notes) ? $normalized_notes[count($normalized_notes) - 1] : null;
|
||||
|
||||
return [
|
||||
'id' => (int) ($row['id'] ?? 0),
|
||||
'target_type' => sanitize_key((string) ($row['target_type'] ?? '')),
|
||||
'target_id' => (int) ($row['target_id'] ?? 0),
|
||||
'reason' => (string) ($row['reason'] ?? ''),
|
||||
'category' => sanitize_key((string) ($row['category'] ?? '')),
|
||||
'status' => sanitize_key((string) ($row['status'] ?? 'pending')),
|
||||
'created_at' => (string) ($row['created_at'] ?? ''),
|
||||
'updated_at' => (string) ($row['updated_at'] ?? ''),
|
||||
'reporter' => $this->build_admin_user_summary($reporter ? (int) $reporter->ID : 0, $reporter),
|
||||
'target' => $this->build_report_target_summary(
|
||||
sanitize_key((string) ($row['target_type'] ?? '')),
|
||||
(int) ($row['target_id'] ?? 0)
|
||||
),
|
||||
'notes' => $normalized_notes,
|
||||
'note_count' => count($normalized_notes),
|
||||
'last_note' => $last_note,
|
||||
];
|
||||
}
|
||||
|
||||
private function report_matches_keyword(array $item, string $keyword): bool {
|
||||
$haystack = implode(' ', array_filter([
|
||||
(string) ($item['reason'] ?? ''),
|
||||
(string) ($item['category'] ?? ''),
|
||||
(string) ($item['reporter']['display_name'] ?? ''),
|
||||
(string) ($item['reporter']['email'] ?? ''),
|
||||
(string) ($item['target']['title'] ?? ''),
|
||||
(string) ($item['target']['display_name'] ?? ''),
|
||||
(string) ($item['target']['excerpt'] ?? ''),
|
||||
(string) ($item['target_id'] ?? ''),
|
||||
]));
|
||||
|
||||
return mb_stripos($haystack, $keyword) !== false;
|
||||
}
|
||||
|
||||
private function build_report_target_summary(string $target_type, int $target_id): array {
|
||||
$summary = [
|
||||
'type' => $target_type,
|
||||
'id' => $target_id,
|
||||
'title' => '',
|
||||
'excerpt' => '',
|
||||
'display_name' => '',
|
||||
'status' => '',
|
||||
'url' => '',
|
||||
'ban_state' => '',
|
||||
];
|
||||
|
||||
if ($target_type === 'post') {
|
||||
$post = get_post($target_id);
|
||||
if ($post instanceof WP_Post) {
|
||||
$summary['title'] = get_the_title($post);
|
||||
$summary['status'] = (string) $post->post_status;
|
||||
$summary['url'] = get_permalink($post);
|
||||
}
|
||||
} elseif ($target_type === 'comment') {
|
||||
$comment = get_comment($target_id);
|
||||
if ($comment instanceof WP_Comment) {
|
||||
$summary['display_name'] = (string) $comment->comment_author;
|
||||
$summary['excerpt'] = wp_trim_words(wp_strip_all_tags((string) $comment->comment_content), 24);
|
||||
$summary['status'] = $comment->comment_approved === '1' ? 'approved' : (string) $comment->comment_approved;
|
||||
$summary['url'] = get_comment_link($comment);
|
||||
if (!empty($comment->comment_post_ID)) {
|
||||
$summary['title'] = get_the_title((int) $comment->comment_post_ID);
|
||||
}
|
||||
}
|
||||
} elseif ($target_type === 'user') {
|
||||
$user = get_userdata($target_id);
|
||||
if ($user instanceof WP_User) {
|
||||
$summary['display_name'] = $user->display_name;
|
||||
$summary['title'] = $user->display_name;
|
||||
$summary['url'] = function_exists('aksrt_get_user_home_url') ? aksrt_get_user_home_url($target_id) : '';
|
||||
$summary['ban_state'] = (string) get_user_meta($target_id, 'aksrt_user_ban_state', true);
|
||||
}
|
||||
}
|
||||
|
||||
return $summary;
|
||||
}
|
||||
|
||||
private function apply_report_action(string $target_type, int $target_id, string $action_taken): string {
|
||||
if ($target_id <= 0 || $action_taken === 'none') {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($target_type === 'user') {
|
||||
if (in_array($action_taken, ['muted', 'restricted', 'banned'], true)) {
|
||||
update_user_meta($target_id, 'aksrt_user_ban_state', $action_taken);
|
||||
return sprintf(__('已同步用户限制状态:%s', 'aksrt'), $action_taken);
|
||||
}
|
||||
|
||||
if ($action_taken === 'clear') {
|
||||
delete_user_meta($target_id, 'aksrt_user_ban_state');
|
||||
return __('已清除用户限制状态', 'aksrt');
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($action_taken === 'content_removed' && $target_type === 'post' && get_post($target_id)) {
|
||||
wp_update_post([
|
||||
'ID' => $target_id,
|
||||
'post_status' => 'pending',
|
||||
]);
|
||||
return __('已将内容改为待审状态', 'aksrt');
|
||||
}
|
||||
|
||||
if ($action_taken === 'content_removed' && $target_type === 'comment' && get_comment($target_id)) {
|
||||
wp_set_comment_status($target_id, 'hold', true);
|
||||
return __('已将评论改为待审状态', 'aksrt');
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private function get_report_status_options(): array {
|
||||
return [
|
||||
['label' => __('待处理', 'aksrt'), 'value' => 'pending'],
|
||||
['label' => __('处理中', 'aksrt'), 'value' => 'reviewing'],
|
||||
['label' => __('已解决', 'aksrt'), 'value' => 'resolved'],
|
||||
['label' => __('已驳回', 'aksrt'), 'value' => 'dismissed'],
|
||||
];
|
||||
}
|
||||
|
||||
private function get_report_target_type_options(): array {
|
||||
return [
|
||||
['label' => __('文章', 'aksrt'), 'value' => 'post'],
|
||||
['label' => __('评论', 'aksrt'), 'value' => 'comment'],
|
||||
['label' => __('用户', 'aksrt'), 'value' => 'user'],
|
||||
];
|
||||
}
|
||||
|
||||
private function get_report_action_options(string $target_type = ''): array {
|
||||
$common = [
|
||||
['label' => __('仅更新状态', 'aksrt'), 'value' => 'none'],
|
||||
['label' => __('升级人工处理', 'aksrt'), 'value' => 'escalated'],
|
||||
];
|
||||
|
||||
if ($target_type === 'user' || $target_type === '') {
|
||||
$common = array_merge($common, [
|
||||
['label' => __('发送警告', 'aksrt'), 'value' => 'warned'],
|
||||
['label' => __('禁言', 'aksrt'), 'value' => 'muted'],
|
||||
['label' => __('限制功能', 'aksrt'), 'value' => 'restricted'],
|
||||
['label' => __('封禁账号', 'aksrt'), 'value' => 'banned'],
|
||||
['label' => __('解除限制', 'aksrt'), 'value' => 'clear'],
|
||||
]);
|
||||
}
|
||||
|
||||
if ($target_type === 'post' || $target_type === 'comment' || $target_type === '') {
|
||||
$common[] = ['label' => __('转为待审内容', 'aksrt'), 'value' => 'content_removed'];
|
||||
}
|
||||
|
||||
return $common;
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /report/submit — 前台举报提交(登录用户)
|
||||
*/
|
||||
public function submit_report(WP_REST_Request $request): WP_REST_Response {
|
||||
if (!class_exists('AKSRT_Report_Center')) {
|
||||
return $this->error('举报系统未启用', 500);
|
||||
}
|
||||
|
||||
$params = $this->get_json_params($request);
|
||||
$target_type = sanitize_key((string) ($params['target_type'] ?? ''));
|
||||
$target_id = (int) ($params['target_id'] ?? 0);
|
||||
$reason = sanitize_textarea_field((string) ($params['reason'] ?? ''));
|
||||
$category = sanitize_key((string) ($params['category'] ?? ''));
|
||||
|
||||
if ($target_type === '' || $target_id <= 0 || $reason === '') {
|
||||
return $this->error('请填写完整的举报信息');
|
||||
}
|
||||
|
||||
$valid_types = ['post', 'comment', 'user'];
|
||||
if (!in_array($target_type, $valid_types, true)) {
|
||||
return $this->error('无效的举报类型');
|
||||
}
|
||||
|
||||
$report_id = AKSRT_Report_Center::get_instance()->submit(
|
||||
get_current_user_id(),
|
||||
$target_type,
|
||||
$target_id,
|
||||
$reason,
|
||||
$category
|
||||
);
|
||||
|
||||
if ($report_id > 0) {
|
||||
return $this->success([
|
||||
'message' => __('举报已提交,我们会尽快处理', 'aksrt'),
|
||||
'data' => ['report_id' => $report_id],
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->error(__('举报提交失败', 'aksrt'));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user