1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
workgroup.php
См. документацию.
1<?php
2
3namespace Bitrix\Socialnetwork\Controller;
4
5use Bitrix\Intranet\Integration\Templates\Bitrix24\ThemePicker;
6use Bitrix\Intranet\Internals\ThemeTable;
7use Bitrix\Main\Context;
8use Bitrix\Main\Engine;
9use Bitrix\Main\Engine\Controller;
10use Bitrix\Main\Entity\Query;
11use Bitrix\Main\Error;
12use Bitrix\Main\Loader;
13use Bitrix\Main\Localization\Loc;
14use Bitrix\Main\ModuleManager;
15use Bitrix\Main\Type\DateTime;
16use Bitrix\Main\UI\PageNavigation;
17use Bitrix\Main\UserTable;
18use Bitrix\Socialnetwork\Collab\Integration\IM\Dialog;
19use Bitrix\Socialnetwork\EO_UserToGroup;
20use Bitrix\Socialnetwork\Helper;
21use Bitrix\Socialnetwork\Helper\AvatarManager;
22use Bitrix\Socialnetwork\Integration\Im\Chat;
23use Bitrix\Socialnetwork\Integration\Main\File;
24use Bitrix\Socialnetwork\Integration\Pull\PushService;
25use Bitrix\Socialnetwork\Internals\Counter;
26use Bitrix\Socialnetwork\Internals\Counter\CounterDictionary;
27use Bitrix\Socialnetwork\Internals\EventService\EventDictionary;
28use Bitrix\Socialnetwork\Internals\EventService\Push\PushEventDictionary;
29use Bitrix\Socialnetwork\Internals\EventService\Service;
30use Bitrix\Socialnetwork\Item\Subscription;
31use Bitrix\Socialnetwork\Item\WorkgroupFavorites;
32use Bitrix\Socialnetwork\Provider\GroupProvider;
33use Bitrix\Socialnetwork\Space\MembersManager;
34use Bitrix\Socialnetwork\Space\Toolbar\Switcher\Option\Pin;
35use Bitrix\Socialnetwork\UserToGroupTable;
36use Bitrix\Socialnetwork\WorkgroupPinTable;
37use Bitrix\Socialnetwork\WorkgroupSiteTable;
38use Bitrix\Socialnetwork\WorkgroupSubjectTable;
39use Bitrix\Socialnetwork\WorkgroupTable;
40use Bitrix\Socialnetwork\WorkgroupTagTable;
41use Bitrix\Tasks\Internals\Effective;
42use CExtranet;
43use Exception;
44
45class Workgroup extends Base
46{
47 private static function getAllowedSelectFields(): array
48 {
49 return [
50 'ID', 'ACTIVE', 'SUBJECT_ID', 'NAME', 'DESCRIPTION', 'KEYWORDS',
51 'CLOSED', 'VISIBLE', 'OPENED', 'PROJECT', 'LANDING',
52 'DATE_CREATE', 'DATE_UPDATE', 'DATE_ACTIVITY',
53 'IMAGE_ID', 'AVATAR_TYPE',
54 'OWNER_ID',
55 'NUMBER_OF_MEMBERS', 'NUMBER_OF_MODERATORS',
56 'INITIATE_PERMS',
57 'PROJECT_DATE_START', 'PROJECT_DATE_FINISH',
58 'SCRUM_OWNER_ID', 'SCRUM_MASTER_ID', 'SCRUM_SPRINT_DURATION', 'SCRUM_TASK_RESPONSIBLE',
59 'TYPE',
60 ];
61 }
62
63 public function getAction(array $params = []): ?array
64 {
65 $groupId = (int)($params['groupId'] ?? 0);
66
67 if ($groupId <= 0)
68 {
69 $this->addEmptyGroupIdError();
70 return null;
71 }
72
73 $select = (array)($params['select'] ?? []);
74 $filter = (array)($params['filter'] ?? []);
75 $filter['ID'] = $groupId;
76
77 if (!\CSocNetUser::isCurrentUserModuleAdmin(SITE_ID, false))
78 {
79 $filter['CHECK_PERMISSIONS'] = $this->getCurrentUser()->getId();
80 }
81
82 $result = \CSocNetGroup::getList([], $filter, false, false, ['ID']);
83 if ($group = $result->fetch())
84 {
85 $groupItem = \Bitrix\Socialnetwork\Item\Workgroup::getById($group['ID']);
86 $groupFields = $groupItem->getFields();
87
88 if (in_array('DATE_CREATE', $select, true))
89 {
90 $culture = Context::getCurrent()->getCulture();
91 $longDateFormat = $culture->getLongDateFormat();
92 $shortTimeFormat = $culture->getShortTimeFormat();
93
94 $groupFields['DATE_CREATE'] = \CComponentUtil::getDateTimeFormatted([
95 'TIMESTAMP' => MakeTimeStamp($groupFields['DATE_CREATE']),
96 'TZ_OFFSET' => \CTimeZone::getOffset(),
97 ], "$longDateFormat, $shortTimeFormat");
98 }
99 if (in_array('AVATAR', $select, true))
100 {
101 $groupFields['AVATAR'] = File::getFileSource((int)$groupFields['IMAGE_ID'], 100, 100);
102 }
103 if (in_array('AVATAR_TYPES', $select, true))
104 {
105 $groupFields['AVATAR_TYPES'] = Helper\Workgroup::getAvatarTypes();
106 }
107 if (in_array('AVATAR_DATA', $select, true))
108 {
109 $imageId = (int) $groupFields['IMAGE_ID'];
110 $avatarType = $groupFields['AVATAR_TYPE'] ?? '';
111 $groupFields['AVATAR_DATA'] = $this->getAvatarData($imageId, $avatarType);
112 }
113 if (in_array('OWNER_DATA', $select, true))
114 {
115 $groupFields['OWNER_DATA'] = $this->getOwnerData($groupFields['OWNER_ID']);
116 }
117 if (in_array('SUBJECT_DATA', $select, true))
118 {
119 $groupFields['SUBJECT_DATA'] = $this->getSubjectData($groupFields['SUBJECT_ID']);
120 }
121 if (in_array('TAGS', $select, true))
122 {
123 $groupFields['TAGS'] = $this->getTags($groupId);
124 }
125 if (in_array('THEME_DATA', $select, true))
126 {
127 $groupFields['THEME_DATA'] = $this->getThemeData($groupId);
128 }
129 if (in_array('ACTIONS', $select, true))
130 {
131 $groupFields['ACTIONS'] = $this->getActions($groupId);
132 }
133 if (in_array('USER_DATA', $select, true))
134 {
135 $groupFields['USER_DATA'] = $this->getUserData($groupId);
136 }
137 if (in_array('DEPARTMENTS', $select, true))
138 {
139 $groupFields['DEPARTMENTS'] = $this->getDepartments($groupFields['UF_SG_DEPT']['VALUE']);
140 }
141 if (in_array('PIN', $select, true))
142 {
143 $groupFields['IS_PIN'] = $this->isPin($groupId, $this->getCurrentUser()->getId());
144 }
145 if (in_array('PRIVACY_TYPE', $select, true))
146 {
147 $groupFields['PRIVACY_CODE'] = Helper\Workgroup::getConfidentialityTypeCodeByParams([
148 'fields' => [
149 'OPENED' => $groupFields['OPENED'],
150 'VISIBLE' => $groupFields['VISIBLE'],
151 ],
152 ]);
153 }
154 if (in_array('LIST_OF_MEMBERS', $select, true))
155 {
156 $groupFields['LIST_OF_MEMBERS'] = $this->getListOfMembers(
157 $groupId,
158 $groupItem->getScrumMaster()
159 );
160 }
161 if (in_array('FEATURES', $select, true))
162 {
163 $groupFields['FEATURES'] = $this->prepareFeatures($groupId);
164 }
165 $needListOfAwaiting = in_array('LIST_OF_MEMBERS_AWAITING_INVITE', $select, true);
166 $needMembersList = in_array('GROUP_MEMBERS_LIST', $select, true);
167 if ($needListOfAwaiting || $needMembersList)
168 {
169 $permissions = Helper\Workgroup::getPermissions(
170 ['groupId' => $groupId],
171 );
172 }
173 if ($needListOfAwaiting)
174 {
175 $groupFields['LIST_OF_MEMBERS_AWAITING_INVITE'] = [];
176 if ($permissions['UserCanModifyGroup'] || $permissions['UserCanInitiate'])
177 {
178 $groupFields['LIST_OF_MEMBERS_AWAITING_INVITE'] = $this->getListOfAwaitingMembers($groupId);
179 }
180 }
181 if ($needMembersList)
182 {
183 $groupFields['GROUP_MEMBERS_LIST'] = [];
184 if ($permissions['UserCanModifyGroup'] || $permissions['UserCanInitiate'])
185 {
186 $membersManager = new MembersManager();
187 $groupFields['GROUP_MEMBERS_LIST'] = $membersManager->getGroupMembersList($groupId);
188 }
189 }
190
191 if (in_array('COUNTERS', $select, true))
192 {
193 $groupFields['COUNTERS'] = $this->getCounters($groupId);
194 }
195
196 if ($groupFields['NUMBER_OF_MEMBERS'])
197 {
198 $groupFields['NUMBER_OF_MEMBERS_PLURAL'] = Loc::getPluralForm($groupFields['NUMBER_OF_MEMBERS']);
199 }
200 if ($groupFields['PROJECT_DATE_START'] || $groupFields['PROJECT_DATE_FINISH'])
201 {
202 $culture = Context::getCurrent()->getCulture();
203 $format = $culture->getDayMonthFormat();
204
206 $dateStart = $groupFields['PROJECT_DATE_START'];
208 $dateFinish = $groupFields['PROJECT_DATE_FINISH'];
209
210 if ($dateStart)
211 {
212 $groupFields['FORMATTED_PROJECT_DATE_START'] = FormatDate(
213 $format,
214 MakeTimeStamp(DateTime::createFromTimestamp($dateStart->getTimestamp()))
215 );
216 }
217 if ($dateFinish)
218 {
219 $groupFields['FORMATTED_PROJECT_DATE_FINISH'] = FormatDate(
220 $format,
221 MakeTimeStamp(DateTime::createFromTimestamp($dateFinish->getTimestamp()))
222 );
223 }
224 }
225
226 if (
227 isset($params['mode'])
228 && $params['mode'] === 'mobile'
229 )
230 {
231 $additionalData = Helper\Workgroup::getAdditionalData([
232 'ids' => [ $groupId ],
233 'features' => ($params['features'] ?? []),
234 'mandatoryFeatures' => ($params['mandatoryFeatures'] ?? []),
235 'currentUserId' => (int)$this->getCurrentUser()->getId(),
236 ]);
237
238 $groupFields['ADDITIONAL_DATA'] = ($additionalData[$groupId] ?? []) ;
239 }
240
241 $isScrum = !empty($groupFields['SCRUM_MASTER_ID']);
242 if (!$isScrum && in_array('EFFICIENCY', $select, true) && Loader::includeModule('tasks'))
243 {
244 $efficiencies = Effective::getAverageEfficiencyForGroups(
245 null,
246 null,
247 0,
248 [$group['ID']],
249 );
250
251 $groupFields['EFFICIENCY'] = $efficiencies[$group['ID']] ?? null;
252 }
253
254 return $groupFields;
255 }
256
257 $this->addError(
258 new Error(
259 Loc::getMessage('SONET_CONTROLLER_WORKGROUP_NOT_FOUND'),
260 'SONET_CONTROLLER_WORKGROUP_NOT_FOUND'
261 )
262 );
263
264 return null;
265 }
266
267 public function listAction(
268 PageNavigation $pageNavigation,
269 array $filter = [],
270 array $select = [],
271 array $order = [],
272 array $params = []
273 )
274 {
275 if (
276 empty($select)
277 || !is_array($select)
278 )
279 {
280 $select = [ 'ID' ];
281 }
282
283 if (!in_array('ID', $select, true))
284 {
285 $select[] = 'ID';
286 }
287
288 $originalSelect = $select;
289
290 if (
291 $params['IS_ADMIN'] === 'Y'
292 && !\CSocNetUser::isCurrentUserModuleAdmin(SITE_ID, false)
293 )
294 {
295 unset($params['IS_ADMIN']);
296 }
297
298 if ($params['IS_ADMIN'] !== 'Y')
299 {
300 $filter['CHECK_PERMISSIONS'] = $this->getCurrentUser()->getId();
301 }
302
304
305 if (
306 $extranetSiteId
307 && $params['IS_ADMIN'] !== 'Y'
309 )
310 {
311 $filter['SITE_ID'] = $extranetSiteId;
312 }
313 else
314 {
315 $filter['SITE_ID'] = (string)($params['siteId'] ?? SITE_ID);
316 }
317
318 if (($key = array_search('AVATAR', $select, true)) !== false)
319 {
320 $select[] = 'IMAGE_ID';
321 $select[] = 'AVATAR_TYPE';
322 unset($select[$key]);
323 }
324
325 $workgroups = [];
326 $count = 0;
327
328 $queryIdFilter = [];
329
330 $res = \CSocNetGroup::getList([], $filter, false, false, [ 'ID' ]);
331 while ($groupFields = $res->fetch())
332 {
333 $queryIdFilter[] = (int)$groupFields['ID'];
334 }
335
336 if (!empty($queryIdFilter))
337 {
338 $select = $this->prepareSelect($select);
339
340 $query = WorkgroupTable::query();
341 $query
342 ->setSelect($select)
343 ->setOrder($order)
344 ->setOffset($pageNavigation->getOffset())
345 ->setLimit(($pageNavigation->getLimit()))
346 ->setFilter([
347 'ID' => $queryIdFilter,
348 ])
349 ->countTotal(true);
350
351 $res = $query->exec();
352
353 $avatarTypes = Helper\Workgroup::getAvatarTypes();
354
355 while ($groupFields = $res->fetch())
356 {
357 if (in_array('AVATAR', $originalSelect, true))
358 {
359 if ((int)$groupFields['IMAGE_ID'] > 0)
360 {
361 $groupFields['AVATAR'] = File::getFileSource((int)$groupFields['IMAGE_ID'], 100, 100);
362 }
363 elseif (
364 !empty($groupFields['AVATAR_TYPE'])
365 && isset($params['mode'])
366 && $params['mode'] === 'mobile'
367 )
368 {
369 $groupFields['AVATAR'] = $avatarTypes[$groupFields['AVATAR_TYPE']]['mobileUrl'];
370 }
371 else
372 {
373 $groupFields['AVATAR'] = '';
374 }
375 }
376
377 $workgroups[(int)$groupFields['ID']] = $groupFields;
378 }
379
380 $count = $res->getCount();
381 }
382
383 $ids = array_keys($workgroups);
384
385 if (
386 isset($params['mode'])
387 && $params['mode'] === 'mobile'
388 )
389 {
390 $additionalData = Helper\Workgroup::getAdditionalData([
391 'ids' => $ids,
392 'features' => ($params['features'] ?? []),
393 'mandatoryFeatures' => ($params['mandatoryFeatures'] ?? []),
394 'currentUserId' => (int)$this->getCurrentUser()->getId(),
395 ]);
396
397 foreach (array_keys($workgroups) as $id)
398 {
399 if (!isset($additionalData[$id]))
400 {
401 continue;
402 }
403
404 $workgroups[$id]['ADDITIONAL_DATA'] = ($additionalData[$id] ?? []) ;
405 }
406 }
407
408 if (($params['shouldSelectDialogId'] ?? 'N') === 'Y')
409 {
410 $chatData = Chat\Workgroup::getChatData([
411 'group_id' => $ids,
412 'skipAvailabilityCheck' => true,
413 ]);
414
415 foreach ($workgroups as $id => $fields)
416 {
417 $workgroups[$id]['DIALOG_ID'] = Dialog::getDialogId($chatData[$id] ?? 0);
418 }
419 }
420
421 $workgroups = $this->convertKeysToCamelCase($workgroups);
422
423 return new Engine\Response\DataType\Page('workgroups', array_values($workgroups), $count);
424 }
425
429 public function isExistingGroupAction(string $name): array
430 {
431 return [
432 'exists' => GroupProvider::getInstance()->isExistingGroup($name),
433 ];
434 }
435
436 private function prepareSelect(array $select = []): array
437 {
438 return array_filter($select, static function ($key) {
439 return in_array(mb_strtoupper($key), static::getAllowedSelectFields(), true);
440 });
441 }
442
443 private function getAvatarData(int $imageId, string $avatarType): array
444 {
445 $avatarManager = new AvatarManager();
446
447 if ($imageId)
448 {
449 $avatarData = $avatarManager->getImageAvatar($imageId)->toArray();
450 }
451 else
452 {
453 $avatarData = $avatarManager->getIconAvatar($avatarType)->toArray();
454 }
455
456 return $avatarData;
457 }
458
459 private function getOwnerData(int $ownerId): array
460 {
461 $owner = UserTable::getList([
462 'select' => ['NAME', 'LAST_NAME', 'SECOND_NAME', 'LOGIN', 'PERSONAL_PHOTO'],
463 'filter' => ['ID' => $ownerId],
464 ])->fetch();
465
466 return [
467 'ID' => $ownerId,
468 'PHOTO' => ($owner['PERSONAL_PHOTO'] ? File::getFileSource($owner['PERSONAL_PHOTO']) : null),
469 'FORMATTED_NAME' => htmlspecialcharsback(
470 \CUser::FormatName(
471 \CSite::getNameFormat(),
472 [
473 'NAME' => $owner['NAME'],
474 'LAST_NAME' => $owner['LAST_NAME'],
475 'SECOND_NAME' => $owner['SECOND_NAME'],
476 'LOGIN' => $owner['LOGIN'],
477 ],
478 true
479 )
480 ),
481 ];
482 }
483
484 private function getSubjectData(int $subjectId): array
485 {
486 $subject = WorkgroupSubjectTable::getList([
487 'select' => ['NAME'],
488 'filter' => ['ID' => $subjectId],
489 ])->fetch();
490
491 return [
492 'ID' => $subjectId,
493 'NAME' => $subject['NAME'],
494 ];
495 }
496
497 private function getTags(int $groupId): array
498 {
499 $tags = WorkgroupTagTable::getList([
500 'select' => ['NAME'],
501 'filter' => ['GROUP_ID' => $groupId],
502 ])->fetchAll();
503
504 return array_map(
505 static function($tag) {
506 return htmlspecialcharsback($tag);
507 },
508 array_column($tags, 'NAME')
509 );
510 }
511
512 private function getThemeData(int $groupId): ?array
513 {
514 if (!Loader::includeModule('intranet'))
515 {
516 return [];
517 }
518
519 $themePicker = new ThemePicker(
520 SITE_TEMPLATE_ID,
521 false,
522 $this->getCurrentUser()->getId(),
523 ThemePicker::ENTITY_TYPE_SONET_GROUP,
524 $groupId
525 );
526
527 $themeUserId = false;
528 $themeId = $themePicker->getCurrentThemeId();
529 if ($themeId)
530 {
531 $res = ThemeTable::getList([
532 'select' => ['USER_ID'],
533 'filter' => [
534 '=ENTITY_TYPE' => $themePicker->getEntityType(),
535 'ENTITY_ID' => $themePicker->getEntityId(),
536 '=CONTEXT' => $themePicker->getContext(),
537 ],
538 ]);
539 if (($themeFields = $res->fetch()) && (int)$themeFields['USER_ID'] > 0)
540 {
541 $themeUserId = (int)$themeFields['USER_ID'];
542 }
543 }
544
545 return $themePicker->getTheme($themeId, $themeUserId);
546 }
547
548 private function getActions(int $groupId): array
549 {
550 $permissions = Helper\Workgroup::getPermissions(['groupId' => $groupId]);
551
552 $canEditFeatures = $permissions['UserCanModifyGroup'];
553 if (!\Bitrix\Socialnetwork\Helper\Workgroup::getEditFeaturesAvailability())
554 {
555 $canEditFeatures = false;
556 }
557
558 return [
559 'EDIT' => $permissions['UserCanModifyGroup'],
560 'DELETE' => $permissions['UserCanModifyGroup'],
561 'INVITE' => $permissions['UserCanInitiate'],
562 'JOIN' => (
563 !$permissions['UserIsMember']
564 && !$permissions['UserRole']
565 ),
566 'LEAVE' => (
567 $permissions['UserIsMember']
568 && !$permissions['UserIsAutoMember']
569 && !$permissions['UserIsOwner']
570 && !$permissions['UserIsScrumMaster']
571 ),
572 'FOLLOW' => $permissions['UserIsMember'],
573 'PIN' => $permissions['UserIsMember'],
574 'EDIT_FEATURES' => $canEditFeatures,
575 ];
576 }
577
578 private function getUserData(int $groupId): array
579 {
580 $permissions = Helper\Workgroup::getPermissions(['groupId' => $groupId]);
581
582 return [
583 'ROLE' => $permissions['UserRole'],
584 'INITIATED_BY_TYPE' => $permissions['InitiatedByType'],
585 'IS_SUBSCRIBED' => (
586 in_array($permissions['UserRole'], UserToGroupTable::getRolesMember(), true)
587 && \CSocNetSubscription::isUserSubscribed($this->getCurrentUser()->getId(), 'SG' . $groupId)
588 ),
589 ];
590 }
591
592 private function getDepartments($ufDepartments): array
593 {
594 $departments = [];
595
596 if (
597 empty($ufDepartments)
598 || !is_array($ufDepartments)
599 || !Loader::includeModule('intranet')
600 )
601 {
602 return $departments;
603 }
604
605 $departmentsList = \CIntranetUtils::getDepartmentsData($ufDepartments);
606 if (empty($departmentsList))
607 {
608 return $departments;
609 }
610
611 foreach ($departmentsList as $id => $name)
612 {
613 if (($id = (int)$id) <= 0)
614 {
615 continue;
616 }
617
618 $departments[] = [
619 'ID' => $id,
620 'NAME' => $name,
621 ];
622 }
623
624 return $departments;
625 }
626
627 private function isPin(int $groupId, int $currentUserId, string $context = ''): bool
628 {
629 $query = new Query(WorkgroupPinTable::getEntity());
630
631 $query = $query
632 ->setSelect([
633 'ID',
634 'GROUP_ID',
635 'USER_ID',
636 ])
637 ->where('GROUP_ID', $groupId)
638 ->where('USER_ID', $currentUserId)
639 ;
640 if ($context === '')
641 {
642 $query = $query->where(Query::filter()
643 ->logic('or')
644 ->whereNull('CONTEXT')
645 ->where('CONTEXT', '')
646 );
647 }
648 else
649 {
650 $query = $query->where('CONTEXT', $context);
651 }
652
653 $pin = $query->setLimit(1)->exec()->fetchObject();
654
655 return (bool) $pin;
656 }
657
658 private function getListOfMembers(int $groupId, int $scrumMasterId): array
659 {
660 $list = [];
661
662 $records = UserToGroupTable::query()
663 ->setSelect([
664 'GROUP_ID',
665 'USER_ID',
666 'ROLE',
667 'INITIATED_BY_TYPE',
668 'AUTO_MEMBER',
669 'NAME' => 'USER.NAME',
670 'LAST_NAME' => 'USER.LAST_NAME',
671 'SECOND_NAME' => 'USER.SECOND_NAME',
672 'WORK_POSITION' => 'USER.WORK_POSITION',
673 'LOGIN' => 'USER.LOGIN',
674 'PERSONAL_PHOTO' => 'USER.PERSONAL_PHOTO',
675 ])
676 ->whereIn('GROUP_ID', $groupId)
677 ->whereIn('ROLE', UserToGroupTable::getRolesMember())
678 ->exec()->fetchCollection()
679 ;
680
681 $members = [];
682 $imageIdList = [];
683 foreach ($records as $record)
684 {
685 $user = $record->get('USER');
686 $imageIdList[$record->get('USER_ID')] = $user->get('PERSONAL_PHOTO');
687 $members[] = $record;
688 }
689 $imageIdList = array_filter(
690 $imageIdList,
691 static function ($id) {
692 return (int) $id > 0;
693 }
694 );
695 $avatars = $this->getUserAvatars($imageIdList);
696
697 foreach ($members as $member)
698 {
699 $memberId = (int) $member['USER_ID'];
700
701 $isOwner = ($member['ROLE'] === UserToGroupTable::ROLE_OWNER);
702 $isModerator = ($member['ROLE'] === UserToGroupTable::ROLE_MODERATOR);
703 $isScrumMaster = ($scrumMasterId === $memberId);
704 $memberUser = $member->getUser();
705
706 $list[] = [
707 'id' => $memberId,
708 'isOwner' => $isOwner,
709 'isModerator' => $isModerator,
710 'isScrumMaster' => $isScrumMaster,
711 'isAutoMember' => $member['AUTO_MEMBER'],
712 'name' => $memberUser->getName(),
713 'lastName' => $memberUser->getLastName(),
714 'position' => $memberUser->getWorkPosition(),
715 'photo' => ($avatars[($imageIdList[$memberId] ?? '')] ?? ''),
716 ];
717 }
718
719 return $list;
720 }
721
722 private function prepareFeatures(int $groupId): array
723 {
724 $features = [];
725
726 $baseFeatures = $this->getBaseFeatures($groupId);
727
728 foreach ($this->getAllowedFeatures() as $featureId => $feature)
729 {
730 if (array_key_exists($featureId, $baseFeatures))
731 {
732 $features[] = [
733 'featureName' => $featureId,
734 'name' => Loc::getMessage('SOCIALNETWORK_WORKGROUP_'.strtoupper($featureId)),
735 'customName' => $baseFeatures[$featureId]['FEATURE_NAME'] ?? '',
736 'id' => $baseFeatures[$featureId]['ID'],
737 'active' => $baseFeatures[$featureId]['ACTIVE'] === 'Y',
738 ];
739 }
740 }
741
742 return $features;
743 }
744
745 private function getBaseFeatures(int $groupId): array
746 {
747 $features = [];
748
749 $queryObject = \CSocNetFeatures::getList(
750 [],
751 [
752 'ENTITY_ID' => $groupId,
753 'ENTITY_TYPE' => SONET_ENTITY_GROUP,
754 ]
755 );
756 while ($featureFields = $queryObject->fetch())
757 {
758 $features[$featureFields['FEATURE']]= $featureFields;
759 }
760
761 return $features;
762 }
763
764 private function getAllowedFeatures(): array
765 {
766 $allowedFeatures = \CSocNetAllowed::getAllowedFeatures();
767
768 $sampleKeysList = [
769 'tasks' => 1,
770 'calendar' => 2,
771 'files' => 3,
772 'chat' => 4,
773 'forum' => 5,
774 'microblog' => 6,
775 'blog' => 7,
776 'photo' => 8,
777 'group_lists' => 9,
778 'wiki' => 10,
779 'content_search' => 11,
780 'marketplace' => 12,
781 ];
782
783 uksort($allowedFeatures, static function($a, $b) use ($sampleKeysList) {
784
785 $valA = ($sampleKeysList[$a] ?? 100);
786 $valB = ($sampleKeysList[$b] ?? 100);
787
788 if ($valA > $valB)
789 {
790 return 1;
791 }
792
793 if ($valA < $valB)
794 {
795 return -1;
796 }
797
798 return 0;
799 });
800
801 return array_filter($allowedFeatures, function($feature) {
802 return (
803 is_array($feature['allowed'])
804 && in_array(SONET_ENTITY_GROUP, $feature['allowed'], true)
805 );
806 });
807 }
808
809 private function getListOfAwaitingMembers(int $groupId, int $limit = 10, int $offset = 0): array
810 {
811 $list = [];
812
813 $records = UserToGroupTable::query()
814 ->setSelect([
815 'GROUP_ID',
816 'USER_ID',
817 'ROLE',
818 'INITIATED_BY_TYPE',
819 'NAME' => 'USER.NAME',
820 'LAST_NAME' => 'USER.LAST_NAME',
821 'SECOND_NAME' => 'USER.SECOND_NAME',
822 'LOGIN' => 'USER.LOGIN',
823 'PERSONAL_PHOTO' => 'USER.PERSONAL_PHOTO',
824 ])
825 ->whereIn('GROUP_ID', $groupId)
826 ->where('INITIATED_BY_TYPE', UserToGroupTable::INITIATED_BY_USER)
827 ->where('ROLE', UserToGroupTable::ROLE_REQUEST)
828 ->setLimit($limit)
829 ->setOffset($offset)
830 ->exec()->fetchCollection()
831 ;
832
833 $members = [];
834 $imageIdList = [];
835 foreach ($records as $record)
836 {
837 $user = $record->get('USER');
838 $imageIdList[$record->get('USER_ID')] = $user->get('PERSONAL_PHOTO');
839
840 $members[] = $record;
841 }
842 $imageIdList = array_filter(
843 $imageIdList,
844 static function ($id) {
845 return (int) $id > 0;
846 }
847 );
848 $avatars = $this->getUserAvatars($imageIdList);
849
850 foreach ($members as $member)
851 {
852 $memberId = (int) $member['USER_ID'];
853
854 $userNameFormatted = \CUser::formatName(\CSite::getNameFormat(), [
855 'NAME' => $member->get('USER')->get('NAME'),
856 'LAST_NAME' => $member->get('USER')->get('LAST_NAME'),
857 'SECOND_NAME' => $member->get('USER')->get('SECOND_NAME'),
858 'LOGIN' => $member->get('USER')->get('LOGIN'),
859 ], ModuleManager::isModuleInstalled('intranet'));
860
861 $list[] = [
862 'id' => $memberId,
863 'name' => $userNameFormatted,
864 'photo' => ($avatars[($imageIdList[$memberId] ?? '')] ?? ''),
865 ];
866 }
867
868 return $list;
869 }
870
871 private function getCounters(int $groupId): array
872 {
873 $counters = [];
874
875 $counterProvider = Counter::getInstance($this->getCurrentUser()->getId());
876
877 $availableCounters = [
878 CounterDictionary::COUNTER_WORKGROUP_REQUESTS_OUT,
879 CounterDictionary::COUNTER_WORKGROUP_REQUESTS_IN,
880 ];
881 foreach ($availableCounters as $counter)
882 {
883 $counters[$counter] = $counterProvider->get($counter, $groupId)['all'];
884 }
885
886 return $counters;
887 }
888
889 public function updateAction(int $groupId, array $fields = []): ?bool
890 {
892 'groupId' => $groupId,
893 'checkAdminSession' => ($this->getScope() !== Controller::SCOPE_REST),
894 ]))
895 {
896 $this->addEmptyGroupIdError();
897 return null;
898 }
899
900 $whiteList = [
901 'NAME',
902 'DESCRIPTION',
903 'KEYWORDS',
904 'VISIBLE',
905 'OPENED',
906 'EXTERNAL',
907 ];
908
909 foreach ($fields as $key => $value)
910 {
911 if (!in_array($key, $whiteList, true))
912 {
913 unset($fields[$key]);
914 }
915 }
916
917 if (
918 empty($fields)
919 )
920 {
921 $this->addError(new Error(
922 Loc::getMessage('SONET_CONTROLLER_WORKGROUP_ACTION_FAILED'),
923 'SONET_CONTROLLER_WORKGROUP_ACTION_FAILED')
924 );
925 return null;
926 }
927
928 try
929 {
930 $result = \CSocNetGroup::update($groupId, $fields);
931 }
932 catch (Exception $e)
933 {
934 $this->addError(new Error($e->getMessage(), $e->getCode()));
935 return null;
936 }
937
938 if (!$result)
939 {
940 $this->addError(new Error(
941 Loc::getMessage('SONET_CONTROLLER_WORKGROUP_ACTION_FAILED'),
942 'SONET_CONTROLLER_WORKGROUP_ACTION_FAILED')
943 );
944 return null;
945 }
946
947 $this->sendPush(PushEventDictionary::EVENT_WORKGROUP_UPDATE, [
948 'params' => [
949 'GROUP_ID' => $groupId,
950 ],
951 ]);
952
953 return true;
954 }
955
956 public function leaveAction(int $groupId)
957 {
958 if (!Helper\Workgroup\Access::canLeave([ 'groupId' => $groupId ]))
959 {
960 $this->addError(new Error('NO PERMISSION'));
961 return null;
962 }
963
964 return \CSocNetUserToGroup::DeleteRelation($this->userId, $groupId);
965 }
966
967 public function deleteAction(int $groupId)
968 {
969 if (
971 'groupId' => $groupId,
972 'checkAdminSession' => ($this->getScope() !== Controller::SCOPE_REST),
973 ])
974 )
975 {
976 $this->addEmptyGroupIdError();
977
978 return null;
979 }
980
981 global $APPLICATION;
982
983 $deleteResult = \CSocNetGroup::Delete($groupId);
984 if (!$deleteResult && ($e = $APPLICATION->GetException()))
985 {
986 return $e->GetString();
987 }
988
989 return true;
990 }
991
992 public function getAvatarTypesAction(): array
993 {
994 return Helper\Workgroup::getAvatarTypes();
995 }
996
997 public function disconnectDepartmentsAction(int $groupId, array $departmentIds)
998 {
999 foreach ($departmentIds as $id)
1000 {
1001 Helper\Workgroup::disconnectDepartment([
1002 'groupId' => $groupId,
1003 'departmentId' => $id,
1004 ]);
1005 }
1006 }
1007
1008 public function setFavoritesAction(array $params = []): ?array
1009 {
1010 $groupId = (int)($params['groupId'] ?? 0);
1011 $getAdditionalResultData = (bool)($params['getAdditionalResultData'] ?? false);
1012
1013 if ($groupId <= 0)
1014 {
1015 $this->addEmptyGroupIdError();
1016 return null;
1017 }
1018
1019 if (!in_array($params['value'] ?? null, WorkgroupFavorites::AVAILABLE_VALUES, true))
1020 {
1021 $this->addIncorrectValueError();
1022 return null;
1023 }
1024
1025 try
1026 {
1028 'GROUP_ID' => $groupId,
1029 'USER_ID' => $this->getCurrentUser()->getId(),
1030 'VALUE' => $params['value'],
1031 ]);
1032 }
1033 catch (Exception $e)
1034 {
1035 $this->addError(new Error($e->getMessage(), $e->getCode()));
1036 return null;
1037 }
1038
1039 if (!$res)
1040 {
1041 $this->addError(new Error(Loc::getMessage('SONET_CONTROLLER_WORKGROUP_ACTION_FAILED'), 'SONET_CONTROLLER_WORKGROUP_ACTION_FAILED'));
1042 return null;
1043 }
1044
1045 $result = [
1046 'ID' => $groupId,
1047 'RESULT' => $params['value'],
1048 ];
1049
1050 if ($getAdditionalResultData)
1051 {
1052 $groupItem = \Bitrix\Socialnetwork\Item\Workgroup::getById($groupId);
1053 $groupFields = $groupItem->getFields();
1054 $groupUrlData = $groupItem->getGroupUrlData([
1055 'USER_ID' => $this->getCurrentUser()->getId(),
1056 ]);
1057
1058 $groupSiteList = [];
1059 $resSite = WorkgroupSiteTable::getList([
1060 'filter' => [
1061 '=GROUP_ID' => $groupId
1062 ],
1063 'select' => [ 'SITE_ID' ],
1064 ]);
1065 while ($groupSite = $resSite->fetch())
1066 {
1067 $groupSiteList[] = $groupSite['SITE_ID'];
1068 }
1069
1070 $result['NAME'] = $groupFields['NAME'];
1071 $result['URL'] = $groupUrlData["URL"];
1072 $result['EXTRANET'] = (
1073 Loader::includeModule('extranet')
1074 && CExtranet::isIntranetUser()
1075 && in_array(CExtranet::getExtranetSiteId(), $groupSiteList, true)
1076 ? 'Y'
1077 : 'N'
1078 );
1079 }
1080
1081 $this->sendPush(PushEventDictionary::EVENT_WORKGROUP_FAVORITES_CHANGED, ['GROUP_ID' => $groupId]);
1082
1083 return $result;
1084 }
1085
1087 {
1088 $groupId = (int)($params['groupId'] ?? 0);
1089 if ($groupId <= 0)
1090 {
1091 $this->addEmptyGroupIdError();
1092 return null;
1093 }
1094
1095 if (!in_array($params['value'] ?? null, Subscription::AVAILABLE_VALUES, true))
1096 {
1097 $this->addIncorrectValueError();
1098 return null;
1099 }
1100
1101 try
1102 {
1103 $result = Subscription::set([
1104 'GROUP_ID' => $groupId,
1105 'USER_ID' => $this->getCurrentUser()->getId(),
1106 'VALUE' => $params['value'],
1107 ]);
1108 }
1109 catch (Exception $e)
1110 {
1111 $this->addError(new Error($e->getMessage(), $e->getCode()));
1112 return null;
1113 }
1114
1115 $this->sendPush(PushEventDictionary::EVENT_WORKGROUP_SUBSCRIBE_CHANGED, ['GROUP_ID' => $groupId]);
1116
1117 return [
1118 'RESULT' => $result ? 'Y' : 'N',
1119 ];
1120 }
1121
1122 public function updatePhotoAction(): bool
1123 {
1124 $groupId = $this->getRequest()->get('groupId');
1125
1126 if (!Helper\Workgroup\Access::canUpdate([ 'groupId' => $groupId ]))
1127 {
1128 $this->addError(new Error('SOCIALNETWORK_GROUP_AJAX_NO_UPDATE_PERMS'));
1129 return false;
1130 }
1131
1132 $workgroupData = WorkgroupTable::getList([
1133 'select' => [ 'ID', 'IMAGE_ID' ],
1134 'filter' => [
1135 '=ID' => $groupId,
1136 ],
1137 ])->fetch();
1138
1139 $newPhotoFile = $this->getRequest()->getFile('newPhoto');
1140
1141 if ($workgroupData['IMAGE_ID'])
1142 {
1143 $newPhotoFile['old_file'] = $workgroupData['IMAGE_ID'];
1144 $newPhotoFile['del'] = $workgroupData['IMAGE_ID'];
1145 }
1146
1147 $res = \CSocNetGroup::update(
1148 $groupId,
1149 [ 'IMAGE_ID' => $newPhotoFile ],
1150 true,
1151 true,
1152 false
1153 );
1154
1155 if (!$res)
1156 {
1157 $this->addError(new Error('SOCIALNETWORK_GROUP_AJAX_FAILED'));
1158 return false;
1159 }
1160
1161 $this->sendPush(PushEventDictionary::EVENT_WORKGROUP_UPDATE, [
1162 'params' => [
1163 'GROUP_ID' => $groupId,
1164 ],
1165 ]);
1166
1167 return true;
1168 }
1169
1170 public function createGroupAction(): array
1171 {
1172 $groupName = $this->getRequest()->get('groupName');
1173 $viewMode = $this->getRequest()->get('viewMode');
1174 $groupImage = $this->getRequest()->getFile('groupImage');
1175 $avatarColor = $this->getRequest()->get('avatarColor');
1176
1178 {
1179 return ['groupId' => 0];
1180 }
1181
1182 $ownerId = $this->getCurrentUser()->getId();
1183
1184 $groupParams = [
1185 'SITE_ID' => [SITE_ID],
1186 'NAME' => $groupName,
1187 'SUBJECT_ID' => $this->getDefaultSubjectId(),
1188 'INITIATE_PERMS' => SONET_ROLES_USER,
1189 'SPAM_PERMS' => SONET_ROLES_USER,
1190 'VISIBLE' => $viewMode !== 'secret' ? 'Y' : 'N',
1191 'OPENED' => $viewMode === 'open' ? 'Y' : 'N',
1192 ];
1193
1194 if (is_array($groupImage))
1195 {
1196 try
1197 {
1198 $avatarManager = new AvatarManager();
1199 $result = $avatarManager->loadAvatar($groupImage);
1200 $groupParams['IMAGE_ID'] = $avatarManager->getAvatar($result['fileId']);
1201 }
1202 catch (\RuntimeException)
1203 {
1204 unset($groupParams['IMAGE_ID']);
1205 }
1206 }
1207
1208 if (!isset($groupParams['IMAGE_ID']))
1209 {
1210 $groupParams['AVATAR_TYPE'] = $this->getColoredDefaultAvatar($avatarColor);
1211 }
1212
1213 $groupId = (int)\CSocNetGroup::createGroup($ownerId, $groupParams);
1214
1215 global $APPLICATION;
1216 if ($e = $APPLICATION->GetException())
1217 {
1218 $this->addError(new Error($e->msg, $e->id));
1219 return [];
1220 }
1221
1222 $this->setDefaultGroupFeatures($groupId);
1223
1224 return [
1225 'groupId' => $groupId,
1226 ];
1227 }
1228
1235 public function turnOnTrialAction(bool $scrum = false): bool
1236 {
1238 {
1239 $this->addError(new Error('Access denied'));
1240
1241 return false;
1242 }
1243
1244 $feature = $scrum ? Helper\Feature::SCRUM_CREATE : Helper\Feature::PROJECTS_GROUPS;
1245
1246 if (
1248 && Helper\Feature::canTurnOnTrial($feature)
1249 )
1250 {
1251 Helper\Feature::turnOnTrial($feature);
1252
1253 return true;
1254 }
1255 else
1256 {
1257 $this->addError(new Error('Already included'));
1258
1259 return false;
1260 }
1261 }
1262
1263 private function getColoredDefaultAvatar(string $color): string
1264 {
1265 if (in_array($color, Helper\Workgroup::getAvatarColors(), true))
1266 {
1267 return "space_$color";
1268 }
1269
1270 return array_rand(Helper\Workgroup::getColoredAvatarTypes());
1271 }
1272
1273 private function setDefaultGroupFeatures(int $groupId): void
1274 {
1275 $allowedFeatures = array_keys(\CSocNetAllowed::getAllowedFeatures());
1276 $inactiveFeaturesList = ['forum', 'photo', 'search', 'group_lists', 'wiki'];
1277
1278 $features = [];
1279 foreach ($allowedFeatures as $featureName)
1280 {
1281 $features[$featureName] = !in_array($featureName, $inactiveFeaturesList, true);
1282 }
1283
1284 foreach ($features as $featureName => $isActive)
1285 {
1286 \CSocNetFeatures::setFeature(
1288 $groupId,
1289 $featureName,
1290 $isActive,
1291 );
1292 }
1293 }
1294
1295 private function getDefaultSubjectId(): int
1296 {
1297 $subject = \CSocNetGroupSubject::GetList(
1298 ["SORT"=>"ASC", "NAME" => "ASC"],
1299 ["SITE_ID" => SITE_ID],
1300 false,
1301 false,
1302 ["ID", "NAME"],
1303 )->fetch();
1304
1305 return (int)($subject['ID'] ?? 0);
1306 }
1307
1308 public function getCanCreateAction(): bool
1309 {
1310 return Helper\Workgroup\Access::canCreate([
1311 'checkAdminSession' => ($this->getScope() !== Controller::SCOPE_REST),
1312 ]);
1313 }
1314
1315 public function updateInvitedUsersAction(int $spaceId, array $users): void
1316 {
1317 $membersManager = new MembersManager();
1318
1319 if (!$membersManager->canInviteUsers($spaceId))
1320 {
1321 return;
1322 }
1323
1324 $membersManager->updateInvitedUsers($spaceId, array_map(static fn($userId) => (int)$userId, $users));
1325 }
1326
1328 int $groupId,
1329 string $type,
1330 int $page,
1331 string $componentName = '',
1332 string $signedParameters = ''
1333 ): ?array
1334 {
1335 if ($groupId <= 0)
1336 {
1337 $this->addEmptyGroupIdError();
1338
1339 return null;
1340 }
1341
1342 if (
1344 'groupId' => $groupId,
1345 'checkAdminSession' => ($this->getScope() !== Controller::SCOPE_REST),
1346 ])
1347 )
1348 {
1349 $this->addError(new Error('Access denied'));
1350
1351 return null;
1352 }
1353
1354 $unsignedParameters = [];
1355 if (
1356 $componentName !== ''
1357 && $signedParameters !== ''
1358 )
1359 {
1362 $signedParameters
1363 );
1364 if (!is_array($unsignedParameters))
1365 {
1366 $unsignedParameters = [];
1367 }
1368 }
1369
1370 $rolesMap = [
1371 'all' => [
1375 ],
1376 'heads' => [
1379 ],
1380 'members' => [
1382 ],
1383 'scrumTeam' => [
1386 ],
1387 ];
1388 $limit = 10;
1389
1390 $query = UserToGroupTable::query();
1391 $records = $query
1392 ->setSelect([
1393 'GROUP_ID',
1394 'GROUP',
1395 'USER_ID',
1396 'ROLE',
1397 'INITIATED_BY_TYPE',
1398 'AUTO_MEMBER',
1399 'NAME' => 'USER.NAME',
1400 'LAST_NAME' => 'USER.LAST_NAME',
1401 'SECOND_NAME' => 'USER.SECOND_NAME',
1402 'LOGIN' => 'USER.LOGIN',
1403 'PERSONAL_PHOTO' => 'USER.PERSONAL_PHOTO',
1404 ])
1405 ->where('GROUP_ID', $groupId)
1406 ->whereIn('ROLE', $rolesMap[$type])
1407 ->setLimit($limit)
1408 ->setOffset(($page - 1) * $limit)
1409 ->exec()->fetchCollection();
1410
1411 $isScrumMembers = ($type === 'scrumTeam');
1412 if ($isScrumMembers)
1413 {
1414 $query->addSelect('GROUP.SCRUM_MASTER_ID', 'SCRUM_MASTER_ID');
1415 }
1416
1417 $imageIds = [];
1418 $resultMembers = [];
1419
1420 foreach ($records as $member)
1421 {
1422 $imageIds[$member->get('USER_ID')] = $member->get('USER')->get('PERSONAL_PHOTO');
1423 $resultMembers[] = $member;
1424 }
1425
1426 $imageIds = array_filter(
1427 $imageIds,
1428 static function ($id) { return (int)$id > 0; }
1429 );
1430 $avatars = Helper\UI\Grid\Workgroup\Members::getUserAvatars($imageIds);
1431 $pathToUser = ($unsignedParameters['PATH_TO_USER'] ?? Helper\Path::get('user_profile'));
1432 $userNameTemplate = ($unsignedParameters['NAME_TEMPLATE'] ?? \CSite::getNameFormat());
1433 $isIntranetInstalled = ModuleManager::isModuleInstalled('intranet');
1434
1435 $members = [];
1436
1437 foreach ($resultMembers as $member)
1438 {
1439 $id = $member->get('USER_ID');
1440 $userNameFormatted = \CUser::formatName($userNameTemplate, [
1441 'NAME' => $member->get('USER')->get('NAME'),
1442 'LAST_NAME' => $member->get('USER')->get('LAST_NAME'),
1443 'SECOND_NAME' => $member->get('USER')->get('SECOND_NAME'),
1444 'LOGIN' => $member->get('USER')->get('LOGIN'),
1445 ], $isIntranetInstalled);
1446
1447 $userUrl = \CComponentEngine::makePathFromTemplate($pathToUser, [
1448 'user_id' => $id,
1449 'id' => $id,
1450 ]);
1451
1452 $members[] = [
1453 'ID' => $id,
1454 'PHOTO' => $avatars[$imageIds[$id] ?? null] ?? '',
1455 'HREF' => $userUrl,
1456 'FORMATTED_NAME' => $userNameFormatted,
1457 'ROLE' => ($isScrumMembers ? $this->getScrumRole($member) : $member->get('ROLE')),
1458 ];
1459
1460 if ($isScrumMembers)
1461 {
1462 if (
1463 $member->get('ROLE') === UserToGroupTable::ROLE_OWNER
1464 && $member->get('USER_ID') === $member->get('GROUP')->get('SCRUM_MASTER_ID')
1465 )
1466 {
1467 $members[] = [
1468 'ID' => $id,
1469 'PHOTO' => $avatars[$imageIds[$id] ?? null] ?? '',
1470 'HREF' => $userUrl,
1471 'FORMATTED_NAME' => $userNameFormatted,
1472 'ROLE' => 'M',
1473 ];
1474 }
1475 }
1476 }
1477
1478 return $members;
1479 }
1480
1481 private function getScrumRole(EO_UserToGroup $member): string
1482 {
1483 if (
1484 $member->get('USER_ID') === $member->get('GROUP')->get('SCRUM_MASTER_ID')
1485 && $member->get('ROLE') !== UserToGroupTable::ROLE_OWNER
1486 )
1487 {
1488 return 'M';
1489 }
1490
1491 return $member->get('ROLE');
1492 }
1493
1497 public function changePinAction(
1498 array $groupIdList,
1499 string $action,
1500 string $componentName = '',
1501 string $signedParameters = ''
1502 ): ?bool
1503 {
1504 $unsignedParameters = [];
1505 if (
1506 $componentName !== ''
1507 && $signedParameters !== ''
1508 )
1509 {
1510 $unsignedParameters = \Bitrix\Main\Component\ParameterSigner::unsignParameters($componentName, $signedParameters);
1511 if (!is_array($unsignedParameters))
1512 {
1513 $unsignedParameters = [];
1514 }
1515 }
1516
1517 $mode = ($unsignedParameters['MODE'] ?? '');
1518
1519 $counter = 0;
1520
1521 foreach ($groupIdList as $groupId)
1522 {
1523 $groupId = (int)$groupId;
1524
1525 if (
1526 $groupId <= 0
1528 'groupId' => $groupId,
1529 ])
1530 )
1531 {
1532 continue;
1533 }
1534
1535 $counter++;
1536
1537 $pin = new Pin($this->userId, $groupId, $mode);
1538 $result = $pin->switch();
1539
1540 if (!$result->isSuccess())
1541 {
1542 $this->addErrors($result->getErrors());
1543 return null;
1544 }
1545
1546 $this->sendPush(PushEventDictionary::EVENT_WORKGROUP_PIN_CHANGED, [
1547 'GROUP_ID' => $groupId,
1548 'ACTION' => $action,
1549 ]
1550 );
1551 }
1552
1553 if ($counter <= 0)
1554 {
1555 $this->addEmptyGroupIdError();
1556 return null;
1557 }
1558
1559 return true;
1560 }
1561
1562 public function acceptIncomingRequestAction(int $groupId, array $userIds): ?array
1563 {
1564 try
1565 {
1566 $result = [];
1567
1568 foreach ($userIds as $userId)
1569 {
1570 $result[$userId] = Helper\Workgroup::acceptIncomingRequest([
1571 'groupId' => $groupId,
1572 'userId' => $userId,
1573 ]);
1574 }
1575
1576 // re-calculte counters for the group moderators
1577 $moderators = UserToGroupTable::getGroupModerators($groupId);
1578 Service::addEvent(
1579 EventDictionary::EVENT_WORKGROUP_MEMBER_REQUEST_CONFIRM,
1580 [
1581 'GROUP_ID' => $groupId,
1582 'RECEPIENTS' => array_map(function ($row) { return $row['USER_ID']; }, $moderators),
1583 ]
1584 );
1585
1586 return $result;
1587 }
1588 catch (Exception $e)
1589 {
1590 $this->addError(new Error($e->getMessage()));
1591
1592 return null;
1593 }
1594 }
1595
1596 public function rejectIncomingRequestAction(int $groupId, array $userIds): ?array
1597 {
1598 try
1599 {
1600 $result = [];
1601
1602 foreach ($userIds as $userId)
1603 {
1604 $result[$userId] = Helper\Workgroup::rejectIncomingRequest([
1605 'groupId' => $groupId,
1606 'userId' => $userId,
1607 ]);
1608 }
1609
1610 // re-calculte counters for the group moderators
1611 $moderators = UserToGroupTable::getGroupModerators($groupId);
1612 Service::addEvent(
1613 EventDictionary::EVENT_WORKGROUP_MEMBER_REQUEST_CONFIRM,
1614 [
1615 'GROUP_ID' => $groupId,
1616 'RECEPIENTS' => array_map(function ($row) { return $row['USER_ID']; }, $moderators),
1617 ]
1618 );
1619
1620 return $result;
1621 }
1622 catch (Exception $e)
1623 {
1624 $this->addError(new Error($e->getMessage()));
1625
1626 return null;
1627 }
1628 }
1629
1630 public function getListIncomingUsersAction(int $groupId, int $pageNum): ?array
1631 {
1632 $permissions = Helper\Workgroup::getPermissions(
1633 ['groupId' => $groupId]
1634 );
1635 if (!$permissions['UserCanModifyGroup'] && !$permissions['UserCanInitiate'])
1636 {
1637 $this->addError(new Error('Access denied'));
1638
1639 return null;
1640 }
1641
1642 $limit = 10;
1643 $offset = ($pageNum - 1) * $limit;
1644
1645 return $this->getListOfAwaitingMembers($groupId, $limit, $offset);
1646 }
1647
1648 public function getChatIdAction(int $groupId): ?string
1649 {
1650 $chatId = '';
1651
1652 if (!Loader::includeModule('im'))
1653 {
1654 return $chatId;
1655 }
1656
1658 [
1659 'group_id' => $groupId,
1660 'skipAvailabilityCheck' => true,
1661 ]
1662 );
1663 if (!empty($chatData[$groupId]) && intval($chatData[$groupId]) > 0)
1664 {
1665 $chatId = $chatData[$groupId];
1666 }
1667 else
1668 {
1670 [
1671 'group_id' => $groupId,
1672 ]
1673 );
1674 }
1675
1676 return $chatId;
1677 }
1678
1679 public function setFeatureAction(int $groupId, array $feature): bool
1680 {
1681 if (
1683 'groupId' => $groupId,
1684 'checkAdminSession' => ($this->getScope() !== Controller::SCOPE_REST),
1685 ])
1686 )
1687 {
1688 $this->addEmptyGroupIdError();
1689
1690 return false;
1691 }
1692
1693 $allowedFeatures = array_keys(\CSocNetAllowed::getAllowedFeatures());
1694
1695 $featureId = is_string($feature['featureName'] ?? null) ? $feature['featureName'] : '';
1696 $customName = is_string($feature['customName'] ?? null) ? $feature['customName'] : false;
1697 $featureActive = is_string($feature['active'] ?? null) && $feature['active'] === 'true';
1698
1699 $activeFeatures = \CSocNetFeatures::GetActiveFeatures(SONET_ENTITY_GROUP, $groupId);
1700
1701 if (in_array($featureId, $allowedFeatures, true))
1702 {
1703 \CSocNetFeatures::setFeature(
1705 $groupId,
1706 $featureId,
1707 $featureActive,
1708 $customName,
1709 );
1710 }
1711
1712 $action = '';
1713
1714 if ($featureActive === in_array($featureId ,$activeFeatures))
1715 {
1716 $action = 'change';
1717 }
1718
1719 if ($featureActive && !in_array($featureId ,$activeFeatures))
1720 {
1721 $action = 'add';
1722 }
1723
1724 if (!$featureActive && in_array($featureId ,$activeFeatures))
1725 {
1726 $action = 'delete';
1727 }
1728
1729 $this->sendPush(PushEventDictionary::EVENT_SPACE_FEATURE_CHANGE, [
1730 'GROUP_ID' => $groupId,
1731 'FEATURE' => $feature,
1732 'ACTION' => $action,
1733 ]
1734 );
1735
1736 return true;
1737 }
1738
1739 private function getUserAvatars(array $imageIds): array
1740 {
1741 $result = [];
1742 if (empty($imageIds))
1743 {
1744 return $result;
1745 }
1746
1747 $result = array_fill_keys($imageIds, '');
1748
1749 $res = \CFile::getList([], ['@ID' => implode(',', $imageIds)]);
1750 while ($file = $res->fetch())
1751 {
1752 $file['SRC'] = \CFile::getFileSRC($file);
1753 $fileInfo = \CFile::resizeImageGet(
1754 $file,
1755 [
1756 'width' => 100,
1757 'height' => 100,
1758 ],
1760 false,
1761 false,
1762 true,
1763 );
1764
1765 $result[$file['ID']] = $fileInfo['src'];
1766 }
1767
1768 return $result;
1769 }
1770
1771 private function sendPush(string $command, array $parameters = []): void
1772 {
1773 $parameters['USER_ID'] = $this->userId;
1774 PushService::addEvent(
1775 [$this->userId],
1776 [
1777 'module_id' => 'socialnetwork',
1778 'command' => $command,
1779 'params' => $parameters,
1780 ]
1781 );
1782 }
1783
1784 private function addEmptyGroupIdError(): void
1785 {
1786 $this->addError(
1787 new Error(
1788 Loc::getMessage('SONET_CONTROLLER_WORKGROUP_EMPTY'),
1789 'SONET_CONTROLLER_WORKGROUP_EMPTY'
1790 )
1791 );
1792 }
1793
1794 private function addIncorrectValueError(): void
1795 {
1796 $this->addError(new Error(
1797 'SONET_CONTROLLER_WORKGROUP_INCORRECT_VALUE',
1798 'SONET_CONTROLLER_WORKGROUP_INCORRECT_VALUE'
1799 ));
1800 }
1801}
$count
Определения admin_tab.php:4
$type
Определения options.php:106
global $APPLICATION
Определения include.php:80
if(!is_object($USER)||! $USER->IsAuthorized()) $userId
Определения check_mail.php:18
static getDialogId(int $chatId, $userId=null)
Определения dialog.php:50
static unsignParameters($componentName, $signedParameters)
Определения parametersigner.php:37
addError(Error $error)
Определения base.php:80
addErrors(array $errors)
Определения base.php:93
Определения error.php:15
setFavoritesAction(array $params=[])
Определения workgroup.php:1008
getListIncomingUsersAction(int $groupId, int $pageNum)
Определения workgroup.php:1630
setFeatureAction(int $groupId, array $feature)
Определения workgroup.php:1679
changePinAction(array $groupIdList, string $action, string $componentName='', string $signedParameters='')
Определения workgroup.php:1497
getGridPopupMembersAction(int $groupId, string $type, int $page, string $componentName='', string $signedParameters='')
Определения workgroup.php:1327
listAction(PageNavigation $pageNavigation, array $filter=[], array $select=[], array $order=[], array $params=[])
Определения workgroup.php:267
updateAction(int $groupId, array $fields=[])
Определения workgroup.php:889
leaveAction(int $groupId)
Определения workgroup.php:956
getChatIdAction(int $groupId)
Определения workgroup.php:1648
disconnectDepartmentsAction(int $groupId, array $departmentIds)
Определения workgroup.php:997
rejectIncomingRequestAction(int $groupId, array $userIds)
Определения workgroup.php:1596
deleteAction(int $groupId)
Определения workgroup.php:967
acceptIncomingRequestAction(int $groupId, array $userIds)
Определения workgroup.php:1562
setSubscriptionAction(array $params=[])
Определения workgroup.php:1086
updateInvitedUsersAction(int $spaceId, array $users)
Определения workgroup.php:1315
turnOnTrialAction(bool $scrum=false)
Определения workgroup.php:1235
isExistingGroupAction(string $name)
Определения workgroup.php:429
static canTurnOnTrial(string $featureName)
Определения feature.php:70
static isFeatureEnabled(string $featureName, int $groupId=0)
Определения feature.php:21
static canView(array $params=[])
Определения access.php:51
static canCreate(array $params=[])
Определения access.php:32
static canUpdate(array $params=[])
Определения access.php:159
static canModify(array $params=[])
Определения access.php:105
static canLeave(array $params=[])
Определения access.php:572
static set(array $params=[])
Определения workgroupfavorites.php:29
static getGroupModerators(int $groupId)
Определения usertogroup.php:220
static makePathFromTemplate($template, $arParams=array())
Определения component_engine.php:355
static getCurrentUserType()
Определения rest.php:3005
static getExtranetSiteId()
Определения rest.php:3029
$componentName
Определения component_props2.php:49
if(errorBox) return true
Определения file_new.php:1035
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$res
Определения filter_act.php:7
$result
Определения get_property_values.php:14
$query
Определения get_search.php:11
$select
Определения iblock_catalog_list.php:194
$filter
Определения iblock_catalog_list.php:54
$context
Определения csv_new_setup.php:223
const BX_RESIZE_IMAGE_EXACT
Определения constants.php:12
$culture
Определения include.php:61
FormatDate($format="", $timestamp=false, $now=false, ?string $languageId=null)
Определения tools.php:871
htmlspecialcharsback($str)
Определения tools.php:2693
MakeTimeStamp($datetime, $format=false)
Определения tools.php:538
$name
Определения menu_edit.php:35
$user
Определения mysql_to_pgsql.php:33
trait Error
Определения error.php:11
$order
Определения payment.php:8
$counter
Определения options.php:5
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
if(empty($signedUserToken)) $key
Определения quickway.php:257
$page
Определения order_form.php:33
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']
Определения template.php:799
else $a
Определения template.php:137
$counters
Определения options.php:100
const SONET_ROLES_USER
Определения include.php:31
const SONET_ENTITY_GROUP
Определения include.php:117
const SITE_ID
Определения sonet_set_content_view.php:12
$fields
Определения yandex_run.php:501