PluginProbe
VikBooking Hotel Booking Engine & PMS / trunk
VikBooking Hotel Booking Engine & PMS vtrunk
1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 All 36 releases
vikbooking / site / controllers / chat.php

chat.php in VikBooking Hotel Booking Engine & PMS trunk, at site/controllers/chat.php

471 lines 15.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikBooking
4 * @subpackage core
5 * @author E4J s.r.l.
6 * @copyright Copyright (C) 2025 E4J s.r.l. All Rights Reserved.
7 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
8 * @link https://vikwp.com
9 */
10
11 // No direct access
12 defined('ABSPATH') or die('No script kiddies please!');
13
14 /**
15 * VikBooking generic chat controller.
16 *
17 * @since 1.8
18 */
19 class VikBookingControllerChat extends JControllerAdmin
20 {
21 /**
22 * Task used to render the chat asynchronously.
23 *
24 * @return void
25 */
26 public function render_chat()
27 {
28 $app = JFactory::getApplication();
29
30 if (!JSession::checkToken()) {
31 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN'));
32 }
33
34 // fetch request data
35 $contextId = $app->input->getUint('id_context', 0);
36 $context = $app->input->get('context', '');
37
38 try {
39 /** @var VBOChatMediator */
40 $chat = VBOFactory::getChatMediator();
41
42 /** @var VBOChatContext */
43 $context = $chat->createContext($context, $contextId);
44
45 if (!$chat->getUser()->can('chat.render', $context)) {
46 // not authorized
47 throw new RuntimeException(JText::translate('JERROR_ALERTNOAUTHOR'), 403);
48 }
49
50 // render the chat
51 $html = $chat->render($context, [
52 'assets' => false,
53 ]);
54 } catch (Exception $error) {
55 VBOHttpDocument::getInstance($app)->close($error->getCode() ?: 500, $error->getMessage());
56 }
57
58 // output the result content
59 VBOHttpDocument::getInstance($app)->json(['html' => $html]);
60 }
61
62 /**
63 * Task used to periodically search for new messages under a given context.
64 *
65 * @return void
66 */
67 public function sync_messages()
68 {
69 $app = JFactory::getApplication();
70
71 if (!JSession::checkToken()) {
72 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN'));
73 }
74
75 // fetch request data
76 $contextId = $app->input->getUint('id_context', 0);
77 $context = $app->input->get('context', '');
78 $threshold = $app->input->getUint('threshold', 0);
79
80 try {
81 /** @var VBOChatMediator */
82 $chat = VBOFactory::getChatMediator();
83
84 /** @var VBOChatContext */
85 $context = $chat->createContext($context, $contextId);
86
87 if (!$chat->getUser()->can('chat.sync', $context)) {
88 // not authorized
89 throw new RuntimeException(JText::translate('JERROR_ALERTNOAUTHOR'), 403);
90 }
91
92 // obtain all the messages under the created context with an ID higher than the specified threshold
93 $messages = $chat->getMessages(
94 (new VBOChatSearch)
95 ->withContext($context)
96 ->message($threshold, '>')
97 );
98
99 // maintain the user logged in
100 $chat->getUser()->keepAlive($context);
101
102 // obtain the public context metadata
103 $metadata = $context->getMetadata($public = true);
104 } catch (Exception $error) {
105 VBOHttpDocument::getInstance($app)->close($error->getCode() ?: 500, $error->getMessage());
106 }
107
108 // output the result content
109 VBOHttpDocument::getInstance($app)->json([
110 'messages' => $messages,
111 'metadata' => $metadata,
112 ]);
113 }
114
115 /**
116 * Task used to scan the pagination of a specified chat.
117 *
118 * @return void
119 */
120 public function load_older_messages()
121 {
122 $app = JFactory::getApplication();
123
124 if (!JSession::checkToken()) {
125 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN'));
126 }
127
128 // fetch request data
129 $contextId = $app->input->getUint('id_context', 0);
130 $context = $app->input->get('context', '');
131 $start = $app->input->getUint('start', 0);
132 $limit = $app->input->getUint('limit', 20);
133 $datetime = $app->input->getString('datetime', null);
134
135 try {
136 /** @var VBOChatMediator */
137 $chat = VBOFactory::getChatMediator();
138
139 /** @var VBOChatContext */
140 $context = $chat->createContext($context, $contextId);
141
142 if (!$chat->getUser()->can('chat.load', $context)) {
143 // not authorized
144 throw new RuntimeException(JText::translate('JERROR_ALERTNOAUTHOR'), 403);
145 }
146
147 // obtain all the messages under the created context with a creation date equal or lower than the specified threshold
148 $messages = $chat->getMessages(
149 (new VBOChatSearch)
150 ->start($start)
151 ->limit($limit)
152 ->withContext($context)
153 ->date($datetime, '<=')
154 );
155 } catch (Exception $error) {
156 VBOHttpDocument::getInstance($app)->close($error->getCode() ?: 500, $error->getMessage());
157 }
158
159 // output the result content
160 VBOHttpDocument::getInstance($app)->json($messages);
161 }
162
163 /**
164 * Task used to send a chat message under a given context.
165 *
166 * @return void
167 */
168 public function send()
169 {
170 $app = JFactory::getApplication();
171
172 if (!JSession::checkToken()) {
173 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN'));
174 }
175
176 // fetch request data
177 $contextId = $app->input->getUint('id_context', 0);
178 $context = $app->input->get('context', '');
179 $message = $app->input->getString('message', '');
180 $createdon = $app->input->getString('createdon', '');
181 $attachments = $app->input->get('attachments', [], 'array');
182
183 try {
184 /** @var VBOChatMediator */
185 $chat = VBOFactory::getChatMediator();
186
187 /** @var VBOChatContext */
188 $context = $chat->createContext($context, $contextId);
189
190 if (!$chat->getUser()->can('chat.send', $context)) {
191 // not authorized
192 throw new RuntimeException(JText::translate('JERROR_ALERTNOAUTHOR'), 403);
193 }
194
195 foreach ($attachments as &$attachment) {
196 // create attachment from JSON
197 $attachment = new VBOChatAttachment($attachment);
198 }
199
200 /** @var VBOChatMessage */
201 $message = $chat->createMessage([
202 'context' => $context->getAlias(),
203 'id_context' => $context->getID(),
204 'message' => $message,
205 'attachments' => $attachments,
206 'createdon' => $createdon,
207 ]);
208
209 // deliver the message
210 $chat->send($message);
211 } catch (Exception $error) {
212 VBOHttpDocument::getInstance($app)->close($error->getCode() ?: 500, $error->getMessage());
213 }
214
215 // output the result content
216 VBOHttpDocument::getInstance($app)->json($message);
217 }
218
219 /**
220 * AJAX end-point used to upload attachments before sending the message.
221 * Files are uploaded onto the attachments folder of the front-end and a
222 * JSON encoded objects array is returned with the details of each file.
223 *
224 * @return void
225 */
226 public function upload_attachments()
227 {
228 $app = JFactory::getApplication();
229
230 if (!JSession::checkToken()) {
231 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN'));
232 }
233
234 // fetch request data
235 $contextId = $app->input->getUint('id_context', 0);
236 $context = $app->input->get('context', '');
237 $files = $app->input->files->get('attachments', [], 'raw');
238
239 if (isset($files['name'])) {
240 // we have a single associative array, we need to push it within a list,
241 // because the upload iterates the $files array
242 $files = [$files];
243 }
244
245 $attachments = [];
246
247 try {
248 /** @var VBOChatMediator */
249 $chat = VBOFactory::getChatMediator();
250
251 /** @var VBOChatContext */
252 $context = $chat->createContext($context, $contextId);
253
254 if (!$chat->getUser()->can('chat.attachment.add', $context)) {
255 // not authorized
256 throw new RuntimeException(JText::translate('JERROR_ALERTNOAUTHOR'), 403);
257 }
258
259 foreach ($files as $file) {
260 /** @var VBOChatAttachment */
261 $attachment = $chat->uploadAttachment($file);
262
263 // register attachment within the list
264 $attachments[] = $attachment;
265 }
266 } catch (Exception $error) {
267 // iterate all uploaded attachments and unlink them
268 foreach ($attachments as $attachment) {
269 $chat->removeAttachment($attachment);
270 }
271
272 VBOHttpDocument::getInstance($app)->close($error->getCode() ?: 500, $error->getMessage());
273 }
274
275 // output the result content
276 VBOHttpDocument::getInstance($app)->json($attachments);
277 }
278
279 /**
280 * AJAX end-point used to remove the selected attachment.
281 *
282 * @return void
283 */
284 public function remove_attachment()
285 {
286 $app = JFactory::getApplication();
287
288 if (!JSession::checkToken()) {
289 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN'));
290 }
291
292 // fetch request data
293 $contextId = $app->input->getUint('id_context', 0);
294 $context = $app->input->get('context', '');
295 $file = $app->input->get('attachment', [], 'array');
296
297 try {
298 /** @var VBOChatMediator */
299 $chat = VBOFactory::getChatMediator();
300
301 /** @var VBOChatContext */
302 $context = $chat->createContext($context, $contextId);
303
304 if (!$chat->getUser()->can('chat.attachment.remove', $context)) {
305 // not authorized
306 throw new RuntimeException(JText::translate('JERROR_ALERTNOAUTHOR'), 403);
307 }
308
309 // create attachment
310 $attachment = new VBOChatAttachment($file);
311
312 // attempt to remove the attachment
313 if (!$chat->removeAttachment($attachment)) {
314 throw new RuntimeException('Unable to remove the attachment: ' . $attachment->getName(), 403);
315 }
316 } catch (Exception $error) {
317 VBOHttpDocument::getInstance($app)->close($error->getCode() ?: 500, $error->getMessage());
318 }
319
320 $app->close();
321 }
322
323 /**
324 * Task used to read the unread messages of a specified chat.
325 *
326 * @return void
327 */
328 public function read_messages()
329 {
330 $app = JFactory::getApplication();
331
332 if (!JSession::checkToken()) {
333 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN'));
334 }
335
336 // fetch request data
337 $contextId = $app->input->getUint('id_context', 0);
338 $context = $app->input->get('context', '');
339 $datetime = $app->input->getString('datetime', null);
340
341 try {
342 /** @var VBOChatMediator */
343 $chat = VBOFactory::getChatMediator();
344
345 /** @var VBOChatContext */
346 $context = $chat->createContext($context, $contextId);
347
348 if (!$chat->getUser()->can('chat.read', $context)) {
349 // not authorized
350 throw new RuntimeException(JText::translate('JERROR_ALERTNOAUTHOR'), 403);
351 }
352
353 // obtain a list holding the ID of all the read messages
354 $messages = $chat->readMessages($context, $datetime);
355 } catch (Exception $error) {
356 VBOHttpDocument::getInstance($app)->close($error->getCode() ?: 500, $error->getMessage());
357 }
358
359 // output the result content
360 VBOHttpDocument::getInstance($app)->json($messages);
361 }
362
363 /**
364 * Starts a new chat session as guest.
365 * In case the user already started a session from this browser, the existing
366 * session will be returned instead.
367 *
368 * @return void
369 *
370 * @since 1.8.8
371 */
372 public function start_session()
373 {
374 $app = JFactory::getApplication();
375
376 try {
377 if (!JSession::checkToken()) {
378 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
379 }
380
381 $sessionModel = new VBOChatSessionModel;
382
383 // get session from cookie
384 $session = $sessionModel->getFromCookie();
385
386 $sessionId = $session->id ?? null;
387
388 // check whether a session was already started for this user
389 if (!$sessionId)
390 {
391 $data = [];
392 $data['name'] = $app->input->getString('name');
393 $data['email'] = $app->input->getString('email');
394
395 // start a new session
396 $sessionId = $sessionModel->save($data);
397 }
398
399 // validate session ID one more time
400 if (!$sessionId) {
401 throw new RuntimeException('Failed starting a new session', 400);
402 }
403 } catch (Exception $error) {
404 VBOHttpDocument::getInstance($app)->close($error->getCode() ?: 500, $error->getMessage());
405 }
406
407 // send session ID to the caller
408 VBOHttpDocument::getInstance($app)->json(['id' => $sessionId]);
409 }
410
411 /**
412 * Ends an existing session as guest.
413 * It is possible to immediately start a new session after closing the existing one.
414 *
415 * @return void
416 *
417 * @since 1.8.8
418 */
419 public function end_session()
420 {
421 $app = JFactory::getApplication();
422
423 try {
424 if (!JSession::checkToken()) {
425 throw new Exception(JText::translate('JINVALID_TOKEN'), 403);
426 }
427
428 $sessionModel = new VBOChatSessionModel;
429
430 // load existing session first
431 $session = $sessionModel->getFromCookie();
432
433 if (!$session) {
434 throw new Exception('Session not started yet.', 400);
435 }
436
437 if ($session->metadata['banned'] ?? false) {
438 throw new Exception('You cannot close and start a new session because you have been banned.', 403);
439 }
440
441 /** @var VBOChatMediator */
442 $chat = VBOFactory::getChatMediator();
443
444 // make sure the user is allowed to end the session
445 if (!$chat->getUser()->can('chat.session.end', new VBOChatContextSession($session->id))) {
446 // not authorized
447 throw new RuntimeException(JText::translate('JERROR_ALERTNOAUTHOR'), 403);
448 }
449
450 // close session
451 $sessionModel->endSession();
452
453 $sessionId = 0;
454
455 // check if we should restart a new one
456 if ($app->input->getBool('restart')) {
457 // start a new session
458 $sessionId = $sessionModel->save([
459 'name' => $session->name,
460 'email' => $session->email,
461 ]);
462 }
463 } catch (Exception $error) {
464 VBOHttpDocument::getInstance($app)->close($error->getCode() ?: 500, $error->getMessage());
465 }
466
467 // send session ID to the caller
468 VBOHttpDocument::getInstance($app)->json(['id' => $sessionId]);
469 }
470 }
471