删除私信分支链路
This commit is contained in:
@@ -53,53 +53,6 @@ class MessageController extends ControllerBase {
|
||||
'callback' => [$this, 'mark_all_read'],
|
||||
'permission_callback' => [$this, 'check_logged_in_permission'],
|
||||
]);
|
||||
|
||||
// ── Private Messages / Conversations ──
|
||||
|
||||
// List conversations
|
||||
register_rest_route(self::API_NAMESPACE, '/conversations', [
|
||||
'methods' => 'GET',
|
||||
'callback' => [$this, 'list_conversations'],
|
||||
'permission_callback' => [$this, 'check_logged_in_permission'],
|
||||
'args' => [
|
||||
'limit' => ['default' => 20, 'sanitize_callback' => 'absint'],
|
||||
],
|
||||
]);
|
||||
|
||||
// Get thread messages
|
||||
register_rest_route(self::API_NAMESPACE, '/conversations/(?P<id>\d+)/messages', [
|
||||
'methods' => 'GET',
|
||||
'callback' => [$this, 'get_thread'],
|
||||
'permission_callback' => [$this, 'check_logged_in_permission'],
|
||||
'args' => [
|
||||
'page' => ['default' => 1, 'sanitize_callback' => 'absint'],
|
||||
'per_page' => ['default' => 30, 'sanitize_callback' => 'absint'],
|
||||
],
|
||||
]);
|
||||
|
||||
// Send message in conversation
|
||||
register_rest_route(self::API_NAMESPACE, '/conversations/(?P<id>\d+)/messages', [
|
||||
'methods' => 'POST',
|
||||
'callback' => [$this, 'send_message'],
|
||||
'permission_callback' => [$this, 'check_logged_in_permission'],
|
||||
'args' => [
|
||||
'content' => ['required' => true, 'sanitize_callback' => 'sanitize_textarea_field'],
|
||||
],
|
||||
]);
|
||||
|
||||
// Create or get conversation with a user
|
||||
register_rest_route(self::API_NAMESPACE, '/conversations/with/(?P<user_id>\d+)', [
|
||||
'methods' => 'POST',
|
||||
'callback' => [$this, 'get_or_create_conversation'],
|
||||
'permission_callback' => [$this, 'check_logged_in_permission'],
|
||||
]);
|
||||
|
||||
// Mark conversation read
|
||||
register_rest_route(self::API_NAMESPACE, '/conversations/(?P<id>\d+)/read', [
|
||||
'methods' => 'POST',
|
||||
'callback' => [$this, 'mark_conversation_read'],
|
||||
'permission_callback' => [$this, 'check_logged_in_permission'],
|
||||
]);
|
||||
}
|
||||
|
||||
// ── Notification handlers ──
|
||||
@@ -160,91 +113,6 @@ class MessageController extends ControllerBase {
|
||||
return $this->success(['data' => ['success' => $result]]);
|
||||
}
|
||||
|
||||
// ── Conversation handlers ──
|
||||
|
||||
public function list_conversations(\WP_REST_Request $request): \WP_REST_Response {
|
||||
$user_id = get_current_user_id();
|
||||
$limit = min(50, (int) $request->get_param('limit'));
|
||||
|
||||
if (!class_exists('\AKSRT\Messages\PrivateMessage')) {
|
||||
return $this->success(['data' => []]);
|
||||
}
|
||||
|
||||
$conversations = \AKSRT\Messages\PrivateMessage::get_instance()->get_conversations($user_id, $limit);
|
||||
return $this->success(['data' => $conversations]);
|
||||
}
|
||||
|
||||
public function get_thread(\WP_REST_Request $request): \WP_REST_Response {
|
||||
$user_id = get_current_user_id();
|
||||
$conv_id = (int) $request->get_param('id');
|
||||
$page = max(1, (int) $request->get_param('page'));
|
||||
$per_page = min(50, (int) $request->get_param('per_page'));
|
||||
|
||||
if (!class_exists('\AKSRT\Messages\PrivateMessage')) {
|
||||
return $this->error('not_available', '私信系统未启用。', 501);
|
||||
}
|
||||
|
||||
$result = \AKSRT\Messages\PrivateMessage::get_instance()->get_thread($conv_id, $user_id, $page, $per_page);
|
||||
if (is_wp_error($result)) {
|
||||
return $this->error('thread_error', $result->get_error_message(), 403);
|
||||
}
|
||||
|
||||
return $this->success(['data' => $result]);
|
||||
}
|
||||
|
||||
public function send_message(\WP_REST_Request $request): \WP_REST_Response {
|
||||
$user_id = get_current_user_id();
|
||||
$conv_id = (int) $request->get_param('id');
|
||||
$content = trim((string) $request->get_param('content'));
|
||||
|
||||
if (!$content) {
|
||||
return $this->error('content_required', '消息内容不能为空。', 400);
|
||||
}
|
||||
|
||||
if (!class_exists('\AKSRT\Messages\PrivateMessage')) {
|
||||
return $this->error('not_available', '私信系统未启用。', 501);
|
||||
}
|
||||
|
||||
$result = \AKSRT\Messages\PrivateMessage::get_instance()->send($conv_id, $user_id, $content);
|
||||
if (!$result['success']) {
|
||||
return $this->error('send_failed', $result['message'] ?? '发送失败。', 500);
|
||||
}
|
||||
|
||||
return $this->success(['data' => $result]);
|
||||
}
|
||||
|
||||
public function get_or_create_conversation(\WP_REST_Request $request): \WP_REST_Response {
|
||||
$user_id = get_current_user_id();
|
||||
$other_id = (int) $request->get_param('user_id');
|
||||
|
||||
if ($user_id === $other_id) {
|
||||
return $this->error('self_message', '不能与自己创建对话。', 400);
|
||||
}
|
||||
|
||||
if (!class_exists('\AKSRT\Messages\PrivateMessage')) {
|
||||
return $this->error('not_available', '私信系统未启用。', 501);
|
||||
}
|
||||
|
||||
$conv_id = \AKSRT\Messages\PrivateMessage::get_instance()->get_or_create_conversation($user_id, $other_id);
|
||||
if (is_wp_error($conv_id)) {
|
||||
return $this->error('create_failed', $conv_id->get_error_message(), 500);
|
||||
}
|
||||
|
||||
return $this->success(['data' => ['conversation_id' => $conv_id]]);
|
||||
}
|
||||
|
||||
public function mark_conversation_read(\WP_REST_Request $request): \WP_REST_Response {
|
||||
$user_id = get_current_user_id();
|
||||
$conv_id = (int) $request->get_param('id');
|
||||
|
||||
if (!class_exists('\AKSRT\Messages\PrivateMessage')) {
|
||||
return $this->error('not_available', '私信系统未启用。', 501);
|
||||
}
|
||||
|
||||
\AKSRT\Messages\PrivateMessage::get_instance()->mark_conversation_read($conv_id, $user_id);
|
||||
return $this->success(['data' => ['success' => true]]);
|
||||
}
|
||||
|
||||
public function check_logged_in_permission(): bool {
|
||||
return is_user_logged_in();
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ class GlobalSchema {
|
||||
['key' => 'lazy_avatar', 'label' => '头像懒加载', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'lazy_posts_content', 'label' => '文章内容图片懒加载', 'type' => 'switch', 'default' => false],
|
||||
['key' => 'lazy_comment', 'label' => '评论内容图片懒加载', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'lazy_private', 'label' => '私信聊天图片懒加载', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'lazy_sider', 'label' => '幻灯片图片懒加载', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'lazy_cover', 'label' => '封面图片懒加载', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'lazy_other', 'label' => '其它图片懒加载', 'type' => 'switch', 'default' => true],
|
||||
@@ -383,12 +382,6 @@ class GlobalSchema {
|
||||
['label' => '纯文本', 'value' => 'plain'],
|
||||
['label' => 'HTML', 'value' => 'html'],
|
||||
]],
|
||||
['key' => 'email_private_receive_limit', 'label' => '私信邮件接收组', 'type' => 'select', 'default' => 'all', 'options' => [
|
||||
['label' => '所有用户', 'value' => 'all'],
|
||||
['label' => 'VIP 及以上', 'value' => 'vip'],
|
||||
['label' => 'VIP2 及以上', 'value' => 'vip2'],
|
||||
['label' => '仅管理员', 'value' => 'admin'],
|
||||
], 'help' => '限制哪些用户组可以收到私信邮件通知'],
|
||||
]],
|
||||
['key' => 'branding', 'title' => '邮件品牌', 'fields' => [
|
||||
['key' => 'mail_showname', 'label' => '发件人名称', 'type' => 'input', 'default' => '', 'help' => '覆盖系统默认发件人名称'],
|
||||
|
||||
@@ -277,21 +277,9 @@ class SchemaUsers {
|
||||
['label' => '认证回复', 'value' => 'auth_apply_reply'],
|
||||
['label' => '下载通知', 'value' => 'download'],
|
||||
['label' => '积分变动', 'value' => 'credits'],
|
||||
['label' => '私信', 'value' => 'private'],
|
||||
['label' => '举报反馈', 'value' => 'report'],
|
||||
]],
|
||||
]],
|
||||
['key' => 'private', 'title' => '私信设置', 'fields' => [
|
||||
['key' => 'private_s', 'label' => '启用私信功能', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'private_smilie_s', 'label' => '支持表情', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'private_code_s', 'label' => '支持代码', 'type' => 'switch', 'default' => false],
|
||||
['key' => 'private_image_s', 'label' => '支持图片', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'private_upload_img', 'label' => '支持上传图片', 'type' => 'switch', 'default' => false],
|
||||
['key' => 'private_quick_s', 'label' => '快捷回复', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'private_quick_often', 'label' => '常用快捷回复', 'type' => 'textarea', 'default' => "你好,请问有什么可以帮你的?\n感谢你的反馈\n已处理,请查收", 'desc' => '一行一条快捷回复文案'],
|
||||
['key' => 'private_submit_text', 'label' => '发送按钮文案', 'type' => 'input', 'default' => '发送'],
|
||||
['key' => 'private_placeholder', 'label' => '输入占位符', 'type' => 'input', 'default' => '请输入消息...'],
|
||||
]],
|
||||
],
|
||||
],
|
||||
'oauth' => [
|
||||
@@ -580,7 +568,6 @@ class SchemaUsers {
|
||||
['key' => 'user_cover_img', 'label' => '默认封面', 'type' => 'media', 'default' => ''],
|
||||
['key' => 'user_rewrite_slug', 'label' => '用户页slug', 'type' => 'input', 'default' => 'user'],
|
||||
['key' => 'user_follow_s', 'label' => '启用关注功能', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'user_message_s', 'label' => '启用私信功能', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'user_online_s', 'label' => '显示在线状态', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'user_last_active_s', 'label' => '显示最后活跃', 'type' => 'switch', 'default' => true],
|
||||
]],
|
||||
|
||||
@@ -151,11 +151,6 @@ trait UserControllerAuthPhoneOperations {
|
||||
return $this->error('未登录', 401);
|
||||
}
|
||||
|
||||
$unread = 0;
|
||||
if (class_exists('\AKSRT\Messages\PrivateMessage')) {
|
||||
$unread = \AKSRT\Messages\PrivateMessage::get_instance()->get_unread_count($user->ID);
|
||||
}
|
||||
|
||||
$credits = 0;
|
||||
if (class_exists('\AKSRT\Credits\Credits')) {
|
||||
$credits = \AKSRT\Credits\Credits::balance($user->ID);
|
||||
@@ -170,7 +165,6 @@ trait UserControllerAuthPhoneOperations {
|
||||
? aksrt_get_avatar_url($user->ID, ['size' => 48])
|
||||
: get_avatar_url($user->ID, ['size' => 48]),
|
||||
'is_admin' => current_user_can('manage_options'),
|
||||
'unread' => $unread,
|
||||
'credits' => $credits,
|
||||
],
|
||||
]);
|
||||
|
||||
@@ -108,37 +108,6 @@ trait DBMigratorPart2 {
|
||||
) {$charset_collate};";
|
||||
dbDelta($sql_notification);
|
||||
|
||||
// ---------- 6. 私信会话 ----------
|
||||
$sql_conversation = "CREATE TABLE {$prefix}aksrt_conversation (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
user_a BIGINT UNSIGNED NOT NULL,
|
||||
user_b BIGINT UNSIGNED NOT NULL,
|
||||
last_message VARCHAR(255) DEFAULT '',
|
||||
last_message_at DATETIME DEFAULT NULL,
|
||||
unread_a INT NOT NULL DEFAULT 0,
|
||||
unread_b INT NOT NULL DEFAULT 0,
|
||||
created_at DATETIME NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uniq_pair (user_a, user_b),
|
||||
KEY idx_user_a (user_a),
|
||||
KEY idx_user_b (user_b),
|
||||
KEY idx_last_msg (last_message_at)
|
||||
) {$charset_collate};";
|
||||
dbDelta($sql_conversation);
|
||||
|
||||
// ---------- 7. 私信消息 ----------
|
||||
$sql_conv_message = "CREATE TABLE {$prefix}aksrt_conversation_message (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
conversation_id BIGINT UNSIGNED NOT NULL,
|
||||
sender_id BIGINT UNSIGNED NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
created_at DATETIME NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_conv_time (conversation_id, created_at),
|
||||
KEY idx_sender (sender_id)
|
||||
) {$charset_collate};";
|
||||
dbDelta($sql_conv_message);
|
||||
|
||||
// ---------- 8. 订单表 ----------
|
||||
$sql_order = "CREATE TABLE {$prefix}aksrt_order (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
|
||||
@@ -21,8 +21,6 @@ trait DBMigratorPart3 {
|
||||
'signin_log' => 'aksrt_signin_log',
|
||||
'dl_token' => 'aksrt_dl_token',
|
||||
'notification' => 'aksrt_notification',
|
||||
'conversation' => 'aksrt_conversation',
|
||||
'conv_message' => 'aksrt_conversation_message',
|
||||
'order' => 'aksrt_order',
|
||||
'order_item' => 'aksrt_order_item',
|
||||
'revenue' => 'aksrt_revenue',
|
||||
|
||||
@@ -600,16 +600,6 @@ trait ScriptsPart1b {
|
||||
true
|
||||
);
|
||||
}
|
||||
$conversation_js = get_template_directory() . '/assets/js/conversation.js';
|
||||
if (file_exists($conversation_js)) {
|
||||
wp_enqueue_script(
|
||||
'aksrt-conversation',
|
||||
$base_uri . '/assets/js/conversation.js',
|
||||
['loader_js'],
|
||||
(string) filemtime($conversation_js),
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Unified share-data builder — single payload assembler for every share
|
||||
|
||||
@@ -572,7 +572,6 @@ trait ScriptsPart1c {
|
||||
'lazy_avatar' => aksrt_is_lazy('lazy_avatar'),
|
||||
'lazy_posts_content' => aksrt_is_lazy('lazy_posts_content'),
|
||||
'lazy_comment' => aksrt_is_lazy('lazy_comment'),
|
||||
'lazy_private' => aksrt_is_lazy('lazy_private'),
|
||||
'lazy_sider' => aksrt_is_lazy('lazy_sider'),
|
||||
'lazy_cover' => aksrt_is_lazy('lazy_cover'),
|
||||
'lazy_other' => aksrt_is_lazy('lazy_other'),
|
||||
|
||||
@@ -98,7 +98,7 @@ class Message {
|
||||
* 发送站内通知(持久化到 aksrt_notification 表)
|
||||
*
|
||||
* @param int $to_user_id 接收人 ID
|
||||
* @param string $type 通知类型 (comment_reply, download_ready, conversation, notice, ...)
|
||||
* @param string $type 通知类型 (comment_reply, download_ready, notice, ...)
|
||||
* @param string $content 通知内容摘要
|
||||
* @param array $data 附加数据 (title, target_url, ...)
|
||||
* @return bool
|
||||
|
||||
@@ -1,381 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Messages;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
class PrivateMessage {
|
||||
|
||||
private static $instance = null;
|
||||
|
||||
public static function get_instance(): self {
|
||||
if (null === self::$instance) self::$instance = new self();
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
public function init(): void {
|
||||
add_action('wp_ajax_aksrt_pm_send', [$this, 'ajax_send']);
|
||||
add_action('wp_ajax_aksrt_pm_conversations', [$this, 'ajax_conversations']);
|
||||
add_action('wp_ajax_aksrt_pm_thread', [$this, 'ajax_thread']);
|
||||
add_action('wp_ajax_aksrt_pm_mark_read', [$this, 'ajax_mark_read']);
|
||||
add_action('wp_ajax_aksrt_pm_unread_count', [$this, 'ajax_unread_count']);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
* Table name helpers
|
||||
* ----------------------------------------------------------------*/
|
||||
|
||||
private function table_conv(): string {
|
||||
global $wpdb;
|
||||
return $wpdb->prefix . 'aksrt_conversation';
|
||||
}
|
||||
|
||||
private function table_msg(): string {
|
||||
global $wpdb;
|
||||
return $wpdb->prefix . 'aksrt_conversation_message';
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
* Conversation CRUD
|
||||
* ----------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Get or create a 1-to-1 conversation between two users.
|
||||
*/
|
||||
public function get_or_create_conversation(int $user_a, int $user_b): int {
|
||||
global $wpdb;
|
||||
|
||||
if ($user_a <= 0 || $user_b <= 0 || $user_a === $user_b) return 0;
|
||||
|
||||
// Ensure consistent ordering
|
||||
$min_id = min($user_a, $user_b);
|
||||
$max_id = max($user_a, $user_b);
|
||||
|
||||
$existing = $wpdb->get_var($wpdb->prepare(
|
||||
"SELECT id FROM {$this->table_conv()} WHERE user_a = %d AND user_b = %d",
|
||||
$min_id, $max_id
|
||||
));
|
||||
|
||||
if ($existing) return (int) $existing;
|
||||
|
||||
$wpdb->insert($this->table_conv(), [
|
||||
'user_a' => $min_id,
|
||||
'user_b' => $max_id,
|
||||
'last_message' => '',
|
||||
'last_message_at' => current_time('mysql'),
|
||||
'unread_a' => 0,
|
||||
'unread_b' => 0,
|
||||
'created_at' => current_time('mysql'),
|
||||
], ['%d', '%d', '%s', '%s', '%d', '%d', '%s']);
|
||||
|
||||
return (int) $wpdb->insert_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* List conversations for a user (most recent first).
|
||||
*
|
||||
* @param int $user_id
|
||||
* @param int $limit
|
||||
* @return array
|
||||
*/
|
||||
public function get_conversations(int $user_id, int $limit = 20): array {
|
||||
global $wpdb;
|
||||
|
||||
if ($user_id <= 0) return [];
|
||||
|
||||
$table_conv = $this->table_conv();
|
||||
$table_msg = $this->table_msg();
|
||||
|
||||
$rows = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT c.*,
|
||||
CASE WHEN c.user_a = %d THEN c.unread_a ELSE c.unread_b END AS my_unread,
|
||||
CASE WHEN c.user_a = %d THEN c.user_b ELSE c.user_a END AS other_user_id
|
||||
FROM {$table_conv} c
|
||||
WHERE c.user_a = %d OR c.user_b = %d
|
||||
ORDER BY c.last_message_at DESC
|
||||
LIMIT %d",
|
||||
$user_id, $user_id, $user_id, $user_id, $limit
|
||||
), ARRAY_A);
|
||||
|
||||
$conversations = [];
|
||||
foreach ((array) $rows as $row) {
|
||||
$other_id = (int) $row['other_user_id'];
|
||||
$other_user = get_userdata($other_id);
|
||||
$conversations[] = [
|
||||
'id' => (int) $row['id'],
|
||||
'other_user_id' => $other_id,
|
||||
'other_name' => $other_user ? $other_user->display_name : __('用户', 'aksrt'),
|
||||
'other_avatar' => $other_user ? get_avatar_url($other_id, ['size' => 48]) : '',
|
||||
'last_message' => $row['last_message'] ?? '',
|
||||
'last_message_at' => $row['last_message_at'] ?? '',
|
||||
'unread' => (int) $row['my_unread'],
|
||||
];
|
||||
}
|
||||
|
||||
return $conversations;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
* Message CRUD
|
||||
* ----------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Send a message in a conversation.
|
||||
*
|
||||
* @param int $conversation_id
|
||||
* @param int $sender_id
|
||||
* @param string $content
|
||||
* @return array{success: bool, message_id?: int, message: string}
|
||||
*/
|
||||
public function send(int $conversation_id, int $sender_id, string $content): array {
|
||||
global $wpdb;
|
||||
|
||||
if ($conversation_id <= 0 || $sender_id <= 0) {
|
||||
return ['success' => false, 'message' => __('参数无效', 'aksrt')];
|
||||
}
|
||||
|
||||
$content = sanitize_textarea_field($content);
|
||||
if ($content === '') {
|
||||
return ['success' => false, 'message' => __('消息不能为空', 'aksrt')];
|
||||
}
|
||||
|
||||
// Verify user is a participant
|
||||
$conv = $wpdb->get_row($wpdb->prepare(
|
||||
"SELECT * FROM {$this->table_conv()} WHERE id = %d",
|
||||
$conversation_id
|
||||
), ARRAY_A);
|
||||
|
||||
if (!$conv) {
|
||||
return ['success' => false, 'message' => __('会话不存在', 'aksrt')];
|
||||
}
|
||||
|
||||
if ((int) $conv['user_a'] !== $sender_id && (int) $conv['user_b'] !== $sender_id) {
|
||||
return ['success' => false, 'message' => __('无权操作', 'aksrt')];
|
||||
}
|
||||
|
||||
$now = current_time('mysql');
|
||||
|
||||
// Insert message
|
||||
$wpdb->insert($this->table_msg(), [
|
||||
'conversation_id' => $conversation_id,
|
||||
'sender_id' => $sender_id,
|
||||
'content' => $content,
|
||||
'created_at' => $now,
|
||||
], ['%d', '%d', '%s', '%s']);
|
||||
|
||||
$message_id = (int) $wpdb->insert_id;
|
||||
|
||||
if (!$message_id) {
|
||||
return ['success' => false, 'message' => __('发送失败', 'aksrt')];
|
||||
}
|
||||
|
||||
// Update conversation metadata
|
||||
$is_a = (int) $conv['user_a'] === $sender_id;
|
||||
$unread_field = $is_a ? 'unread_b' : 'unread_a';
|
||||
|
||||
$wpdb->update($this->table_conv(), [
|
||||
'last_message' => mb_substr($content, 0, 200),
|
||||
'last_message_at' => $now,
|
||||
$unread_field => (int) $conv[$unread_field] + 1,
|
||||
], ['id' => $conversation_id]);
|
||||
|
||||
// Create notification for the recipient
|
||||
$recipient_id = $is_a ? (int) $conv['user_b'] : (int) $conv['user_a'];
|
||||
if (class_exists('AKSRT\\Messages\\Message')) {
|
||||
$sender_name = '';
|
||||
$sender_user = get_userdata($sender_id);
|
||||
if ($sender_user) {
|
||||
$sender_name = $sender_user->display_name;
|
||||
}
|
||||
Message::get_instance()->send(
|
||||
$recipient_id,
|
||||
'conversation',
|
||||
mb_substr($content, 0, 100),
|
||||
[
|
||||
'title' => sprintf(__('%s 发来私信', 'aksrt'), $sender_name),
|
||||
'target_url' => add_query_arg(['msg_type' => 'conversation']),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
do_action('aksrt_private_message_sent', $conversation_id, $sender_id, $recipient_id, $message_id);
|
||||
|
||||
return ['success' => true, 'message_id' => $message_id, 'message' => __('已发送', 'aksrt')];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get messages in a conversation (paginated, newest first).
|
||||
*
|
||||
* @param int $conversation_id
|
||||
* @param int $user_id Must be a participant.
|
||||
* @param int $page
|
||||
* @param int $per_page
|
||||
* @return array
|
||||
*/
|
||||
public function get_thread(int $conversation_id, int $user_id, int $page = 1, int $per_page = 30): array {
|
||||
global $wpdb;
|
||||
|
||||
if ($conversation_id <= 0 || $user_id <= 0) return ['messages' => [], 'total' => 0];
|
||||
|
||||
// Verify participation
|
||||
$conv = $wpdb->get_row($wpdb->prepare(
|
||||
"SELECT * FROM {$this->table_conv()} WHERE id = %d",
|
||||
$conversation_id
|
||||
), ARRAY_A);
|
||||
|
||||
if (!$conv || ((int) $conv['user_a'] !== $user_id && (int) $conv['user_b'] !== $user_id)) {
|
||||
return ['messages' => [], 'total' => 0];
|
||||
}
|
||||
|
||||
$offset = max(0, ($page - 1) * $per_page);
|
||||
|
||||
$total = (int) $wpdb->get_var($wpdb->prepare(
|
||||
"SELECT COUNT(*) FROM {$this->table_msg()} WHERE conversation_id = %d",
|
||||
$conversation_id
|
||||
));
|
||||
|
||||
$rows = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT * FROM {$this->table_msg()}
|
||||
WHERE conversation_id = %d
|
||||
ORDER BY created_at DESC
|
||||
LIMIT %d OFFSET %d",
|
||||
$conversation_id, $per_page, $offset
|
||||
), ARRAY_A);
|
||||
|
||||
$messages = [];
|
||||
foreach ((array) $rows as $row) {
|
||||
$sender = get_userdata((int) $row['sender_id']);
|
||||
$messages[] = [
|
||||
'id' => (int) $row['id'],
|
||||
'sender_id' => (int) $row['sender_id'],
|
||||
'sender_name' => $sender ? $sender->display_name : __('用户', 'aksrt'),
|
||||
'sender_avatar' => $sender ? get_avatar_url((int) $row['sender_id'], ['size' => 32]) : '',
|
||||
'content' => $row['content'] ?? '',
|
||||
'is_mine' => (int) $row['sender_id'] === $user_id,
|
||||
'created_at' => $row['created_at'] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
// Mark as read for this user
|
||||
$this->mark_conversation_read($conversation_id, $user_id);
|
||||
|
||||
return [
|
||||
'messages' => $messages,
|
||||
'total' => $total,
|
||||
'page' => $page,
|
||||
'pages' => max(1, (int) ceil($total / $per_page)),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark all messages in a conversation as read for a user.
|
||||
*/
|
||||
public function mark_conversation_read(int $conversation_id, int $user_id): void {
|
||||
global $wpdb;
|
||||
|
||||
$conv = $wpdb->get_row($wpdb->prepare(
|
||||
"SELECT * FROM {$this->table_conv()} WHERE id = %d",
|
||||
$conversation_id
|
||||
), ARRAY_A);
|
||||
|
||||
if (!$conv) return;
|
||||
|
||||
$is_a = (int) $conv['user_a'] === $user_id;
|
||||
$field = $is_a ? 'unread_a' : 'unread_b';
|
||||
|
||||
$wpdb->update($this->table_conv(), [$field => 0], ['id' => $conversation_id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get total unread conversation count for a user.
|
||||
*/
|
||||
public function get_unread_count(int $user_id): int {
|
||||
global $wpdb;
|
||||
|
||||
if ($user_id <= 0) return 0;
|
||||
|
||||
$count = $wpdb->get_var($wpdb->prepare(
|
||||
"SELECT SUM(CASE WHEN user_a = %d THEN unread_a ELSE unread_b END)
|
||||
FROM {$this->table_conv()}
|
||||
WHERE user_a = %d OR user_b = %d",
|
||||
$user_id, $user_id, $user_id
|
||||
));
|
||||
|
||||
return max(0, (int) $count);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
* AJAX Handlers
|
||||
* ----------------------------------------------------------------*/
|
||||
|
||||
public function ajax_send(): void {
|
||||
check_ajax_referer('aksrt_pm', '_nonce');
|
||||
|
||||
$user_id = get_current_user_id();
|
||||
if ($user_id <= 0) wp_send_json_error(['message' => __('请先登录', 'aksrt')]);
|
||||
|
||||
$recipient_id = (int) ($_POST['recipient_id'] ?? 0);
|
||||
$content = sanitize_textarea_field((string) ($_POST['content'] ?? ''));
|
||||
|
||||
if ($recipient_id <= 0) wp_send_json_error(['message' => __('收件人无效', 'aksrt')]);
|
||||
|
||||
$conv_id = $this->get_or_create_conversation($user_id, $recipient_id);
|
||||
if (!$conv_id) wp_send_json_error(['message' => __('无法创建会话', 'aksrt')]);
|
||||
|
||||
$result = $this->send($conv_id, $user_id, $content);
|
||||
|
||||
if ($result['success']) {
|
||||
wp_send_json_success($result);
|
||||
}
|
||||
wp_send_json_error($result);
|
||||
}
|
||||
|
||||
public function ajax_conversations(): void {
|
||||
check_ajax_referer('aksrt_pm', '_nonce');
|
||||
|
||||
$user_id = get_current_user_id();
|
||||
if ($user_id <= 0) wp_send_json_error(['message' => __('请先登录', 'aksrt')]);
|
||||
|
||||
$limit = max(1, min(50, (int) ($_GET['limit'] ?? 20)));
|
||||
$conversations = $this->get_conversations($user_id, $limit);
|
||||
|
||||
wp_send_json_success(['conversations' => $conversations]);
|
||||
}
|
||||
|
||||
public function ajax_thread(): void {
|
||||
check_ajax_referer('aksrt_pm', '_nonce');
|
||||
|
||||
$user_id = get_current_user_id();
|
||||
if ($user_id <= 0) wp_send_json_error(['message' => __('请先登录', 'aksrt')]);
|
||||
|
||||
$conv_id = (int) ($_GET['conversation_id'] ?? 0);
|
||||
$page = max(1, (int) ($_GET['page'] ?? 1));
|
||||
|
||||
$result = $this->get_thread($conv_id, $user_id, $page);
|
||||
wp_send_json_success($result);
|
||||
}
|
||||
|
||||
public function ajax_mark_read(): void {
|
||||
check_ajax_referer('aksrt_pm', '_nonce');
|
||||
|
||||
$user_id = get_current_user_id();
|
||||
if ($user_id <= 0) wp_send_json_error(['message' => __('请先登录', 'aksrt')]);
|
||||
|
||||
$conv_id = (int) ($_POST['conversation_id'] ?? 0);
|
||||
$this->mark_conversation_read($conv_id, $user_id);
|
||||
|
||||
wp_send_json_success(['unread' => $this->get_unread_count($user_id)]);
|
||||
}
|
||||
|
||||
public function ajax_unread_count(): void {
|
||||
check_ajax_referer('aksrt_pm', '_nonce');
|
||||
|
||||
$user_id = get_current_user_id();
|
||||
if ($user_id <= 0) wp_send_json_error(['message' => __('请先登录', 'aksrt')]);
|
||||
|
||||
wp_send_json_success(['unread' => $this->get_unread_count($user_id)]);
|
||||
}
|
||||
}
|
||||
@@ -194,7 +194,6 @@ trait DisplayPageGroups {
|
||||
'seo' => self::get_seo_settings(),
|
||||
'mail' => self::get_smtp(),
|
||||
'email_events' => self::get_email_event_config(),
|
||||
'email_private_receive_limit' => self::get_email_private_receive_limit(),
|
||||
'footer' => self::get_footer_settings(),
|
||||
'tabbar' => self::get_footer_tabbar_settings(),
|
||||
'floating_buttons' => self::get_floating_buttons_settings(),
|
||||
|
||||
@@ -100,11 +100,6 @@ trait DomainGroups {
|
||||
return Integration::auto_clear_settings();
|
||||
}
|
||||
|
||||
/** 私信功能配置 */
|
||||
public static function private_message_settings(): array {
|
||||
return Integration::private_message_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单项扩展 meta 字段列表
|
||||
*/
|
||||
|
||||
@@ -9,13 +9,6 @@ defined('ABSPATH') || exit;
|
||||
|
||||
class Integration {
|
||||
|
||||
/** 私信邮件接收组限制 (all/vip/vip2/admin) */
|
||||
public static function get_email_private_receive_limit(): string {
|
||||
$limit = (string) Settings::get_value('email_private_receive_limit', 'all');
|
||||
$valid = ['all', 'vip', 'vip2', 'admin'];
|
||||
return in_array($limit, $valid, true) ? $limit : 'all';
|
||||
}
|
||||
|
||||
/** 获取OAuth配置 */
|
||||
public static function get_oauth(): array {
|
||||
return get_option('aksrt_oauth', []);
|
||||
@@ -386,7 +379,7 @@ class Integration {
|
||||
if (!is_array($types)) {
|
||||
$types = [];
|
||||
}
|
||||
$allowed = ['posts', 'comment', 'favorite', 'like', 'hot', 'followed', 'system', 'pay', 'withdraw_reply', 'medal', 'auth_apply_reply', 'download', 'credits', 'private', 'report'];
|
||||
$allowed = ['posts', 'comment', 'favorite', 'like', 'hot', 'followed', 'system', 'pay', 'withdraw_reply', 'medal', 'auth_apply_reply', 'download', 'credits', 'report'];
|
||||
return [
|
||||
'enabled' => !empty($settings['message_auto_clear_s']),
|
||||
'days' => max(1, min(3650, (int) ($settings['message_auto_clear_time'] ?? 365))),
|
||||
@@ -394,25 +387,6 @@ class Integration {
|
||||
];
|
||||
}
|
||||
|
||||
/** 私信功能配置 */
|
||||
public static function private_message_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
$quick_often = (string) ($settings['private_quick_often'] ?? "你好,请问有什么可以帮你的?\n感谢你的反馈\n已处理,请查收");
|
||||
$quick_lines = array_filter(array_map('trim', preg_split('/\r\n|\r|\n/', $quick_often)));
|
||||
|
||||
return [
|
||||
'enabled' => !array_key_exists('private_s', $settings) || !empty($settings['private_s']),
|
||||
'smilie' => !empty($settings['private_smilie_s']),
|
||||
'code' => !empty($settings['private_code_s']),
|
||||
'image' => !empty($settings['private_image_s']),
|
||||
'upload_img' => !empty($settings['private_upload_img']),
|
||||
'quick_reply' => !empty($settings['private_quick_s']),
|
||||
'quick_often' => array_values($quick_lines),
|
||||
'submit_text' => sanitize_text_field((string) ($settings['private_submit_text'] ?? '发送')),
|
||||
'placeholder' => sanitize_text_field((string) ($settings['private_placeholder'] ?? '请输入消息...')),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取右侧浮动按钮完整配置
|
||||
* @return array {enabled, style, position, scroll_hide, scroll_down_hide, filter_blur, items}
|
||||
|
||||
@@ -729,15 +729,6 @@ class Settings {
|
||||
DisplayRuntime::save_friend_links($links);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 私信邮件接收组限制 (all/vip/vip2/admin) */
|
||||
public static function get_email_private_receive_limit(): string {
|
||||
return Integration::get_email_private_receive_limit();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 获取OAuth配置 */
|
||||
public static function get_oauth(): array {
|
||||
return Integration::get_oauth();
|
||||
|
||||
Reference in New Issue
Block a user