403Webshell
Server IP : 80.87.202.40  /  Your IP : 216.73.216.169
Web Server : Apache
System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64
User : bitrix ( 600)
PHP Version : 8.2.27
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : OFF |  Sudo : ON |  Pkexec : ON
Directory :  /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/socialnetwork/lib/controller/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/socialnetwork/lib/controller/workgroup.php
<?php

namespace Bitrix\Socialnetwork\Controller;

use Bitrix\Intranet\Integration\Templates\Bitrix24\ThemePicker;
use Bitrix\Intranet\Internals\ThemeTable;
use Bitrix\Main\Context;
use Bitrix\Main\Engine;
use Bitrix\Main\Engine\Controller;
use Bitrix\Main\Entity\Query;
use Bitrix\Main\Error;
use Bitrix\Main\Loader;
use Bitrix\Main\Localization\Loc;
use Bitrix\Main\ModuleManager;
use Bitrix\Main\Type\DateTime;
use Bitrix\Main\UI\PageNavigation;
use Bitrix\Main\UserTable;
use Bitrix\Socialnetwork\Collab\Integration\IM\Dialog;
use Bitrix\Socialnetwork\EO_UserToGroup;
use Bitrix\Socialnetwork\Helper;
use Bitrix\Socialnetwork\Helper\AvatarManager;
use Bitrix\Socialnetwork\Integration\Im\Chat;
use Bitrix\Socialnetwork\Integration\Main\File;
use Bitrix\Socialnetwork\Integration\Pull\PushService;
use Bitrix\Socialnetwork\Internals\Counter;
use Bitrix\Socialnetwork\Internals\Counter\CounterDictionary;
use Bitrix\Socialnetwork\Internals\EventService\EventDictionary;
use Bitrix\Socialnetwork\Internals\EventService\Push\PushEventDictionary;
use Bitrix\Socialnetwork\Internals\EventService\Service;
use Bitrix\Socialnetwork\Item\Subscription;
use Bitrix\Socialnetwork\Item\WorkgroupFavorites;
use Bitrix\Socialnetwork\Provider\GroupProvider;
use Bitrix\Socialnetwork\Space\MembersManager;
use Bitrix\Socialnetwork\Space\Toolbar\Switcher\Option\Pin;
use Bitrix\Socialnetwork\UserToGroupTable;
use Bitrix\Socialnetwork\WorkgroupPinTable;
use Bitrix\Socialnetwork\WorkgroupSiteTable;
use Bitrix\Socialnetwork\WorkgroupSubjectTable;
use Bitrix\Socialnetwork\WorkgroupTable;
use Bitrix\Socialnetwork\WorkgroupTagTable;
use Bitrix\Tasks\Internals\Effective;
use CExtranet;
use Exception;

class Workgroup extends Base
{
	private static function getAllowedSelectFields(): array
	{
		return [
			'ID', 'ACTIVE', 'SUBJECT_ID', 'NAME', 'DESCRIPTION', 'KEYWORDS',
			'CLOSED', 'VISIBLE', 'OPENED', 'PROJECT', 'LANDING',
			'DATE_CREATE', 'DATE_UPDATE', 'DATE_ACTIVITY',
			'IMAGE_ID', 'AVATAR_TYPE',
			'OWNER_ID',
			'NUMBER_OF_MEMBERS', 'NUMBER_OF_MODERATORS',
			'INITIATE_PERMS',
			'PROJECT_DATE_START', 'PROJECT_DATE_FINISH',
			'SCRUM_OWNER_ID', 'SCRUM_MASTER_ID', 'SCRUM_SPRINT_DURATION', 'SCRUM_TASK_RESPONSIBLE',
			'TYPE',
		];
	}

