Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
botprovider.php
1<?php
3
10use Bitrix\Main\EO_User;
11use Bitrix\Main\EO_User_Collection;
22
24{
25 public function __construct(array $options = [])
26 {
27 parent::__construct();
28
29 if (isset($options['searchableBotTypes']) && is_array($options['searchableBotTypes']))
30 {
31 $this->options['searchableBotTypes'] = $options['searchableBotTypes'];
32 }
33
34 $this->options['fillDialog'] = true;
35 if (isset($options['fillDialog']) && is_bool($options['fillDialog']))
36 {
37 $this->options['fillDialog'] = $options['fillDialog'];
38 }
39
40 $this->options['fillDialogWithDefaultValues'] = true;
41 if (isset($options['fillDialogWithDefaultValues']) && is_bool($options['fillDialogWithDefaultValues']))
42 {
43 $this->options['fillDialogWithDefaultValues'] = $options['fillDialogWithDefaultValues'];
44 }
45 }
46
47 public function isAvailable(): bool
48 {
49 return $GLOBALS['USER']->isAuthorized() && !User::getInstance()->isExtranet();
50 }
51
52 public function doSearch(SearchQuery $searchQuery, Dialog $dialog): void
53 {
54 $limit = 100;
55
56 $items = $this->getBotItems([
57 'searchQuery' => $searchQuery->getQuery(),
58 'limit' => $limit
59 ]);
60
61 $items = $this->filterHiddenBots($items);
62
63 $limitExceeded = $limit <= count($items);
64 if ($limitExceeded)
65 {
66 $searchQuery->setCacheable(false);
67 }
68
69 $dialog->addItems($items);
70 }
71
72 private function filterHiddenBots(array $items): array
73 {
74 foreach ($items as $key => $item)
75 {
76 $user = \Bitrix\Im\V2\Entity\User\User::getInstance((int)$item->getId());
77 if ($user instanceof UserBot && $user->isBot())
78 {
79 $botData = $user->getBotData()->toRestFormat();
80
81 if ($botData['isHidden'])
82 {
83 unset($items[$key]);
84 }
85 }
86 }
87
88 return $items;
89 }
90
91 public function shouldFillDialog(): bool
92 {
93 return $this->getOption('fillDialog', true);
94 }
95
96 public function getItems(array $ids): array
97 {
98 if (!$this->shouldFillDialog())
99 {
100 return [];
101 }
102
103 return $this->getBotItems([
104 'userId' => $ids,
105 ]);
106 }
107
108 public function getSelectedItems(array $ids): array
109 {
110 return $this->getItems($ids);
111 }
112
113 public function getBotItems(array $options = []): array
114 {
115 return $this->makeBotItems($this->getBotCollection($options), $options);
116 }
117
118 public function makeBotItems(EO_User_Collection $bots, array $options = []): array
119 {
120 return self::makeItems($bots, array_merge($this->getOptions(), $options));
121 }
122
123 public function getBotCollection(array $options = []): EO_User_Collection
124 {
125 $options = array_merge($this->getOptions(), $options);
126
127 return self::getBots($options);
128 }
129
130 public static function getBots(array $options = []): EO_User_Collection
131 {
132 $query = UserTable::query();
133
134 $query->setSelect([
135 'ID',
136 'NAME',
137 'LAST_NAME',
138 'SECOND_NAME',
139 'PERSONAL_PHOTO',
140 'WORK_POSITION',
141 'BOT_TYPE' => 'im_bot.TYPE',
142 'BOT_COUNT_MESSAGE' => 'im_bot.COUNT_MESSAGE',
143 ]);
144
145 $query->registerRuntimeField(
146 new Reference(
147 'im_bot',
148 BotTable::class,
149 Join::on('this.ID', 'ref.BOT_ID'),
150 ['join_type' => Join::TYPE_INNER]
151 )
152 );
153
154 if (!empty($options['searchQuery']) && is_string($options['searchQuery']))
155 {
156 $query->registerRuntimeField(
157 new Reference(
158 'USER_INDEX',
159 \Bitrix\Main\UserIndexTable::class,
160 Join::on('this.ID', 'ref.USER_ID'),
161 ['join_type' => 'INNER']
162 )
163 );
164
165 $query->whereMatch(
166 'USER_INDEX.SEARCH_USER_CONTENT',
167 Filter\Helper::matchAgainstWildcard(
168 Content::prepareStringToken($options['searchQuery']), '*', 1
169 )
170 );
171 }
172
173 if (isset($options['searchableBotTypes']) && is_array($options['searchableBotTypes']))
174 {
175 $query->whereIn('BOT_TYPE', $options['searchableBotTypes']);
176 }
177
178 $userIds = [];
179 $userFilter = isset($options['userId']) ? 'userId' : (isset($options['!userId']) ? '!userId' : null);
180 if (isset($options[$userFilter]))
181 {
182 if (is_array($options[$userFilter]) && !empty($options[$userFilter]))
183 {
184 foreach ($options[$userFilter] as $id)
185 {
186 $id = (int)$id;
187 if ($id > 0)
188 {
189 $userIds[] = $id;
190 }
191 }
192
193 $userIds = array_unique($userIds);
194
195 if (!empty($userIds))
196 {
197 if ($userFilter === 'userId')
198 {
199 $query->whereIn('ID', $userIds);
200 }
201 else
202 {
203 $query->whereNotIn('ID', $userIds);
204 }
205 }
206 }
207 else if (!is_array($options[$userFilter]) && (int)$options[$userFilter] > 0)
208 {
209 if ($userFilter === 'userId')
210 {
211 $query->where('ID', (int)$options[$userFilter]);
212 }
213 else
214 {
215 $query->whereNot('ID', (int)$options[$userFilter]);
216 }
217 }
218 }
219
220 if (isset($options['limit']) && is_int($options['limit']))
221 {
222 $query->setLimit($options['limit']);
223 }
224 else
225 {
226 $query->setLimit(100);
227 }
228
229 if (!empty($options['order']) && is_array($options['order']))
230 {
231 $query->setOrder($options['order']);
232 }
233 else
234 {
235 $query->setOrder([
236 'BOT_COUNT_MESSAGE' => 'DESC'
237 ]);
238 }
239
240 $result = $query->exec();
241
242 return $result->fetchCollection();
243 }
244
245 public static function makeItems(EO_User_Collection $bots, array $options = []): array
246 {
247 $result = [];
248 $isBitrix24 = ModuleManager::isModuleInstalled('bitrix24');
249
250 foreach ($bots as $bot)
251 {
252 $botData = Bot::getCache($bot->getId());
253 if (
254 $isBitrix24
255 && $botData['TYPE'] === Bot::TYPE_NETWORK
256 && $botData['CLASS'] === 'Bitrix\ImBot\Bot\Support24'
257 )
258 {
259 continue;
260 }
261
262 $result[] = self::makeItem($bot, $options);
263 }
264
265 return $result;
266 }
267
268 public static function makeItem(EO_User $bot, array $options = []): Item
269 {
270 $defaultIcon =
271 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2228%22%20'
272 . 'height%3D%2228%22%20viewBox%3D%220%200%2028%2028%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20'
273 . 'fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Ccircle%20cx%3D%2214%22%20cy%3D%2214%22%20r%3D%2214%22%20'
274 . 'fill%3D%22%232FC6F6%22%2F%3E%0A%20%20%20%20%3Cpath%20'
275 . 'fill%3D%22%23FFFFFF%22%20d%3D%22M19.053132%2C10.0133936%20L19.9184066%2C7.09247624%20C19'
276 . '.9937984%2C6.83851954%2019.930205%2C6.56296095%2019.7515811%2C6.36960075%20C19.5729573%2C6'
277 . '.17624054%2019.3064404%2C6.09445472%2019.0524247%2C6.15505122%20C18.798409%2C6.21564772%2018'
278 . '.5954856%2C6.40942049%2018.5200937%2C6.66337719%20L17.7789513%2C9.17078557%20C15.4748028%2C7'
279 . '.94807693%2012.7275787%2C7.95098931%2010.4259431%2C9.17858062%20L9.68114981%2C6.66337719%20C9'
280 . '.56460406%2C6.27079414%209.15710205%2C6.04859979%208.77096861%2C6.16709222%20C8.38483517%2C6'
281 . '.28558465%208.16629117%2C6.69989319%208.28283693%2C7.09247624%20L9.15176243%2C10.0249005%20C7'
282 . '.2004503%2C11.6106349%206.0672511%2C14.0147948%206.0740137%2C16.5545557%20C6.0740137%2C21.1380463%209'
283 . '.67019697%2C20.0133316%2014.1097491%2C20.0133316%20C18.5493013%2C20.0133316%2022.1454845%2C21'
284 . '.1380463%2022.1454845%2C16.5545557%20C22.1533008%2C14.0079881%2021.0139427%2C11.5979375%2019'
285 . '.053132%2C10.0133936%20Z%20M14.1024472%2C15.9316939%20C10.9334248%2C15.9316939%208.36315777%2C16'
286 . '.2657676%208.36315777%2C14.9001487%20C8.36315777%2C13.5345299%2010.9334248%2C12.4257765%2014'
287 . '.1024472%2C12.4257765%20C17.2714696%2C12.4257765%2019.8453876%2C13.5334163%2019.8453876%2C14'
288 . '.9001487%20C19.8453876%2C16.2668812%2017.2751206%2C15.9316939%2014.1024472%2C15.9316939%20Z%20M11'
289 . '.477416%2C13.4487843%20C11.0249669%2C13.5328062%2010.7150974%2C13.9604811%2010.7703097%2C14'
290 . '.4247164%20C10.825522%2C14.8889517%2011.2267231%2C15.229209%2011.6858298%2C15.201166%20C12'
291 . '.1449365%2C15.1731231%2012.5031841%2C14.7864774%2012.5033322%2C14.3188606%20C12.4520761%2C13'
292 . '.7928552%2011.9955831%2C13.4057049%2011.477416%2C13.4487843%20Z%20M16.0191544%2C14.4269902%20C16'
293 . '.0754002%2C14.8911461%2016.4771659%2C15.230674%2016.9362856%2C15.2020479%20C17.3954053%2C15'
294 . '.1734219%2017.7533545%2C14.7865259%2017.7533947%2C14.3188606%20C17.7021533%2C13.7912874%2017'
295 . '.2433569%2C13.4035634%2016.7238275%2C13.4487843%20C16.2716033%2C13.5343137%2015.9629087%2C13'
296 . '.9628342%2016.0191544%2C14.4269902%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A'
297 ;
298
299 $imBot = Bot::getCache($bot->getId());
300 $customData = [
301 'imUser' => User::getInstance($bot->getId())->getArray(),
302 'imBot' => [
303 'APP_ID' => $imBot['APP_ID'] ?? null,
304 'BOT_ID' => $imBot['BOT_ID'] ?? null,
305 'CODE' => $imBot['CODE'] ?? null,
306 'HIDDEN' => $imBot['HIDDEN'] ?? null,
307 'LANG' => $imBot['LANG'] ?? null,
308 'MODULE_ID' => $imBot['MODULE_ID'] ?? null,
309 'OPENLINE' => $imBot['OPENLINE'] ?? null,
310 'TYPE' => $imBot['TYPE'] ?? null,
311 'VERIFIED' => $imBot['VERIFIED'] ?? null,
312 ],
313 ];
314
315 if ($bot->getId() !== null)
316 {
317 $botData = BotData::getInstance($bot->getId())->toRestFormat();
318 }
319
320 $customData['imUser']['BOT_DATA'] = (!empty($botData)) ? $botData : null;
321
322 $avatar = Helper\User::makeAvatar($bot);
323 if (!$avatar)
324 {
325 if ($customData['imUser']['COLOR'] !== '')
326 {
327 $avatar = str_replace(
328 '2FC6F6',
329 explode('#', $customData['imUser']['COLOR'])[1],
330 $defaultIcon
331 );
332 }
333 else
334 {
335 $avatar = $defaultIcon;
336 }
337 }
338
339 return new Item([
340 'id' => $bot->getId(),
341 'entityId' => 'im-bot',
342 'entityType' => Bot::getListForJs()[$bot->getId()]['type'],
343 'title' => Helper\User::formatName($bot, $options),
344 'avatar' => $avatar,
345 'customData' => $customData,
346 ]);
347 }
348
349 public function fillDialog(Dialog $dialog): void
350 {
351 if (!$this->shouldFillDialog())
352 {
353 return;
354 }
355
356 if (!$this->getOption('fillDialogWithDefaultValues', true))
357 {
358 $recentBots = new EO_User_Collection();
359 $recentItems = $dialog->getRecentItems()->getEntityItems('im-bot');
360 $recentIds = array_map('intval', array_keys($recentItems));
361 $this->fillRecentBots($recentBots, $recentIds, new EO_User_Collection());
362
363 $dialog->addRecentItems($this->makeBotItems($recentBots));
364
365 return;
366 }
367
368 $maxBotsInRecentTab = 50;
369
370 // Preload first 50 users ('doSearch' method has to have the same filter).
371 $preloadedBots = $this->getBotCollection([
372 'order' => ['ID' => 'DESC'],
373 'limit' => $maxBotsInRecentTab
374 ]);
375
376 if (count($preloadedBots) < $maxBotsInRecentTab)
377 {
378 // Turn off the user search
379 $entity = $dialog->getEntity('im-bot');
380 if ($entity)
381 {
382 $entity->setDynamicSearch(false);
383 }
384 }
385
386 $recentBots = new EO_User_Collection();
387
388 // Recent Items
389 $recentItems = $dialog->getRecentItems()->getEntityItems('im-bot');
390 $recentIds = array_map('intval', array_keys($recentItems));
391 $this->fillRecentBots($recentBots, $recentIds, $preloadedBots);
392
393 // Global Recent Items
394 if (count($recentBots) < $maxBotsInRecentTab)
395 {
396 $recentGlobalItems = $dialog->getGlobalRecentItems()->getEntityItems('im-bot');
397 $recentGlobalIds = [];
398
399 if (!empty($recentGlobalItems))
400 {
401 $recentGlobalIds = array_map('intval', array_keys($recentGlobalItems));
402 $recentGlobalIds = array_values(array_diff($recentGlobalIds, $recentBots->getIdList()));
403 $recentGlobalIds = array_slice($recentGlobalIds, 0, $maxBotsInRecentTab - $recentBots->count());
404 }
405
406 $this->fillRecentBots($recentBots, $recentGlobalIds, $preloadedBots);
407 }
408
409 // The rest of preloaded users
410 foreach ($preloadedBots as $preloadedBot)
411 {
412 $recentBots->add($preloadedBot);
413 }
414
415 $dialog->addRecentItems($this->makeBotItems($recentBots));
416 }
417
418 private function fillRecentBots(
419 EO_User_Collection $recentBots,
420 array $recentIds,
421 EO_User_Collection $preloadedBots
422 ): void
423 {
424 if (count($recentIds) < 1)
425 {
426 return;
427 }
428
429 $ids = array_values(array_diff($recentIds, $preloadedBots->getIdList()));
430
431 if (!empty($ids))
432 {
433 $bots = $this->getBotCollection([
434 'userId' => $ids,
435 ]);
436
437 foreach ($bots as $bot)
438 {
439 $preloadedBots->add($bot);
440 }
441 }
442
443 foreach ($recentIds as $recentId)
444 {
445 $bot = $preloadedBots->getByPrimary($recentId);
446 if ($bot)
447 {
448 $recentBots->add($bot);
449 }
450 }
451 }
452}
static getListForJs()
Definition bot.php:1360
const TYPE_NETWORK
Definition bot.php:25
static getCache($botId)
Definition bot.php:1311
makeBotItems(EO_User_Collection $bots, array $options=[])
static makeItems(EO_User_Collection $bots, array $options=[])
static makeItem(EO_User $bot, array $options=[])
doSearch(SearchQuery $searchQuery, Dialog $dialog)
static getInstance($userId=null)
Definition user.php:44
static isModuleInstalled($moduleName)
getOption(string $option, $defaultValue=null)
getEntity(string $entityId)
Definition dialog.php:277
$GLOBALS['____1444769544']
Definition license.php:1