PluginProbe
Extendify / 2.2.0
Extendify v2.2.0
3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 0.7.0 All 126 releases
extendify / app / Agent / Controllers / ChatHistoryController.php

ChatHistoryController.php in Extendify 2.2.0, at app/Agent/Controllers/ChatHistoryController.php

195 lines 5.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Store info about messages/events from chat
5 */
6
7 namespace Extendify\Agent\Controllers;
8
9 defined('ABSPATH') || die('No direct access.');
10
11 use Extendify\Shared\Services\Sanitizer;
12
13 /**
14 * The controller
15 */
16
17 class ChatHistoryController
18 {
19 /**
20 * Initialize the controller and set up the database table.
21 *
22 * @return \WP_REST_Response
23 */
24 public static function init()
25 {
26 self::setupChatHistoryTable();
27 }
28
29 /**
30 * Get the last 150 messages
31 *
32 * @return array
33 */
34 public static function getChatHistory($user_id = null)
35 {
36 global $wpdb;
37 $table = $wpdb->prefix . 'extendify_agent_events';
38 $user_id = $user_id ?: get_current_user_id();
39
40 $results = $wpdb->get_results(
41 $wpdb->prepare(
42 "SELECT * FROM $table WHERE user_id = %d ORDER BY id DESC LIMIT 150",
43 $user_id
44 ),
45 ARRAY_A
46 );
47 return array_map(function ($item) {
48 return [
49 'id' => $item['event_id'],
50 'type' => $item['type'],
51 'details' => json_decode($item['details'], true),
52 ];
53 }, $results);
54 }
55
56
57 /**
58 * Return the data
59 *
60 * @return \WP_REST_Response
61 */
62 public static function get()
63 {
64 $messages = self::getChatHistory();
65 $state = ['state' => ['messages' => Sanitizer::sanitizeArray($messages)]];
66 return new \WP_REST_Response($state);
67 }
68
69 /**
70 * Persist the data
71 *
72 * @param \WP_REST_Request $request - The request.
73 * @return \WP_REST_Response
74 */
75 public static function store($request)
76 {
77 global $wpdb;
78 $table = $wpdb->prefix . 'extendify_agent_events';
79 $user_id = get_current_user_id();
80
81 $state = $request->get_param('state');
82 $parsed = is_string($state) ? json_decode($state, true) : $state;
83 $messages = $parsed['state']['messages'] ?? [];
84
85 // Find the latest event and only add new messages since then.
86 $latest = $wpdb->get_var(
87 $wpdb->prepare(
88 "SELECT event_id FROM $table WHERE user_id = %d ORDER BY created_at DESC LIMIT 1",
89 $user_id
90 )
91 );
92 $startIndex = 0;
93 if ($latest) {
94 foreach ($messages as $i => $msg) {
95 if ($msg['id'] === $latest) {
96 $startIndex = $i + 1;
97 break;
98 }
99 }
100 }
101
102 $toInsert = array_slice($messages, $startIndex);
103 foreach ($toInsert as $msg) {
104 self::upsertEvent($msg, $user_id);
105 }
106
107 return self::get();
108 }
109
110 /**
111 * Upsert an event into the database.
112 *
113 * @param array $msg The message data.
114 * @param int $user_id The user ID.
115 * @return void
116 */
117 private static function upsertEvent($msg, $user_id)
118 {
119 global $wpdb;
120 $table = $wpdb->prefix . 'extendify_agent_events';
121 $created_at = current_time('mysql');
122 $event_id = Sanitizer::sanitizeText($msg['id']);
123 $type = Sanitizer::sanitizeText($msg['type']);
124 $details = wp_json_encode(Sanitizer::sanitizeArray($msg['details']));
125
126 $sql = $wpdb->prepare(
127 "INSERT INTO $table (created_at, event_id, type, details, user_id)
128 VALUES (%s, %s, %s, %s, %d)
129 ON DUPLICATE KEY UPDATE
130 created_at = VALUES(created_at),
131 type = VALUES(type),
132 details = VALUES(details)",
133 $created_at,
134 $event_id,
135 $type,
136 $details,
137 $user_id
138 );
139 $wpdb->query($sql);
140 }
141
142 /**
143 * Ensures the custom table exists and is up to date for MySQL.
144 * Creates the table if missing, adds missing columns, and ensures an index on user_id.
145 *
146 * @return void
147 */
148 private static function setupChatHistoryTable()
149 {
150 global $wpdb;
151 $table = $wpdb->prefix . 'extendify_agent_events';
152 $columns = [
153 'id' => "BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY",
154 'created_at' => "DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP",
155 'event_id' => "VARCHAR(64) NOT NULL",
156 'type' => "VARCHAR(64) NOT NULL",
157 'details' => "LONGTEXT",
158 'user_id' => "BIGINT UNSIGNED NOT NULL"
159 ];
160
161 // Check if the table exists and create it if not
162 $exists = $wpdb->get_var("SHOW TABLES LIKE '$table'");
163 if (!$exists) {
164 $cols = [];
165 foreach ($columns as $name => $type) {
166 $cols[] = "$name $type";
167 }
168 $sql = "CREATE TABLE $table (" . implode(',', $cols) . ", INDEX(user_id))";
169 $sql .= " " . $wpdb->get_charset_collate() . ";";
170 $wpdb->query($sql);
171 return;
172 }
173
174 // Check existing columns and add missing ones
175 $existingCols = array_column($wpdb->get_results("SHOW COLUMNS FROM $table", ARRAY_A), 'Field');
176 foreach ($columns as $name => $type) {
177 if (!in_array($name, $existingCols, true)) {
178 $wpdb->query("ALTER TABLE $table ADD COLUMN $name $type");
179 }
180 }
181
182 // Unique index on (event_id, user_id)
183 $uniqueIndex = $wpdb->get_results("SHOW INDEX FROM $table WHERE Key_name = 'unique_event_id'", ARRAY_A);
184 if (empty($uniqueIndex)) {
185 $wpdb->query("CREATE UNIQUE INDEX unique_event_id ON $table(event_id, user_id)");
186 }
187
188 // Regular index on user_id
189 $userIndex = $wpdb->get_results("SHOW INDEX FROM $table WHERE Key_name = 'user_id'", ARRAY_A);
190 if (empty($userIndex)) {
191 $wpdb->query("CREATE INDEX user_id ON $table(user_id)");
192 }
193 }
194 }
195