	public function getAction(array $params = []): ?array
	{
		$groupId = (int)($params['groupId'] ?? 0);

		if ($groupId <= 0)
		{
			$this->addEmptyGroupIdError();
			return null;
		}

		$select = ($params['select'] ?? []);
		$filter = ($params['filter'] ?? []);
		$filter['ID'] = $groupId;

		if (!\CSocNetUser::isCurrentUserModuleAdmin(SITE_ID, false))
		{
			$filter['CHECK_PERMISSIONS'] = $this->getCurrentUser()->getId();
		}

		$result = \CSocNetGroup::getList([], $filter, false, false, ['ID']);
		if ($group = $result->fetch())
		{
			$groupItem = \Bitrix\Socialnetwork\Item\Workgroup::getById($group['ID']);
			$groupFields = $groupItem->getFields();

			if (in_array('DATE_CREATE', $select, true))
			{
				$culture = Context::getCurrent()->getCulture();
				$longDateFormat = $culture->getLongDateFormat();
				$shortTimeFormat = $culture->getShortTimeFormat();

				$groupFields['DATE_CREATE'] = \CComponentUtil::getDateTimeFormatted([
					'TIMESTAMP' => MakeTimeStamp($groupFields['DATE_CREATE']),
					'TZ_OFFSET' => \CTimeZone::getOffset(),
				], "$longDateFormat, $shortTimeFormat");
			}
			if (in_array('AVATAR', $select, true))
			{
				$groupFields['AVATAR'] = File::getFileSource((int)$groupFields['IMAGE_ID'], 100, 100);
			}
			if (in_array('AVATAR_TYPES', $select, true))
			{
				$groupFields['AVATAR_TYPES'] = Helper\Workgroup::getAvatarTypes();
			}
			if (in_array('AVATAR_DATA', $select, true))
			{
				$imageId = (int) $groupFields['IMAGE_ID'];
				$avatarType = $groupFields['AVATAR_TYPE'] ?? '';
				$groupFields['AVATAR_DATA'] = $this->getAvatarData($imageId, $avatarType);
			}
			if (in_array('OWNER_DATA', $select, true))
			{
				$groupFields['OWNER_DATA'] = $this->getOwnerData($groupFields['OWNER_ID']);
			}
			if (in_array('SUBJECT_DATA', $select, true))
			{
				$groupFields['SUBJECT_DATA'] = $this->getSubjectData($groupFields['SUBJECT_ID']);
			}
			if (in_array('TAGS', $select, true))
			{
				$groupFields['TAGS'] = $this->getTags($groupId);
			}
			if (in_array('THEME_DATA', $select, true))
			{
				$groupFields['THEME_DATA'] = $this->getThemeData($groupId);
			}
			if (in_array('ACTIONS', $select, true))
			{
				$groupFields['ACTIONS'] = $this->getActions($groupId);
			}
			if (in_array('USER_DATA', $select, true))
			{
				$groupFields['USER_DATA'] = $this->getUserData($groupId);
			}
			if (in_array('DEPARTMENTS', $select, true))
			{
				$groupFields['DEPARTMENTS'] = $this->getDepartments($groupFields['UF_SG_DEPT']['VALUE']);
			}
			if (in_array('PIN', $select, true))
			{
				$groupFields['IS_PIN'] = $this->isPin($groupId, $this->getCurrentUser()->getId());
			}
			if (in_array('PRIVACY_TYPE', $select, true))
			{
				$groupFields['PRIVACY_CODE'] = Helper\Workgroup::getConfidentialityTypeCodeByParams([
					'fields' => [
						'OPENED' => $groupFields['OPENED'],
						'VISIBLE' => $groupFields['VISIBLE'],
					],
				]);
			}
			if (in_array('LIST_OF_MEMBERS', $select, true))
			{
				$groupFields['LIST_OF_MEMBERS'] = $this->getListOfMembers(
					$groupId,
					$groupItem->getScrumMaster()
				);
			}
			if (in_array('FEATURES', $select, true))
			{
				$groupFields['FEATURES'] = $this->prepareFeatures($groupId);
			}
			$needListOfAwaiting = in_array('LIST_OF_MEMBERS_AWAITING_INVITE', $select, true);
			$needMembersList = in_array('GROUP_MEMBERS_LIST', $select, true);
			if ($needListOfAwaiting || $needMembersList)
			{
				$permissions = Helper\Workgroup::getPermissions(
					['groupId' => $groupId],
				);
			}
			if ($needListOfAwaiting)
			{
				$groupFields['LIST_OF_MEMBERS_AWAITING_INVITE'] = [];
				if ($permissions['UserCanModifyGroup'] || $permissions['UserCanInitiate'])
				{
					$groupFields['LIST_OF_MEMBERS_AWAITING_INVITE'] = $this->getListOfAwaitingMembers($groupId);
				}
			}
			if ($needMembersList)
			{
				$groupFields['GROUP_MEMBERS_LIST'] = [];
				if ($permissions['UserCanModifyGroup'] || $permissions['UserCanInitiate'])
				{
					$membersManager = new MembersManager();
					$groupFields['GROUP_MEMBERS_LIST'] = $membersManager->getGroupMembersList($groupId);
				}
			}

			if (in_array('COUNTERS', $select, true))
			{
				$groupFields['COUNTERS'] = $this->getCounters($groupId);
			}

			if ($groupFields['NUMBER_OF_MEMBERS'])
			{
				$groupFields['NUMBER_OF_MEMBERS_PLURAL'] = Loc::getPluralForm($groupFields['NUMBER_OF_MEMBERS']);
			}
			if ($groupFields['PROJECT_DATE_START'] || $groupFields['PROJECT_DATE_FINISH'])
			{
				$culture = Context::getCurrent()->getCulture();
				$format = $culture->getDayMonthFormat();

				/** @var DateTime $dateStart */
				$dateStart = $groupFields['PROJECT_DATE_START'];
				/** @var DateTime $dateFinish */
				$dateFinish = $groupFields['PROJECT_DATE_FINISH'];

				if ($dateStart)
				{
					$groupFields['FORMATTED_PROJECT_DATE_START'] = FormatDate(
						$format,
						MakeTimeStamp(DateTime::createFromTimestamp($dateStart->getTimestamp()))
					);
				}
				if ($dateFinish)
				{
					$groupFields['FORMATTED_PROJECT_DATE_FINISH'] = FormatDate(
						$format,
						MakeTimeStamp(DateTime::createFromTimestamp($dateFinish->getTimestamp()))
					);
				}
			}

			if (
				isset($params['mode'])
				&& $params['mode'] === 'mobile'
			)
			{
				$additionalData = Helper\Workgroup::getAdditionalData([
					'ids' => [ $groupId ],
					'features' => ($params['features'] ?? []),
					'mandatoryFeatures' => ($params['mandatoryFeatures'] ?? []),
					'currentUserId' => (int)$this->getCurrentUser()->getId(),
				]);

				$groupFields['ADDITIONAL_DATA'] = ($additionalData[$groupId] ?? []) ;
			}

			$isScrum = !empty($groupFields['SCRUM_MASTER_ID']);
			if (!$isScrum && in_array('EFFICIENCY', $select, true) && Loader::includeModule('tasks'))
			{
				$efficiencies = Effective::getAverageEfficiencyForGroups(
					null,
					null,
					0,
					[$group['ID']],
				);

				$groupFields['EFFICIENCY'] = $efficiencies[$group['ID']] ?? null;
			}

			return $groupFields;
		}

		$this->addError(
			new Error(
				Loc::getMessage('SONET_CONTROLLER_WORKGROUP_NOT_FOUND'),
				'SONET_CONTROLLER_WORKGROUP_NOT_FOUND'
			)
		);

		return null;
	}

