'success', 'full_name' => $account['full_name'], 'role' => $account['role'], 'can_manage' => current_user_can(RAPIDCHAT_CAP_MANAGE), 'can_assign' => rapidchat_user_can('rapidchat_assign'), )); } add_action('wp_ajax_rapidchat_admin_conversations_user', 'rapidchat_admin_conversations_user'); function rapidchat_admin_conversations_user() { global $wpdb; $account = rapidchat_require_operator(); $wpdb->update( $wpdb->rapidchat_accounts, array('status' => 'Waiting', 'last_seen' => current_time('mysql')), array('id' => (int) $account['id']), array('%s', '%s'), array('%d') ); $filter = isset($_POST['filter']) ? sanitize_text_field(wp_unslash($_POST['filter'])) : 'all'; echo rapidchat_kses(rapidchat_render_admin_conversations($account, $filter)); wp_die(); } /** Fill team_name / team_colour on conversation rows (arrays or objects) from the rapidchat_team_labels filter. */ function rapidchat_add_team_labels($rows) { $team_ids = array(); foreach ($rows as $row) { $team_ids[] = (int) (is_object($row) ? $row->team_id : $row['team_id']); } $team_ids = array_values(array_filter(array_unique($team_ids))); $labels = $team_ids ? (array) apply_filters('rapidchat_team_labels', array(), $team_ids) : array(); foreach ($rows as $key => $row) { $team_id = (int) (is_object($row) ? $row->team_id : $row['team_id']); $name = isset($labels[$team_id]['name']) ? (string) $labels[$team_id]['name'] : ''; $colour = isset($labels[$team_id]['colour']) ? (string) $labels[$team_id]['colour'] : ''; if (is_object($row)) { $row->team_name = $name; $row->team_colour = $colour; } else { $rows[$key]['team_name'] = $name; $rows[$key]['team_colour'] = $colour; } } return $rows; } /** One row per conversation, filtered and ordered in the database. */ function rapidchat_admin_conversations($operator_id, $limit = RAPIDCHAT_LIST_LIMIT, $filter = 'all') { global $wpdb; $visibility = rapidchat_operator_visibility($operator_id); $filters = array( 'all' => array('', array()), 'closed' => array(" AND c.state = 'closed'", array()), 'mine' => array(" AND c.state = 'open' AND EXISTS (SELECT 1 FROM %i cp_mine WHERE cp_mine.conversation_id = c.id AND cp_mine.operator_id = %d AND cp_mine.is_available IN (0, 3))", array($wpdb->rapidchat_participants, (int) $operator_id)), 'queued' => array(" AND c.state = 'open' AND NOT EXISTS (SELECT 1 FROM %i cp_claimed WHERE cp_claimed.conversation_id = c.id AND cp_claimed.is_available = 0)", array($wpdb->rapidchat_participants)), 'unread' => array(' AND (SELECT COUNT(*) FROM %i um WHERE um.conversation_id = c.id AND um.is_read = 0 AND um.account_id = c.account_sender_id) > 0', array($wpdb->rapidchat_messages)), ); list($filter_sql, $filter_args) = isset($filters[$filter]) ? $filters[$filter] : $filters['all']; // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- $visibility['sql'] and $filter_sql are literal SQL with placeholders only; every value is bound by prepare(). $rows = $wpdb->get_results( $wpdb->prepare( "SELECT c.id, c.account_sender_id, c.account_receiver_id, c.submit_date, c.last_activity, c.state, c.team_id, c.custom_fields, c.rating, c.feedback, c.closed_at, a.full_name AS sender_name, a.country AS sender_country, a2.full_name AS receiver_name, a2.country AS receiver_country, lm.msg AS msg, lm.submit_date AS msg_date, lm.msg_type AS msg_type, CASE WHEN EXISTS (SELECT 1 FROM %i cp_mine WHERE cp_mine.conversation_id = c.id AND cp_mine.operator_id = %d AND cp_mine.is_available = 0) THEN 0 WHEN EXISTS (SELECT 1 FROM %i cp_join WHERE cp_join.conversation_id = c.id AND cp_join.operator_id = %d AND cp_join.is_available = 3) THEN 3 WHEN EXISTS (SELECT 1 FROM %i cp_other WHERE cp_other.conversation_id = c.id AND cp_other.is_available = 0) THEN 2 ELSE 1 END AS is_available, (SELECT COUNT(*) FROM %i um WHERE um.conversation_id = c.id AND um.is_read = 0 AND um.account_id = c.account_sender_id) AS unread_count, (SELECT a3.full_name FROM %i cp3 JOIN %i a3 ON a3.id = cp3.operator_id WHERE cp3.conversation_id = c.id AND cp3.is_available = 0 LIMIT 1) AS assigned_name, (SELECT cp4.operator_id FROM %i cp4 WHERE cp4.conversation_id = c.id AND cp4.is_available = 0 LIMIT 1) AS assigned_id FROM %i c JOIN %i a ON a.id = c.account_sender_id JOIN %i a2 ON a2.id = c.account_receiver_id LEFT JOIN %i lm ON lm.id = (SELECT MAX(m2.id) FROM %i m2 WHERE m2.conversation_id = c.id) WHERE 1=1" . $visibility['sql'] . $filter_sql . ' ORDER BY COALESCE(c.last_activity, c.submit_date) DESC LIMIT %d', array_merge( array( $wpdb->rapidchat_participants, (int) $operator_id, $wpdb->rapidchat_participants, (int) $operator_id, $wpdb->rapidchat_participants, $wpdb->rapidchat_messages, $wpdb->rapidchat_participants, $wpdb->rapidchat_accounts, $wpdb->rapidchat_participants, $wpdb->rapidchat_conversations, $wpdb->rapidchat_accounts, $wpdb->rapidchat_accounts, $wpdb->rapidchat_messages, $wpdb->rapidchat_messages, ), $visibility['args'], $filter_args, array((int) $limit) ) ), ARRAY_A ); // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared return rapidchat_add_team_labels((array) $rows); } function rapidchat_render_admin_conversations(array $account, $filter = 'all') { $operator_id = (int) $account['id']; $conversations = rapidchat_admin_conversations($operator_id, RAPIDCHAT_LIST_LIMIT, $filter); $can_queue = rapidchat_user_can('rapidchat_reply'); $can_assign = rapidchat_user_can('rapidchat_assign'); $output = '
'; return $output; } $unread_items = ''; $mine = ''; $queued = ''; $others = ''; $closed = ''; foreach ($conversations as $conversation) { $is_mine = ((int) $conversation['account_sender_id'] === $operator_id); $contact_name = $is_mine ? $conversation['receiver_name'] : $conversation['sender_name']; $contact_id = $is_mine ? $conversation['account_receiver_id'] : $conversation['account_sender_id']; $country = $is_mine ? $conversation['receiver_country'] : $conversation['sender_country']; $unread = (int) $conversation['unread_count']; $is_closed = ($conversation['state'] !== 'open'); $assigned_id = (int) $conversation['assigned_id']; $is_joined = ((int) $conversation['is_available'] === 3); $mine_now = ($assigned_id === $operator_id || (int) $conversation['is_available'] === 0 || $is_joined); $is_queued = (!$assigned_id && !$is_closed && ((int) $conversation['is_available'] === 1 || empty($conversation['assigned_id']))); $custom_fields = json_decode((string) $conversation['custom_fields'], true); $tags = (is_array($custom_fields) && !empty($custom_fields['tags'])) ? (array) $custom_fields['tags'] : array(); $tags_attr = esc_attr(implode(' ', array_map('strtolower', $tags))); $item = ''; if ($filter === 'unread') { $unread_items .= $item; } elseif ($is_closed) { $closed .= $item; } elseif ($mine_now) { $mine .= $item; } elseif ($is_queued) { $queued .= $item; } elseif ($can_assign) { $others .= $item; } } if ($filter === 'unread') { if ($unread_items !== '') { $output .= '' . $unread_items; } } elseif ($filter === 'mine') { if ($mine !== '') { $output .= '' . $mine; } } elseif ($filter === 'queued') { if ($queued !== '') { $output .= '' . $queued; } } elseif ($filter === 'closed') { if ($closed !== '') { $output .= '' . $closed; } } else { if ($mine !== '') { $output .= '' . $mine; } if ($queued !== '' && $can_queue) { $output .= '' . $queued; } if ($others !== '') { $output .= '' . $others; } if ($closed !== '') { $output .= '' . $closed; } } $output .= ''; return $output; } add_action('wp_ajax_rapidchat_conversation_admin', 'rapidchat_conversation_admin'); function rapidchat_conversation_admin() { global $wpdb; $account = rapidchat_require_operator(); $operator_id = (int) $account['id']; $conversation_id = isset($_POST['conversation_id']) ? (int) $_POST['conversation_id'] : 0; if (!rapidchat_can_access_conversation($operator_id, $conversation_id, true)) { wp_send_json_error(__('Conversation not found.', 'rapidchat'), 403); } $conversation = $wpdb->get_row($wpdb->prepare( 'SELECT c.*, a.full_name AS sender_name, a.email AS sender_email, a.ip_address AS sender_ip, a.country AS sender_country, a.wp_user_id AS sender_wp_user_id, a.role AS sender_role, a.last_seen AS sender_last_seen, a.status AS sender_status, a2.full_name AS receiver_name, a2.email AS receiver_email, a2.ip_address AS receiver_ip, a2.country AS receiver_country, a2.wp_user_id AS receiver_wp_user_id, a2.role AS receiver_role, a2.last_seen AS receiver_last_seen, a2.status AS receiver_status FROM %i c JOIN %i a ON a.id = c.account_sender_id JOIN %i a2 ON a2.id = c.account_receiver_id WHERE c.id = %d', $wpdb->rapidchat_conversations, $wpdb->rapidchat_accounts, $wpdb->rapidchat_accounts, $conversation_id )); if (!$conversation) { wp_send_json_error(__('Conversation not found.', 'rapidchat'), 404); } list($conversation) = rapidchat_add_team_labels(array($conversation)); $sender_id = (int) $conversation->account_sender_id; $conversation->total_chats = (int) $wpdb->get_var($wpdb->prepare( "SELECT COUNT(*) FROM %i WHERE account_sender_id = %d", $wpdb->rapidchat_conversations, $sender_id )); $assignments = rapidchat_conversation_assignments($conversation_id); $is_available = isset($assignments[$operator_id]) ? (int) $assignments[$operator_id]->is_available : (rapidchat_conversation_is_claimed($assignments) ? 2 : 1); if ($is_available === 0 || $is_available === 3) { $wpdb->query($wpdb->prepare( 'UPDATE %i SET is_read = 1 WHERE conversation_id = %d AND account_id <> %d AND is_read = 0', $wpdb->rapidchat_messages, $conversation_id, $operator_id )); } $messages = $wpdb->get_results($wpdb->prepare( 'SELECT id, account_id, msg, attachment_url, attachment_type, attachment_name, attachment_size, msg_type, submit_date FROM %i WHERE conversation_id = %d ORDER BY id ASC LIMIT 500', $wpdb->rapidchat_messages, $conversation_id )); $names = rapidchat_account_names(wp_list_pluck($messages, 'account_id')); $operator_ids = array_map('intval', array_keys($assignments)); $read_through = rapidchat_conversation_read_through($conversation_id, $operator_id); echo rapidchat_kses(rapidchat_render_admin_conversation($conversation, $messages, $names, $account, $assignments, $operator_ids, $is_available, $read_through)); wp_die(); } function rapidchat_conversation_is_claimed(array $assignments) { foreach ($assignments as $row) { if ((int) $row->is_available === 0) { return true; } } return false; } function rapidchat_conversation_assignments($conversation_id) { global $wpdb; return $wpdb->get_results( $wpdb->prepare( 'SELECT operator_id, is_available FROM %i WHERE conversation_id = %d', $wpdb->rapidchat_participants, (int) $conversation_id ), OBJECT_K ); } /** Every policy decision the conversation view needs, keyed by action. */ function rapidchat_conversation_permissions($conversation_id, array $account) { $perms = array(); foreach (array('claim', 'reply', 'note', 'manage', 'close', 'transfer', 'assign', 'join', 'invite', 'leave', 'delete') as $action) { $perms[$action] = rapidchat_operator_can($action, $conversation_id, $account); } return $perms; } function rapidchat_render_admin_conversation($conversation, $messages, array $names, array $account, array $assignments, array $operator_ids, $is_available, $read_through = 0) { $operator_id = (int) $account['id']; $perms = rapidchat_conversation_permissions((int) $conversation->id, $account); $chat_team = rapidchat_conversation_team((int) $conversation->id); $holder = null; foreach ($chat_team as $member) { if ((int) $member['state'] === 0) { $holder = $member; break; } } $is_owner = $holder && (int) $holder['id'] === $operator_id; $view = array( 'conversation' => $conversation, 'account' => $account, 'perms' => $perms, 'chat_team' => $chat_team, 'holder' => $holder, 'is_owner' => $is_owner, ); $is_sender = ($operator_id === (int) $conversation->account_sender_id); $contact_name = $is_sender ? $conversation->receiver_name : $conversation->sender_name; $contact_ctry = $is_sender ? $conversation->receiver_country : $conversation->sender_country; $output = ''; return $output; } $output .= ''; $output .= apply_filters('rapidchat_conversation_before_messages', '', $view); $output .= ''; $output .= rapidchat_render_messages($messages, $names, $operator_id, $operator_ids, 'admin', $read_through); $output .= '' . esc_html__('This conversation is closed.', 'rapidchat') . '
' . esc_html__('Read-only: you are not part of this chat.', 'rapidchat') . '