Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
ImportSendingService.php
1<?php
2
3namespace Bitrix\Im\V2\Import;
4
5use Bitrix\Disk\File;
13
15{
16 private array $chat;
17 private ?DateTime $lastDateCreate;
18
19 public function __construct(array $chat)
20 {
21 $this->chat = $chat;
22 }
23
24 public function addMessages(array $messages): Result
25 {
26 $resultArray = [
27 'SUCCESS_RESULT' => [],
28 'ERROR_RESULT' => [],
29 ];
30
31 $messages = $this->fillFiles($messages);
32
33 $addedFiles = [];
34 foreach ($messages as $index => $message)
35 {
36 $externalId = $message['externalId'] === '' ? $index : $message['externalId'];
37 $addResult = $this->addMessage($message);
38 if (!$addResult->isSuccess())
39 {
40 $sendStubResult = $this->sendStubMessage($message);
41 if (!$sendStubResult->isSuccess())
42 {
43 return $sendStubResult;
44 }
45 $error = $addResult->getErrors()[0];
46 $resultArray['ERROR_RESULT'][] = [
47 'ID' => $sendStubResult->getResult(),
48 'EXTERNAL_ID' => $externalId,
49 'ERROR_CODE' => $error->getCode(),
50 'ERROR_MESSAGE' => $error->getMessage(),
51 ];
52 }
53 else
54 {
55 $resultArray['SUCCESS_RESULT'][] = [
56 'ID' => $addResult->getResult()['ID'],
57 'EXTERNAL_ID' => $externalId,
58 ];
59 $this->lastDateCreate = $this->getDateTimeFromAtom($message['dateCreate']);
60 if (isset($message['fileId']))
61 {
62 $addedFiles[] = (int)$message['fileId'];
63 }
64 }
65 }
66 $this->increaseFilesVersion($addedFiles);
67
68 return (new Result())->setResult($resultArray);
69 }
70
71 public function updateMessages(array $messages): Result
72 {
73 $result = new Result();
74 $resultArray = [
75 'SUCCESS_RESULT' => [],
76 'ERROR_RESULT' => [],
77 ];
78
79 $ids = array_column($messages, 'id');
80 $chatIds = $this->getChatIdsByMessageIds($ids);
81 $messages = $this->fillFiles($messages);
82
83 $addedFiles = [];
84 foreach ($messages as $message)
85 {
86 $message['chatId'] = $chatIds[(int)$message['id']] ?? null;
87 $updateResult = $this->updateMessage($message);
88 if (!$updateResult->isSuccess())
89 {
90 $error = $updateResult->getErrors()[0];
91 $resultArray['ERROR_RESULT'][] = [
92 'ID' =>(int)$message['id'],
93 'ERROR_CODE' => $error->getCode(),
94 'ERROR_MESSAGE' => $error->getMessage(),
95 ];
96 }
97 else
98 {
99 $resultArray['SUCCESS_RESULT'][] = $updateResult->getResult();
100 if (isset($message['fileId']))
101 {
102 $addedFiles[] = (int)$message['fileId'];
103 }
104 }
105 }
106 $this->increaseFilesVersion($addedFiles);
107
108 return $result->setResult($resultArray);
109 }
110
111 private function fillFiles(array $messages): array
112 {
113 $files = $this->getFiles($messages);
114
115 foreach ($messages as $index => $message)
116 {
117 if (isset($message['fileId']))
118 {
119 $messages[$index]['file'] = $files[(int)$message['fileId']] ?? null;
120 }
121 }
122
123 return $messages;
124 }
125
126 private function getFiles(array $messages): array
127 {
128 $fileIds = [];
129
130 foreach ($messages as $message)
131 {
132 if (isset($message['fileId']) && (int)$message['fileId'] > 0)
133 {
134 $fileIds[] = (int)$message['fileId'];
135 }
136 }
137
138 if (empty($fileIds))
139 {
140 return [];
141 }
142
143 $files = File::getModelList(['filter' => ['ID' => $fileIds]]);
144 $filesById = [];
145
146 foreach ($files as $file)
147 {
148 $filesById[$file->getId()] = $file;
149 }
150
151 return $filesById;
152 }
153
154 private function increaseFilesVersion(array $files): void
155 {
156 if (empty($files))
157 {
158 return;
159 }
160
161 $implodeFileId = implode(',', $files);
162 $sql = "UPDATE b_disk_object SET GLOBAL_CONTENT_VERSION=2 WHERE ID IN ({$implodeFileId})";
163 Application::getConnection()->query($sql);
164 }
165
166 private function addMessage(array $message): Result
167 {
168 $result = new Result();
169
170 $validateResult = $this->validateFields($message);
171 if (!$validateResult->isSuccess())
172 {
173 return $validateResult;
174 }
175 $message = $validateResult->getResult();
176 $messageFieldsResult = $this->getMessageFields($message);
177 $messageId = \CIMMessenger::Add($messageFieldsResult);
178
179 if ($messageId === false)
180 {
181 return $result->addError($this->getErrorLegacy());
182 }
183
184 return $result->setResult(['ID' => $messageId]);
185 }
186
187 private function checkFileAccess(array $message): Result
188 {
189 $result = new Result();
190
191 if (!isset($message['file']))
192 {
193 return $result->addError(new ImportError(ImportError::FILE_NOT_FOUND));
194 }
195 if ((int)$message['file']->getParentId() !== (int)$this->chat['DISK_FOLDER_ID'])
196 {
197 return $result->addError(new ImportError(ImportError::FILE_ACCESS_ERROR));
198 }
199
200 return $result;
201 }
202
203 private function updateMessage(array $message): Result
204 {
205 $result = new Result();
206 $id = (int)$message['id'];
207 if ((int)$this->chat['ID'] !== $message['chatId'])
208 {
209 return $result->addError(new MessageError(MessageError::MESSAGE_NOT_FOUND));
210 }
211
212 $validateResult = $this->validateParams($message);
213
214 if (!$validateResult->isSuccess())
215 {
216 return $validateResult;
217 }
218
219 $params = $validateResult->getResult();
220
221 if (!empty($params))
222 {
223 \CIMMessageParam::Set($id, $params);
224 }
225
226 if (isset($message['message']))
227 {
228 $urlPreview = !(isset($message['urlPreview']) && $message['urlPreview'] === "N");
229 $isSuccessUpdate = \CIMMessenger::Update($id, $message['message'], $urlPreview, false, null, false, true);
230 if (!$isSuccessUpdate)
231 {
232 return $result->addError(new ImportError(ImportError::UPDATE_MESSAGE_ERROR));
233 }
234 }
235
236 return $result->setResult(['ID' => $id]);
237 }
238
239 private function getErrorLegacy(): Error
240 {
241 global $APPLICATION;
242 $error = $APPLICATION->GetException();
243 if ($error instanceof \CAdminException)
244 {
245 $errorCode = $error->messages[0]['id'] ?? ImportError::ADD_MESSAGE_ERROR;
246 $errorMessage = $error->messages[0]['text'] ?? '';
247 }
248 else
249 {
250 $errorCode = $error->GetID();
251 $errorMessage = $error->GetString();
252 }
253
254 return new Error($errorCode, $errorMessage);
255 }
256
257 private function getChatIdsByMessageIds(array $messageIds): array
258 {
259 $result = [];
260 if (empty($messageIds))
261 {
262 return [];
263 }
264
265 $messages = MessageTable::query()
266 ->setSelect(['ID', 'CHAT_ID'])
267 ->whereIn('ID', $messageIds)
268 ->fetchCollection()
269 ;
270
271 foreach ($messages as $message)
272 {
273 $result[$message->getId()] = $message->getChatId();
274 }
275
276 return $result;
277 }
278
279 private function sendStubMessage(array $originalMessage): Result
280 {
281 $result = new Result();
282 $chatId = (int)$this->chat['ID'];
283 $originalDate = $this->getDateTimeFromAtom($originalMessage['dateCreate']);
284 if (isset($originalDate) && !$this->hasDateError())
285 {
286 $date = $originalDate;
287 }
288 else
289 {
290 $date = $this->getLastDateCreate();
291 }
292
293 if (!isset($date))
294 {
295 return $result->addError(new ImportError(ImportError::DATETIME_FORMAT_ERROR_FIRST));
296 }
297
298 $messageId = \CIMMessenger::Add([
299 'MESSAGE' => Loc::getMessage('IM_IMPORT_BROKEN_MESSAGE'),
300 'MESSAGE_DATE' => $date->toString(),
301 'FROM_USER_ID' => $originalMessage['authorId'] ?? 0,
302 'TO_CHAT_ID' => $chatId,
303 'MESSAGE_TYPE' => $this->chat['MESSAGE_TYPE'],
304 'SYSTEM' => $originalMessage['system'],
305 'URL_PREVIEW' => 'N',
306 'PUSH' => 'N',
307 'RECENT_ADD' => 'N',
308 'SKIP_COMMAND' => 'Y',
309 'SKIP_USER_CHECK' => 'Y',
310 'CONVERT' => 'Y'
311 ]);
312
313 return $result->setResult($messageId);
314 }
315
316 private function getLastDateCreate(): ?DateTime
317 {
318 if (isset($this->lastDateCreate))
319 {
320 return $this->lastDateCreate;
321 }
322
323 $result = MessageTable::query()
324 ->setSelect(['DATE_CREATE'])
325 ->where('CHAT_ID', (int)$this->chat['ID'])
326 ->setOrder(['DATE_CREATE' => 'DESC'])
327 ->setLimit(1)
328 ->fetch()
329 ;
330
331 $this->lastDateCreate = $result ? $result['DATE_CREATE'] : null;
332
333 return $this->lastDateCreate;
334 }
335
336 private function hasDateError(): bool
337 {
338 global $APPLICATION;
339 $error = $APPLICATION->GetException();
340 if ($error === false)
341 {
342 return false;
343 }
344 if ($error instanceof \CAdminException)
345 {
346 foreach ($error->messages as $message)
347 {
348 if ($message['id'] ?? '' === 'MESSAGE_DATE')
349 {
350 return true;
351 }
352 }
353 }
354 else
355 {
356 return $error->GetID() === 'MESSAGE_DATE';
357 }
358
359 return false;
360 }
361
362 private function validateFields(array $message): Result
363 {
364 $result = new Result();
365 $dateCreate = $this->getDateTimeFromAtom($message['dateCreate']);
366 if (!isset($dateCreate))
367 {
368 return $result->addError(new ImportError(ImportError::DATETIME_FORMAT_ERROR));
369 }
370 if ($this->getLastDateCreate() !== null && $dateCreate->getTimestamp() < $this->getLastDateCreate()->getTimestamp())
371 {
372 return $result->addError(new ImportError(ImportError::CHRONOLOGY_ERROR));
373 }
374 $validateParams = $this->validateParams($message);
375 if (!$validateParams->isSuccess())
376 {
377 return $validateParams;
378 }
379 $params = $validateParams->getResult();
380
381 $message['dateCreate'] = $dateCreate->toString();
382 $message['keyboard'] = $params['KEYBOARD'] ?? null;
383 $message['menu'] = $params['MENU'] ?? null;
384 $message['attach'] = $params['ATTACH'] ?? null;
385 $message['fileId'] = $params['FILE_ID'] ?? null;
386
387 return $result->setResult($message);
388 }
389
390 private function validateParams(array $message): Result
391 {
392 $params = [];
394 $results = [
395 'FILE_ID' => $this->getFileIdParams($message),
396 'KEYBOARD' => $this->getKeyboard($message),
397 'MENU' => $this->getMenu($message),
398 'ATTACH' => $this->getAttach($message)
399 ];
400
401 foreach ($results as $paramName => $result)
402 {
403 if (!$result->isSuccess())
404 {
405 return $result;
406 }
407 if ($result->getResult() !== null)
408 {
409 $params[$paramName] = $result->getResult();
410 }
411 }
412
413 return (new Result())->setResult($params);
414 }
415
416 private function getMessageFields(array $message): array
417 {
418 return [
419 'MESSAGE' => $message['message'],
420 'MESSAGE_DATE' => $message['dateCreate'],
421 'FROM_USER_ID' => (int)$message['authorId'],
422 'TO_CHAT_ID' => (int)$this->chat['ID'],
423 'MESSAGE_TYPE' => $this->chat['MESSAGE_TYPE'],
424 'SYSTEM' => $message['system'],
425 'ATTACH' => $message['attach'],
426 'KEYBOARD' => $message['keyboard'],
427 'MENU' => $message['menu'],
428 'URL_PREVIEW' => 'N',
429 'FILES' => $message['fileId'],
430 'PUSH' => 'N',
431 'RECENT_ADD' => 'N',
432 'SKIP_COMMAND' => 'Y',
433 'SKIP_USER_CHECK' => 'Y',
434 'CONVERT' => 'Y'
435 ];
436 }
437
438 private function getDateTimeFromAtom(string $dateAtom): ?DateTime
439 {
440 return DateTime::tryParse($dateAtom, \DateTimeInterface::RFC3339);
441 }
442
443 private function getFileIdParams(array $message): Result
444 {
445 $result = new Result();
446 $fileId = null;
447 if (isset($message['fileId']))
448 {
449 $fileId = [];
450 if ($message['fileId'] === 'N')
451 {
452 return $result->setResult([]);
453 }
454 $fileCheckResult = $this->checkFileAccess($message);
455 if (!$fileCheckResult->isSuccess())
456 {
457 return $fileCheckResult;
458 }
459 $fileId = [(int)$message['fileId']];
460 }
461
462 return $result->setResult($fileId);
463 }
464
465 private function getKeyboard(array $message): Result
466 {
467 $result = new Result();
468 $keyboard = null;
469 if (isset($message['keyboard']))
470 {
471 if ($message['keyboard'] === 'N')
472 {
473 return $result->setResult('N');
474 }
475 $keyboard = [];
476 if (!isset($message['keyboard']['BUTTONS']))
477 {
478 $keyboard['BUTTONS'] = $message['keyboard'];
479 }
480 else
481 {
482 $keyboard = $message['keyboard'];
483 }
484 $keyboard['BOT_ID'] = $message['botId'];
485 $keyboard = \Bitrix\Im\Bot\Keyboard::getKeyboardByJson($keyboard);
486 if (!isset($keyboard))
487 {
488 return $result->addError(new ImportError('KEYBOARD_ERROR', 'Incorrect keyboard params'));
489 }
490 if (!$keyboard->isAllowSize())
491 {
492 return $result->addError(new ImportError('KEYBOARD_OVERSIZE', 'You have exceeded the maximum allowable size of keyboard'));
493 }
494 }
495
496 return $result->setResult($keyboard);
497 }
498
499 private function getMenu(array $message): Result
500 {
501 $result = new Result();
502 $menu = null;
503 if (isset($message['menu']))
504 {
505 if ($message['menu'] === 'N')
506 {
507 return $result->setResult('N');
508 }
509 $menu = [];
510 if (!isset($message['menu']['ITEMS']))
511 {
512 $menu['ITEMS'] = $message['menu'];
513 }
514 else
515 {
516 $menu = $message['menu'];
517 }
518 $menu['BOT_ID'] = $message['botId'];
519 $menu = \Bitrix\Im\Bot\ContextMenu::getByJson($menu);
520 if (!isset($menu))
521 {
522 return $result->addError(new ImportError('MENU_ERROR', 'Incorrect menu params'));
523 }
524 if (!$menu->isAllowSize())
525 {
526 return $result->addError(new ImportError('MENU_OVERSIZE', 'You have exceeded the maximum allowable size of menu'));
527 }
528 }
529
530 return $result->setResult($menu);
531 }
532
533 private function getAttach(array $message): Result
534 {
535 $result = new Result();
536 $attach = null;
537 if (isset($message['attach']))
538 {
539 if ($message['attach'] === 'N')
540 {
541 return $result->setResult('N');
542 }
543 $attach = \CIMMessageParamAttach::GetAttachByJson($message['attach']);
544 if (!isset($attach))
545 {
546 return $result->addError(new ImportError('ATTACH_ERROR', 'Incorrect attach params'));
547 }
548 if (!$attach->IsAllowSize())
549 {
550 return $result->addError(new ImportError('ATTACH_OVERSIZE', 'You have exceeded the maximum allowable size of attach'));
551 }
552 }
553
554 return $result->setResult($attach);
555 }
556}
static getConnection($name="")
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29
static tryParse($timeString, $format=null)
Definition datetime.php:260