	public function listAction(
		PageNavigation $pageNavigation,
		array $filter = [],
		array $select = [],
		array $order = [],
		array $params = []
	)
	{
		if (
			empty($select)
			|| !is_array($select)
		)
		{
			$select = [ 'ID' ];
		}

		if (!in_array('ID', $select, true))
		{
			$select[] = 'ID';
		}

		$originalSelect = $select;

		if (
			$params['IS_ADMIN'] === 'Y'
			&& !\CSocNetUser::isCurrentUserModuleAdmin(SITE_ID, false)
		)
		{
			unset($params['IS_ADMIN']);
		}

		if ($params['IS_ADMIN'] !== 'Y')
		{
			$filter['CHECK_PERMISSIONS'] = $this->getCurrentUser()->getId();
		}

		$extranetSiteId = \CSocNetLogRestService::getExtranetSiteId();

		if (
			$extranetSiteId
			&& $params['IS_ADMIN'] !== 'Y'
			&& \CSocNetLogRestService::getCurrentUserType() === 'extranet'
		)
		{
			$filter['SITE_ID'] = $extranetSiteId;
		}
		else
		{
			$filter['SITE_ID'] = (string)($params['siteId'] ?? SITE_ID);
		}

		if (($key = array_search('AVATAR', $select, true)) !== false)
		{
			$select[] = 'IMAGE_ID';
			$select[] = 'AVATAR_TYPE';
			unset($select[$key]);
		}

		$workgroups = [];
		$count = 0;

		$queryIdFilter = [];

		$res = \CSocNetGroup::getList([], $filter, false, false, [ 'ID' ]);
		while ($groupFields = $res->fetch())
		{
			$queryIdFilter[] = (int)$groupFields['ID'];
		}

		if (!empty($queryIdFilter))
		{
			$select = $this->prepareSelect($select);

			$query = WorkgroupTable::query();
			$query
				->setSelect($select)
				->setOrder($order)
				->setOffset($pageNavigation->getOffset())
				->setLimit(($pageNavigation->getLimit()))
				->setFilter([
					'ID' => $queryIdFilter,
				])
				->countTotal(true);

			$res = $query->exec();

			$avatarTypes = Helper\Workgroup::getAvatarTypes();

			while ($groupFields = $res->fetch())
			{
				if (in_array('AVATAR', $originalSelect, true))
				{
					if ((int)$groupFields['IMAGE_ID'] > 0)
					{
						$groupFields['AVATAR'] = File::getFileSource((int)$groupFields['IMAGE_ID'], 100, 100);
					}
					elseif (
						!empty($groupFields['AVATAR_TYPE'])
						&& isset($params['mode'])
						&& $params['mode'] === 'mobile'
					)
					{
						$groupFields['AVATAR'] = $avatarTypes[$groupFields['AVATAR_TYPE']]['mobileUrl'];
					}
					else
					{
						$groupFields['AVATAR'] = '';
					}
				}

				$workgroups[(int)$groupFields['ID']] = $groupFields;
			}

			$count = $res->getCount();
		}

		$ids = array_keys($workgroups);

		if (
			isset($params['mode'])
			&& $params['mode'] === 'mobile'
		)
		{
			$additionalData = Helper\Workgroup::getAdditionalData([
				'ids' => $ids,
				'features' => ($params['features'] ?? []),
				'mandatoryFeatures' => ($params['mandatoryFeatures'] ?? []),
				'currentUserId' => (int)$this->getCurrentUser()->getId(),
			]);

			foreach (array_keys($workgroups) as $id)
			{
				if (!isset($additionalData[$id]))
				{
					continue;
				}

				$workgroups[$id]['ADDITIONAL_DATA'] = ($additionalData[$id] ?? []) ;
			}
		}

		if (($params['shouldSelectDialogId'] ?? 'N') === 'Y')
		{
			$chatData = Chat\Workgroup::getChatData([
				'group_id' => $ids,
				'skipAvailabilityCheck' => true,
			]);

			foreach ($workgroups as $id => $fields)
			{
				$workgroups[$id]['DIALOG_ID'] = Dialog::getDialogId($chatData[$id] ?? 0);
			}
		}

		$workgroups = $this->convertKeysToCamelCase($workgroups);

		return new Engine\Response\DataType\Page('workgroups', array_values($workgroups), $count);
	}

	/**
	 * @restMethod socialnetwork.api.workgroup.isExistingGroup
	 */
	public function isExistingGroupAction(string $name): array
	{
		return [
			'exists' => GroupProvider::getInstance()->isExistingGroup($name),
		];
	}

	private function prepareSelect(array $select = []): array
	{
		return array_filter($select, static function ($key) {
			return in_array(mb_strtoupper($key), static::getAllowedSelectFields(), true);
		});
	}

	private function getAvatarData(int $imageId, string $avatarType): array
	{
		$avatarManager = new AvatarManager();

		if ($imageId)
		{
			$avatarData = $avatarManager->getImageAvatar($imageId)->toArray();
		}
		else
		{
			$avatarData = $avatarManager->getIconAvatar($avatarType)->toArray();
		}

		return $avatarData;
	}

	private function getOwnerData(int $ownerId): array
	{
		$owner = UserTable::getList([
			'select' => ['NAME', 'LAST_NAME', 'SECOND_NAME', 'LOGIN', 'PERSONAL_PHOTO'],
			'filter' => ['ID' => $ownerId],
		])->fetch();

		return [
			'ID' => $ownerId,
			'PHOTO' => ($owner['PERSONAL_PHOTO'] ? File::getFileSource($owner['PERSONAL_PHOTO']) : null),
			'FORMATTED_NAME' => htmlspecialcharsback(
				\CUser::FormatName(
					\CSite::getNameFormat(),
					[
						'NAME' => $owner['NAME'],
						'LAST_NAME' => $owner['LAST_NAME'],
						'SECOND_NAME' => $owner['SECOND_NAME'],
						'LOGIN' => $owner['LOGIN'],
					],
					true
				)
			),
		];
	}

	private function getSubjectData(int $subjectId): array
	{
		$subject = WorkgroupSubjectTable::getList([
			'select' => ['NAME'],
			'filter' => ['ID' => $subjectId],
		])->fetch();

		return [
			'ID' => $subjectId,
			'NAME' => $subject['NAME'],
		];
	}

	private function getTags(int $groupId): array
	{
		$tags = WorkgroupTagTable::getList([
			'select' => ['NAME'],
			'filter' => ['GROUP_ID' => $groupId],
		])->fetchAll();

		return array_map(
			static function($tag) {
				return htmlspecialcharsback($tag);
			},
			array_column($tags, 'NAME')
		);
	}

	private function getThemeData(int $groupId): ?array
	{
		if (!Loader::includeModule('intranet'))
		{
			return [];
		}

		$themePicker = new ThemePicker(
			SITE_TEMPLATE_ID,
			false,
			$this->getCurrentUser()->getId(),
			ThemePicker::ENTITY_TYPE_SONET_GROUP,
			$groupId
		);

		$themeUserId = false;
		$themeId = $themePicker->getCurrentThemeId();
		if ($themeId)
		{
			$res = ThemeTable::getList([
				'select' => ['USER_ID'],
				'filter' => [
					'=ENTITY_TYPE' => $themePicker->getEntityType(),
					'ENTITY_ID' => $themePicker->getEntityId(),
					'=CONTEXT' => $themePicker->getContext(),
				],
			]);
			if (($themeFields = $res->fetch()) && (int)$themeFields['USER_ID'] > 0)
			{
				$themeUserId = (int)$themeFields['USER_ID'];
			}
		}

		return $themePicker->getTheme($themeId, $themeUserId);
	}

	private function getActions(int $groupId): array
	{
		$permissions = Helper\Workgroup::getPermissions(['groupId' => $groupId]);

		$canEditFeatures = $permissions['UserCanModifyGroup'];
		if (!\Bitrix\Socialnetwork\Helper\Workgroup::getEditFeaturesAvailability())
		{
			$canEditFeatures = false;
		}

		return [
			'EDIT' => $permissions['UserCanModifyGroup'],
			'DELETE' => $permissions['UserCanModifyGroup'],
			'INVITE' => $permissions['UserCanInitiate'],
			'JOIN' => (
				!$permissions['UserIsMember']
				&& !$permissions['UserRole']
			),
			'LEAVE' => (
				$permissions['UserIsMember']
				&& !$permissions['UserIsAutoMember']
				&& !$permissions['UserIsOwner']
				&& !$permissions['UserIsScrumMaster']
			),
			'FOLLOW' => $permissions['UserIsMember'],
			'PIN' => $permissions['UserIsMember'],
			'EDIT_FEATURES' => $canEditFeatures,
		];
	}

	private function getUserData(int $groupId): array
	{
		$permissions = Helper\Workgroup::getPermissions(['groupId' => $groupId]);

		return [
			'ROLE' => $permissions['UserRole'],
			'INITIATED_BY_TYPE' => $permissions['InitiatedByType'],
			'IS_SUBSCRIBED' => (
				in_array($permissions['UserRole'], UserToGroupTable::getRolesMember(), true)
				&& \CSocNetSubscription::isUserSubscribed($this->getCurrentUser()->getId(), 'SG' . $groupId)
			),
		];
	}

	private function getDepartments($ufDepartments): array
	{
		$departments = [];

		if (
			empty($ufDepartments)
			|| !is_array($ufDepartments)
			|| !Loader::includeModule('intranet')
		)
		{
			return $departments;
		}

		$departmentsList = \CIntranetUtils::getDepartmentsData($ufDepartments);
		if (empty($departmentsList))
		{
			return $departments;
		}

		foreach ($departmentsList as $id => $name)
		{
			if (($id = (int)$id) <= 0)
			{
				continue;
			}

			$departments[] = [
				'ID' => $id,
				'NAME' => $name,
			];
		}

		return $departments;
	}

	private function isPin(int $groupId, int $currentUserId, string $context = ''): bool
	{
		$query = new Query(WorkgroupPinTable::getEntity());

		$query = $query
			->setSelect([
				'ID',
				'GROUP_ID',
				'USER_ID',
			])
			->where('GROUP_ID', $groupId)
			->where('USER_ID', $currentUserId)
		;
		if ($context === '')
		{
			$query = $query->where(Query::filter()
				->logic('or')
				->whereNull('CONTEXT')
				->where('CONTEXT', '')
			);
		}
		else
		{
			$query = $query->where('CONTEXT', $context);
		}

		$pin = $query->setLimit(1)->exec()->fetchObject();

		return (bool) $pin;
	}

	private function getListOfMembers(int $groupId, int $scrumMasterId): array
	{
		$list = [];

		$records = UserToGroupTable::query()
			->setSelect([
				'GROUP_ID',
				'USER_ID',
				'ROLE',
				'INITIATED_BY_TYPE',
				'AUTO_MEMBER',
				'NAME' => 'USER.NAME',
				'LAST_NAME' => 'USER.LAST_NAME',
				'SECOND_NAME' => 'USER.SECOND_NAME',
				'WORK_POSITION' => 'USER.WORK_POSITION',
				'LOGIN' => 'USER.LOGIN',
				'PERSONAL_PHOTO' => 'USER.PERSONAL_PHOTO',
			])
			->whereIn('GROUP_ID', $groupId)
			->whereIn('ROLE', UserToGroupTable::getRolesMember())
			->exec()->fetchCollection()
		;

		$members = [];
		$imageIdList = [];
		foreach ($records as $record)
		{
			$user = $record->get('USER');
			$imageIdList[$record->get('USER_ID')] = $user->get('PERSONAL_PHOTO');
			$members[] = $record;
		}
		$imageIdList = array_filter(
			$imageIdList,
			static function ($id) {
				return (int) $id > 0;
			}
		);
		$avatars = $this->getUserAvatars($imageIdList);

		foreach ($members as $member)
		{
			$memberId = (int) $member['USER_ID'];

			$isOwner = ($member['ROLE'] === UserToGroupTable::ROLE_OWNER);
			$isModerator = ($member['ROLE'] === UserToGroupTable::ROLE_MODERATOR);
			$isScrumMaster = ($scrumMasterId === $memberId);
			$memberUser = $member->getUser();

			$list[] = [
				'id' => $memberId,
				'isOwner' => $isOwner,
				'isModerator' => $isModerator,
				'isScrumMaster' => $isScrumMaster,
				'isAutoMember' => $member['AUTO_MEMBER'],
				'name' => $memberUser->getName(),
				'lastName' => $memberUser->getLastName(),
				'position' => $memberUser->getWorkPosition(),
				'photo' => ($avatars[($imageIdList[$memberId] ?? '')] ?? ''),
			];
		}

		return $list;
	}

	private function prepareFeatures(int $groupId): array
	{
		$features = [];

		$baseFeatures = $this->getBaseFeatures($groupId);

		foreach ($this->getAllowedFeatures() as $featureId => $feature)
		{
			if (array_key_exists($featureId, $baseFeatures))
			{
				$features[] = [
					'featureName' => $featureId,
					'name' => Loc::getMessage('SOCIALNETWORK_WORKGROUP_'.strtoupper($featureId)),
					'customName' => $baseFeatures[$featureId]['FEATURE_NAME'] ?? '',
					'id' => $baseFeatures[$featureId]['ID'],
					'active' => $baseFeatures[$featureId]['ACTIVE'] === 'Y',
				];
			}
		}

		return $features;
	}

	private function getBaseFeatures(int $groupId): array
	{
		$features = [];

		$queryObject = \CSocNetFeatures::getList(
			[],
			[
				'ENTITY_ID' => $groupId,
				'ENTITY_TYPE' => SONET_ENTITY_GROUP,
			]
		);
		while ($featureFields = $queryObject->fetch())
		{
			$features[$featureFields['FEATURE']]= $featureFields;
		}

		return $features;
	}

	private function getAllowedFeatures(): array
	{
		$allowedFeatures = \CSocNetAllowed::getAllowedFeatures();

		$sampleKeysList = [
			'tasks' => 1,
			'calendar' => 2,
			'files' => 3,
			'chat' => 4,
			'forum' => 5,
			'microblog' => 6,
			'blog' => 7,
			'photo' => 8,
			'group_lists' => 9,
			'wiki' => 10,
			'content_search' => 11,
			'marketplace' => 12,
		];

		uksort($allowedFeatures, static function($a, $b) use ($sampleKeysList) {

			$valA = ($sampleKeysList[$a] ?? 100);
			$valB = ($sampleKeysList[$b] ?? 100);

			if ($valA > $valB)
			{
				return 1;
			}

			if ($valA < $valB)
			{
				return -1;
			}

			return 0;
		});

		return array_filter($allowedFeatures, function($feature) {
			return (
				is_array($feature['allowed'])
				&& in_array(SONET_ENTITY_GROUP, $feature['allowed'], true)
			);
		});
	}

	private function getListOfAwaitingMembers(int $groupId, int $limit = 10, int $offset = 0): array
	{
		$list = [];

		$records = UserToGroupTable::query()
			->setSelect([
				'GROUP_ID',
				'USER_ID',
				'ROLE',
				'INITIATED_BY_TYPE',
				'NAME' => 'USER.NAME',
				'LAST_NAME' => 'USER.LAST_NAME',
				'SECOND_NAME' => 'USER.SECOND_NAME',
				'LOGIN' => 'USER.LOGIN',
				'PERSONAL_PHOTO' => 'USER.PERSONAL_PHOTO',
			])
			->whereIn('GROUP_ID', $groupId)
			->where('INITIATED_BY_TYPE', UserToGroupTable::INITIATED_BY_USER)
			->where('ROLE', UserToGroupTable::ROLE_REQUEST)
			->setLimit($limit)
			->setOffset($offset)
			->exec()->fetchCollection()
		;

		$members = [];
		$imageIdList = [];
		foreach ($records as $record)
		{
			$user = $record->get('USER');
			$imageIdList[$record->get('USER_ID')] = $user->get('PERSONAL_PHOTO');

			$members[] = $record;
		}
		$imageIdList = array_filter(
			$imageIdList,
			static function ($id) {
				return (int) $id > 0;
			}
		);
		$avatars = $this->getUserAvatars($imageIdList);

		foreach ($members as $member)
		{
			$memberId = (int) $member['USER_ID'];

			$userNameFormatted = \CUser::formatName(\CSite::getNameFormat(), [
				'NAME' => $member->get('USER')->get('NAME'),
				'LAST_NAME' => $member->get('USER')->get('LAST_NAME'),
				'SECOND_NAME' => $member->get('USER')->get('SECOND_NAME'),
				'LOGIN' => $member->get('USER')->get('LOGIN'),
			], ModuleManager::isModuleInstalled('intranet'));

			$list[] = [
				'id' => $memberId,
				'name' => $userNameFormatted,
				'photo' => ($avatars[($imageIdList[$memberId] ?? '')] ?? ''),
			];
		}

		return $list;
	}

	private function getCounters(int $groupId): array
	{
		$counters = [];

		$counterProvider = Counter::getInstance($this->getCurrentUser()->getId());

		$availableCounters = [
			CounterDictionary::COUNTER_WORKGROUP_REQUESTS_OUT,
			CounterDictionary::COUNTER_WORKGROUP_REQUESTS_IN,
		];
		foreach ($availableCounters as $counter)
		{
			$counters[$counter] = $counterProvider->get($counter, $groupId)['all'];
		}

		return $counters;
	}

	public function updateAction(int $groupId, array $fields = []): ?bool
	{
		if (!Helper\Workgroup\Access::canModify([
			'groupId' => $groupId,
			'checkAdminSession' => ($this->getScope() !== Controller::SCOPE_REST),
		]))
		{
			$this->addEmptyGroupIdError();
			return null;
		}

		$whiteList = [
			'NAME',
			'DESCRIPTION',
			'KEYWORDS',
			'VISIBLE',
			'OPENED',
			'EXTERNAL',
		];

		foreach ($fields as $key => $value)
		{
			if (!in_array($key, $whiteList, true))
			{
				unset($fields[$key]);
			}
		}

		if (
			empty($fields)
		)
		{
			$this->addError(new Error(
				Loc::getMessage('SONET_CONTROLLER_WORKGROUP_ACTION_FAILED'),
				'SONET_CONTROLLER_WORKGROUP_ACTION_FAILED')
			);
			return null;
		}

		try
		{
			$result = \CSocNetGroup::update($groupId, $fields);
		}
		catch (Exception $e)
		{
			$this->addError(new Error($e->getMessage(), $e->getCode()));
			return null;
		}

		if (!$result)
		{
			$this->addError(new Error(
				Loc::getMessage('SONET_CONTROLLER_WORKGROUP_ACTION_FAILED'),
				'SONET_CONTROLLER_WORKGROUP_ACTION_FAILED')
			);
			return null;
		}

		$this->sendPush(PushEventDictionary::EVENT_WORKGROUP_UPDATE, [
			'params' => [
				'GROUP_ID' => $groupId,
			],
		]);

		return true;
	}

	public function leaveAction(int $groupId)
	{
		if (!Helper\Workgroup\Access::canLeave([ 'groupId' => $groupId ]))
		{
			$this->addError(new Error('NO PERMISSION'));
			return null;
		}

		return \CSocNetUserToGroup::DeleteRelation($this->userId, $groupId);
	}

	public function deleteAction(int $groupId)
	{
		if (
			!Helper\Workgroup\Access::canModify([
				'groupId' => $groupId,
				'checkAdminSession' => ($this->getScope() !== Controller::SCOPE_REST),
			])
		)
		{
			$this->addEmptyGroupIdError();

			return null;
		}

		global $APPLICATION;

		$deleteResult = \CSocNetGroup::Delete($groupId);
		if (!$deleteResult && ($e = $APPLICATION->GetException()))
		{
			return $e->GetString();
		}

		return true;
	}

	public function getAvatarTypesAction(): array
	{
		return Helper\Workgroup::getAvatarTypes();
	}

	public function disconnectDepartmentsAction(int $groupId, array $departmentIds)
	{
		foreach ($departmentIds as $id)
		{
			Helper\Workgroup::disconnectDepartment([
				'groupId' => $groupId,
				'departmentId' => $id,
			]);
		}
	}

	public function setFavoritesAction(array $params = []): ?array
	{
		$groupId = (int)($params['groupId'] ?? 0);
		$getAdditionalResultData = (bool)($params['getAdditionalResultData'] ?? false);

		if ($groupId <= 0)
		{
			$this->addEmptyGroupIdError();
			return null;
		}

		if (!in_array($params['value'] ?? null, WorkgroupFavorites::AVAILABLE_VALUES, true))
		{
			$this->addIncorrectValueError();
			return null;
		}

		try
		{
			$res = WorkgroupFavorites::set([
				'GROUP_ID' => $groupId,
				'USER_ID' => $this->getCurrentUser()->getId(),
				'VALUE' => $params['value'],
			]);
		}
		catch (Exception $e)
		{
			$this->addError(new Error($e->getMessage(), $e->getCode()));
			return null;
		}

		if (!$res)
		{
			$this->addError(new Error(Loc::getMessage('SONET_CONTROLLER_WORKGROUP_ACTION_FAILED'), 'SONET_CONTROLLER_WORKGROUP_ACTION_FAILED'));
			return null;
		}

		$result = [
			'ID' => $groupId,
			'RESULT' => $params['value'],
		];

		if ($getAdditionalResultData)
		{
			$groupItem = \Bitrix\Socialnetwork\Item\Workgroup::getById($groupId);
			$groupFields = $groupItem->getFields();
			$groupUrlData = $groupItem->getGroupUrlData([
				'USER_ID' => $this->getCurrentUser()->getId(),
			]);

			$groupSiteList = [];
			$resSite = WorkgroupSiteTable::getList([
				'filter' => [
					'=GROUP_ID' => $groupId
				],
				'select' => [ 'SITE_ID' ],
			]);
			while ($groupSite = $resSite->fetch())
			{
				$groupSiteList[] = $groupSite['SITE_ID'];
			}

			$result['NAME'] = $groupFields['NAME'];
			$result['URL'] = $groupUrlData["URL"];
			$result['EXTRANET'] = (
			Loader::includeModule('extranet')
			&& CExtranet::isIntranetUser()
			&& in_array(CExtranet::getExtranetSiteId(), $groupSiteList, true)
				? 'Y'
				: 'N'
			);
		}

		$this->sendPush(PushEventDictionary::EVENT_WORKGROUP_FAVORITES_CHANGED, ['GROUP_ID' => $groupId]);

		return $result;
	}

	public function setSubscriptionAction(array $params = []): ?array
	{
		$groupId = (int)($params['groupId'] ?? 0);
		if ($groupId <= 0)
		{
			$this->addEmptyGroupIdError();
			return null;
		}

		if (!in_array($params['value'] ?? null, Subscription::AVAILABLE_VALUES, true))
		{
			$this->addIncorrectValueError();
			return null;
		}

		try
		{
			$result = Subscription::set([
				'GROUP_ID' => $groupId,
				'USER_ID' => $this->getCurrentUser()->getId(),
				'VALUE' => $params['value'],
			]);
		}
		catch (Exception $e)
		{
			$this->addError(new Error($e->getMessage(), $e->getCode()));
			return null;
		}

		$this->sendPush(PushEventDictionary::EVENT_WORKGROUP_SUBSCRIBE_CHANGED, ['GROUP_ID' => $groupId]);

		return [
			'RESULT' => $result ? 'Y' : 'N',
		];
	}

	public function updatePhotoAction(): bool
	{
		$groupId = $this->getRequest()->get('groupId');

		if (!Helper\Workgroup\Access::canUpdate([ 'groupId' => $groupId ]))
		{
			$this->addError(new Error('SOCIALNETWORK_GROUP_AJAX_NO_UPDATE_PERMS'));
			return false;
		}

		$workgroupData = WorkgroupTable::getList([
			'select' => [ 'ID', 'IMAGE_ID' ],
			'filter' => [
				'=ID' => $groupId,
			],
		])->fetch();

		$newPhotoFile = $this->getRequest()->getFile('newPhoto');

		if ($workgroupData['IMAGE_ID'])
		{
			$newPhotoFile['old_file'] = $workgroupData['IMAGE_ID'];
			$newPhotoFile['del'] = $workgroupData['IMAGE_ID'];
		}

		$res = \CSocNetGroup::update(
			$groupId,
			[ 'IMAGE_ID' => $newPhotoFile ],
			true,
			true,
			false
		);

		if (!$res)
		{
			$this->addError(new Error('SOCIALNETWORK_GROUP_AJAX_FAILED'));
			return false;
		}

		$this->sendPush(PushEventDictionary::EVENT_WORKGROUP_UPDATE, [
			'params' => [
				'GROUP_ID' => $groupId,
			],
		]);

		return true;
	}

	public function createGroupAction(): array
	{
		$groupName = $this->getRequest()->get('groupName');
		$viewMode = $this->getRequest()->get('viewMode');
		$groupImage = $this->getRequest()->getFile('groupImage');
		$avatarColor = $this->getRequest()->get('avatarColor');

		if (!Helper\Workgroup\Access::canCreate())
		{
			return ['groupId' => 0];
		}

		$ownerId = $this->getCurrentUser()->getId();

		$groupParams = [
			'SITE_ID' => [SITE_ID],
			'NAME' => $groupName,
			'SUBJECT_ID' => $this->getDefaultSubjectId(),
			'INITIATE_PERMS' => SONET_ROLES_USER,
			'SPAM_PERMS' => SONET_ROLES_USER,
			'VISIBLE' => $viewMode !== 'secret' ? 'Y' : 'N',
			'OPENED' => $viewMode === 'open' ? 'Y' : 'N',
		];

		if (is_array($groupImage))
		{
			try
			{
				$avatarManager = new AvatarManager();
				$result = $avatarManager->loadAvatar($groupImage);
				$groupParams['IMAGE_ID'] = $avatarManager->getAvatar($result['fileId']);
			}
			catch (\RuntimeException)
			{
				unset($groupParams['IMAGE_ID']);
			}
		}

		if (!isset($groupParams['IMAGE_ID']))
		{
			$groupParams['AVATAR_TYPE'] = $this->getColoredDefaultAvatar($avatarColor);
		}

		$groupId = (int)\CSocNetGroup::createGroup($ownerId, $groupParams);

		global $APPLICATION;
		if ($e = $APPLICATION->GetException())
		{
			$this->addError(new Error($e->msg, $e->id));
			return [];
		}

		$this->setDefaultGroupFeatures($groupId);

		return [
			'groupId' => $groupId,
		];
	}

	/**
	 * The method will enable trial mode for projects or scrum.
	 *
	 * @param bool $scrum If you need to create a trial for scrum.
	 * @return bool
	 */
	public function turnOnTrialAction(bool $scrum = false): bool
	{
		if (!Helper\Workgroup\Access::canCreate())
		{
			$this->addError(new Error('Access denied'));

			return false;
		}

		$feature = $scrum ? Helper\Feature::SCRUM_CREATE : Helper\Feature::PROJECTS_GROUPS;

		if (
			!Helper\Feature::isFeatureEnabled($feature)
			&& Helper\Feature::canTurnOnTrial($feature)
		)
		{
			Helper\Feature::turnOnTrial($feature);

			return true;
		}
		else
		{
			$this->addError(new Error('Already included'));

			return false;
		}
	}

	private function getColoredDefaultAvatar(string $color): string
	{
		if (in_array($color, Helper\Workgroup::getAvatarColors(), true))
		{
			return "space_$color";
		}

		return array_rand(Helper\Workgroup::getColoredAvatarTypes());
	}

	private function setDefaultGroupFeatures(int $groupId): void
	{
		$allowedFeatures = array_keys(\CSocNetAllowed::getAllowedFeatures());
		$inactiveFeaturesList = ['forum', 'photo', 'search', 'group_lists', 'wiki'];

		$features = [];
		foreach ($allowedFeatures as $featureName)
		{
			$features[$featureName] = !in_array($featureName, $inactiveFeaturesList, true);
		}

		foreach ($features as $featureName => $isActive)
		{
			\CSocNetFeatures::setFeature(
				SONET_ENTITY_GROUP,
				$groupId,
				$featureName,
				$isActive,
			);
		}
	}

	private function getDefaultSubjectId(): int
	{
		$subject = \CSocNetGroupSubject::GetList(
			["SORT"=>"ASC", "NAME" => "ASC"],
			["SITE_ID" => SITE_ID],
			false,
			false,
			["ID", "NAME"],
		)->fetch();

		return (int)($subject['ID'] ?? 0);
	}

	public function getCanCreateAction(): bool
	{
		return Helper\Workgroup\Access::canCreate([
			'checkAdminSession' => ($this->getScope() !== Controller::SCOPE_REST),
		]);
	}

	public function updateInvitedUsersAction(int $spaceId, array $users): void
	{
		$membersManager = new MembersManager();

		if (!$membersManager->canInviteUsers($spaceId))
		{
			return;
		}

		$membersManager->updateInvitedUsers($spaceId, array_map(static fn($userId) => (int)$userId, $users));
	}

	public function getGridPopupMembersAction(
		int $groupId,
		string $type,
		int $page,
		string $componentName = '',
		string $signedParameters = ''
	): ?array
	{
		if ($groupId <= 0)
		{
			$this->addEmptyGroupIdError();

			return null;
		}

		if (
			!Helper\Workgroup\Access::canView([
				'groupId' => $groupId,
				'checkAdminSession' => ($this->getScope() !== Controller::SCOPE_REST),
			])
		)
		{
			$this->addError(new Error('Access denied'));

			return null;
		}

		$unsignedParameters = [];
		if (
			$componentName !== ''
			&& $signedParameters !== ''
		)
		{
			$unsignedParameters = \Bitrix\Main\Component\ParameterSigner::unsignParameters(
				$componentName,
				$signedParameters
			);
			if (!is_array($unsignedParameters))
			{
				$unsignedParameters = [];
			}
		}

		$rolesMap = [
			'all' => [
				UserToGroupTable::ROLE_OWNER,
				UserToGroupTable::ROLE_MODERATOR,
				UserToGroupTable::ROLE_USER,
			],
			'heads' => [
				UserToGroupTable::ROLE_OWNER,
				UserToGroupTable::ROLE_MODERATOR,
			],
			'members' => [
				UserToGroupTable::ROLE_USER,
			],
			'scrumTeam' => [
				UserToGroupTable::ROLE_OWNER,
				UserToGroupTable::ROLE_MODERATOR,
			],
		];
		$limit = 10;

		$query = UserToGroupTable::query();
		$records = $query
			->setSelect([
				'GROUP_ID',
				'GROUP',
				'USER_ID',
				'ROLE',
				'INITIATED_BY_TYPE',
				'AUTO_MEMBER',
				'NAME' => 'USER.NAME',
				'LAST_NAME' => 'USER.LAST_NAME',
				'SECOND_NAME' => 'USER.SECOND_NAME',
				'LOGIN' => 'USER.LOGIN',
				'PERSONAL_PHOTO' => 'USER.PERSONAL_PHOTO',
			])
			->where('GROUP_ID', $groupId)
			->whereIn('ROLE', $rolesMap[$type])
			->setLimit($limit)
			->setOffset(($page - 1) * $limit)
			->exec()->fetchCollection();

		$isScrumMembers = ($type === 'scrumTeam');
		if ($isScrumMembers)
		{
			$query->addSelect('GROUP.SCRUM_MASTER_ID', 'SCRUM_MASTER_ID');
		}

		$imageIds = [];
		$resultMembers = [];

		foreach ($records as $member)
		{
			$imageIds[$member->get('USER_ID')] = $member->get('USER')->get('PERSONAL_PHOTO');
			$resultMembers[] = $member;
		}

		$imageIds = array_filter(
			$imageIds,
			static function ($id) { return (int)$id > 0; }
		);
		$avatars = Helper\UI\Grid\Workgroup\Members::getUserAvatars($imageIds);
		$pathToUser = ($unsignedParameters['PATH_TO_USER'] ?? Helper\Path::get('user_profile'));
		$userNameTemplate = ($unsignedParameters['NAME_TEMPLATE'] ?? \CSite::getNameFormat());
		$isIntranetInstalled = ModuleManager::isModuleInstalled('intranet');

		$members = [];

		foreach ($resultMembers as $member)
		{
			$id = $member->get('USER_ID');
			$userNameFormatted = \CUser::formatName($userNameTemplate, [
				'NAME' => $member->get('USER')->get('NAME'),
				'LAST_NAME' => $member->get('USER')->get('LAST_NAME'),
				'SECOND_NAME' => $member->get('USER')->get('SECOND_NAME'),
				'LOGIN' => $member->get('USER')->get('LOGIN'),
			], $isIntranetInstalled);

			$userUrl = \CComponentEngine::makePathFromTemplate($pathToUser, [
				'user_id' => $id,
				'id' => $id,
			]);

			$members[] = [
				'ID' => $id,
				'PHOTO' => $avatars[$imageIds[$id] ?? null] ?? '',
				'HREF' => $userUrl,
				'FORMATTED_NAME' => $userNameFormatted,
				'ROLE' => ($isScrumMembers ? $this->getScrumRole($member) : $member->get('ROLE')),
			];

			if ($isScrumMembers)
			{
				if (
					$member->get('ROLE') === UserToGroupTable::ROLE_OWNER
					&& $member->get('USER_ID') === $member->get('GROUP')->get('SCRUM_MASTER_ID')
				)
				{
					$members[] = [
						'ID' => $id,
						'PHOTO' => $avatars[$imageIds[$id] ?? null] ?? '',
						'HREF' => $userUrl,
						'FORMATTED_NAME' => $userNameFormatted,
						'ROLE' => 'M',
					];
				}
			}
		}

		return $members;
	}

	private function getScrumRole(EO_UserToGroup $member): string
	{
		if (
			$member->get('USER_ID') === $member->get('GROUP')->get('SCRUM_MASTER_ID')
			&& $member->get('ROLE') !== UserToGroupTable::ROLE_OWNER
		)
		{
			return 'M';
		}

		return $member->get('ROLE');
	}

	/**
	 * @restMethod socialnetwork.api.workgroup.changePin
	 */
	public function changePinAction(
		array $groupIdList,
		string $action,
		string $componentName = '',
		string $signedParameters = ''
	): ?bool
	{
		$unsignedParameters = [];
		if (
			$componentName !== ''
			&& $signedParameters !== ''
		)
		{
			$unsignedParameters = \Bitrix\Main\Component\ParameterSigner::unsignParameters($componentName, $signedParameters);
			if (!is_array($unsignedParameters))
			{
				$unsignedParameters = [];
			}
		}

		$mode = ($unsignedParameters['MODE'] ?? '');

		$counter = 0;

		foreach ($groupIdList as $groupId)
		{
			$groupId = (int)$groupId;

			if (
				$groupId <= 0
				|| !Helper\Workgroup\Access::canView([
					'groupId' => $groupId,
				])
			)
			{
				continue;
			}

			$counter++;

			$pin = new Pin($this->userId, $groupId, $mode);
			$result = $pin->switch();

			if (!$result->isSuccess())
			{
				$this->addErrors($result->getErrors());
				return null;
			}

			$this->sendPush(PushEventDictionary::EVENT_WORKGROUP_PIN_CHANGED, [
					'GROUP_ID' => $groupId,
					'ACTION' => $action,
				]
			);
		}

		if ($counter <= 0)
		{
			$this->addEmptyGroupIdError();
			return null;
		}

		return true;
	}

	public function acceptIncomingRequestAction(int $groupId, array $userIds): ?array
	{
		try
		{
			$result = [];

			foreach ($userIds as $userId)
			{
				$result[$userId] = Helper\Workgroup::acceptIncomingRequest([
					'groupId' => $groupId,
					'userId' => $userId,
				]);
			}

			// re-calculte counters for the group moderators
			$moderators = UserToGroupTable::getGroupModerators($groupId);
			Service::addEvent(
				EventDictionary::EVENT_WORKGROUP_MEMBER_REQUEST_CONFIRM,
				[
					'GROUP_ID' => $groupId,
					'RECEPIENTS' => array_map(function ($row) { return $row['USER_ID']; }, $moderators),
				]
			);

			return $result;
		}
		catch (Exception $e)
		{
			$this->addError(new Error($e->getMessage()));

			return null;
		}
	}

	public function rejectIncomingRequestAction(int $groupId, array $userIds): ?array
	{
		try
		{
			$result = [];

			foreach ($userIds as $userId)
			{
				$result[$userId] = Helper\Workgroup::rejectIncomingRequest([
					'groupId' => $groupId,
					'userId' => $userId,
				]);
			}

			// re-calculte counters for the group moderators
			$moderators = UserToGroupTable::getGroupModerators($groupId);
			Service::addEvent(
				EventDictionary::EVENT_WORKGROUP_MEMBER_REQUEST_CONFIRM,
				[
					'GROUP_ID' => $groupId,
					'RECEPIENTS' => array_map(function ($row) { return $row['USER_ID']; }, $moderators),
				]
			);

			return $result;
		}
		catch (Exception $e)
		{
			$this->addError(new Error($e->getMessage()));

			return null;
		}
	}

	public function getListIncomingUsersAction(int $groupId, int $pageNum): ?array
	{
		$permissions = Helper\Workgroup::getPermissions(
			['groupId' => $groupId]
		);
		if (!$permissions['UserCanModifyGroup'] && !$permissions['UserCanInitiate'])
		{
			$this->addError(new Error('Access denied'));

			return null;
		}

		$limit = 10;
		$offset = ($pageNum - 1) * $limit;

		return $this->getListOfAwaitingMembers($groupId, $limit, $offset);
	}

	public function getChatIdAction(int $groupId): ?string
	{
		$chatId = '';

		if (!Loader::includeModule('im'))
		{
			return $chatId;
		}

		$chatData = \Bitrix\Socialnetwork\Integration\Im\Chat\Workgroup::getChatData(
			[
				'group_id' => $groupId,
				'skipAvailabilityCheck' => true,
			]
		);
		if (!empty($chatData[$groupId]) && intval($chatData[$groupId]) > 0)
		{
			$chatId = $chatData[$groupId];
		}
		else
		{
			$chatId = \Bitrix\Socialnetwork\Integration\Im\Chat\Workgroup::createChat(
				[
					'group_id' => $groupId,
				]
			);
		}

		return $chatId;
	}

	public function setFeatureAction(int $groupId, array $feature): bool
	{
		if (
			!Helper\Workgroup\Access::canModify([
				'groupId' => $groupId,
				'checkAdminSession' => ($this->getScope() !== Controller::SCOPE_REST),
			])
		)
		{
			$this->addEmptyGroupIdError();

			return false;
		}

		$allowedFeatures = array_keys(\CSocNetAllowed::getAllowedFeatures());

		$featureId = is_string($feature['featureName'] ?? null) ? $feature['featureName'] : '';
		$customName = is_string($feature['customName'] ?? null) ? $feature['customName'] : false;
		$featureActive = is_string($feature['active'] ?? null) && $feature['active'] === 'true';

		$activeFeatures = \CSocNetFeatures::GetActiveFeatures(SONET_ENTITY_GROUP, $groupId);

		if (in_array($featureId, $allowedFeatures, true))
		{
			\CSocNetFeatures::setFeature(
				SONET_ENTITY_GROUP,
				$groupId,
				$featureId,
				$featureActive,
				$customName,
			);
		}

		$action = '';

		if ($featureActive === in_array($featureId ,$activeFeatures))
		{
			$action = 'change';
		}

		if ($featureActive && !in_array($featureId ,$activeFeatures))
		{
			$action = 'add';
		}

		if (!$featureActive && in_array($featureId ,$activeFeatures))
		{
			$action = 'delete';
		}

		$this->sendPush(PushEventDictionary::EVENT_SPACE_FEATURE_CHANGE, [
				'GROUP_ID' => $groupId,
				'FEATURE' => $feature,
				'ACTION' => $action,
			]
		);

		return true;
	}

	private function getUserAvatars(array $imageIds): array
	{
		$result = [];
		if (empty($imageIds))
		{
			return $result;
		}

		$result = array_fill_keys($imageIds, '');

		$res = \CFile::getList([], ['@ID' => implode(',', $imageIds)]);
		while ($file = $res->fetch())
		{
			$file['SRC'] = \CFile::getFileSRC($file);
			$fileInfo = \CFile::resizeImageGet(
				$file,
				[
					'width' => 100,
					'height' => 100,
				],
				BX_RESIZE_IMAGE_EXACT,
				false,
				false,
				true,
			);

			$result[$file['ID']] = $fileInfo['src'];
		}

		return $result;
	}

	private function sendPush(string $command, array $parameters = []): void
	{
		$parameters['USER_ID'] = $this->userId;
		PushService::addEvent(
			[$this->userId],
			[
				'module_id' => 'socialnetwork',
				'command' => $command,
				'params' => $parameters,
			]
		);
	}

	private function addEmptyGroupIdError(): void
	{
		$this->addError(
			new Error(
				Loc::getMessage('SONET_CONTROLLER_WORKGROUP_EMPTY'),
				'SONET_CONTROLLER_WORKGROUP_EMPTY'
			)
		);
	}

	private function addIncorrectValueError(): void
	{
		$this->addError(new Error(
			'SONET_CONTROLLER_WORKGROUP_INCORRECT_VALUE',
			'SONET_CONTROLLER_WORKGROUP_INCORRECT_VALUE'
		));
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit