This commit is contained in:
root
2025-11-13 19:04:05 +03:00
commit 240d0aba5f
75129 changed files with 11118122 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
<?php
namespace Bitrix\UI\Integration\Main;
use \Bitrix\UI\Avatar\Mask;
class User
{
public static function onDelete($userId): void
{
(new Mask\Owner\User($userId))->delete();
}
}

View File

@@ -0,0 +1,80 @@
<?php
namespace Bitrix\UI\Integration\Rest;
use \Bitrix\Main;
use \Bitrix\Rest;
use \Bitrix\UI\Avatar\Mask;
use \Bitrix\UI\Avatar;
class App
{
private const REST_STATISTIC_MASK_ENTITY_NAME = 'MASK';
public static function onRestAppDelete($app)
{
if (isset($app['APP_ID'])
&& $app['APP_ID']
&& ($app = Rest\AppTable::getByClientId($app['APP_ID']))
)
{
try
{
(new Mask\Owner\RestApp($app['ID']))->delete();
if (!Avatar\Model\ItemTable::getList(['filter' => ['=OWNER_TYPE' => Mask\Owner\RestApp::class], 'limit' => 1])->fetch())
{
\CAgent::RemoveAgent(__CLASS__ . '::sendRestStatistic();', 'ui');
}
}
catch (\Throwable $e)
{
// in case we do not
}
}
}
public static function OnRestAppInstall()
{
\CAgent::addAgent(
__CLASS__.'::sendRestStatistic();',
'ui',
'N',
86400,
"",
"Y",
"",
100,
false,
false
);
}
public static function sendRestStatistic()
{
if (
Main\Loader::includeModule('rest')
&& is_callable(['\Bitrix\Rest\UsageStatTable', 'logUserInterface'])
)
{
$dbRes = Avatar\Model\ItemToFileTable::getList([
'select' => ['APP_ID' => 'ITEM.OWNER_ID', 'CNT'],
'filter' => [
'=ITEM.OWNER_TYPE' => Mask\Owner\RestApp::class,
],
'runtime' => [new Main\Entity\ExpressionField('CNT', 'COUNT(%s)', 'ID')],
'group' => ['ITEM.OWNER_ID'],
]);
while ($res = $dbRes->fetch())
{
Rest\UsageStatTable::logUserInterface(
$res['APP_ID'],
static::REST_STATISTIC_MASK_ENTITY_NAME,
$res['CNT']
);
}
Rest\UsageStatTable::finalize();
}
return __CLASS__ . '::' . __FUNCTION__ . '();';
}
}

View File

@@ -0,0 +1,67 @@
<?php
namespace Bitrix\UI\Integration\Rest;
use \Bitrix\Main;
abstract class ExportStep {
//region input info
public string $entityCode;
public $entityId;
public Main\Type\Dictionary $previous;
public int $stepNumber;
//end region
//region OutputInfo
public Main\Type\Dictionary $data;
public Main\Type\Dictionary $files;
public Main\Type\Dictionary $next;
public Main\ErrorCollection $errorCollection;
//endregion
public function __construct(Main\Event $event)
{
$this->entityCode = $event->getParameter('CODE');
$this->entityId = $event->getParameter('ITEM_CODE');
$this->stepNumber = (int) $event->getParameter('STEP');
$data = json_decode($event->getParameter('NEXT') ?: '', true);
$this->previousStep = new Main\Type\Dictionary(($data ?: []));
$this->data = new Main\Type\Dictionary();
$this->files = new Main\Type\Dictionary();
$this->nextStep = new Main\Type\Dictionary();
$this->errorCollection = new Main\ErrorCollection();
$this->init();
}
abstract public function init(): void;
public function makeAnAnswer(): ?array
{
return [
'FILE_NAME' =>
implode('_',
[
(new \ReflectionClass(static::class))->getShortName(),
$this->entityCode,
$this->entityId,
$this->stepNumber
]
),
'CONTENT' => $this->data->toArray(),
'FILES' => $this->files->toArray(),
'NEXT' => $this->nextStep->count() <= 0
? false : json_encode($this->nextStep->toArray()),
] + (($error = $this->errorCollection->current()) ? [
'ERROR_MESSAGE' => $error->getMessage(),
'ERROR_ACTION' => $error->getCode(),
] : []);
}
public static function fulfill(Main\Event $event): array
{
$step = new static($event);
return $step->makeAnAnswer();
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace Bitrix\UI\Integration\Rest;
use \Bitrix\Main;
use \Bitrix\Rest;
abstract class ImportStep {
//region input info
public string $entityCode;
public Main\Type\Dictionary $data;
public Main\Type\Dictionary $previousStep;
public Rest\Configuration\Structure $structure;
//end region
//region OutputInfo
public Main\Type\Dictionary $nextStep;
public Main\ErrorCollection $errorCollection;
//endregion
public function __construct(Main\Event $event)
{
$this->entityCode = $event->getParameter('CODE');
$this->data = new Main\Type\Dictionary($event->getParameter('CONTENT')['DATA']);
$this->structure = new Rest\Configuration\Structure($event->getParameter('CONTEXT_USER'));
$this->previousStep = new Main\Type\Dictionary($event->getParameter('CONTENT')['RATIO']);
$this->nextStep = new Main\Type\Dictionary();
$this->errorCollection = new Main\ErrorCollection();
$this->init($event);
}
abstract public function init($event): void;
abstract public function makeAStep(): void;
public function makeAnAnswer(): ?array
{
return [
'RATIO' => $this->nextStep->toArray(),
] + (($error = $this->errorCollection->current()) ? [
'ERROR_MESSAGE' => $error->getMessage(),
'ERROR_ACTION' => $error->getCode(),
] : []);
}
public static function fulfill(Main\Event $event): array
{
$step = new static($event);
if ($step->errorCollection->isEmpty())
{
$step->makeAStep();
}
return $step->makeAnAnswer();
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace Bitrix\UI\Integration\Rest;
use \Bitrix\Main;
use \Bitrix\Main\Event;
use \Bitrix\Ui;
use \Bitrix\UI\Avatar;
class MaskExport extends ExportStep
{
private const PAGE_SIZE = 1;
public static function getSettings(Event $event): ?array
{
$step = $event->getParameter('STEP');
$setting = $event->getParameter('SETTING');
return [
'SETTING' => $setting,
'NEXT' => false
];
}
public function init(): void
{
$query = Avatar\Model\ItemTable::query()
->setFilter([
'=OWNER_TYPE' => Avatar\Mask\Owner\User::class,
'=OWNER_ID' => $this->entityId
])
->setSelect(['ID', 'FILE_ID', 'TITLE', 'DESCRIPTION', 'SORT'])
->setOrder(['ID' => 'ASC'])
->setLimit(static::PAGE_SIZE)
->setOffset($this->stepNumber * static::PAGE_SIZE)
->exec();
while ($res = $query->fetch())
{
$this->data[] = $res;
$this->files[] = ['ID' => $res['FILE_ID']];
}
if ($this->data->count() >= static::PAGE_SIZE)
{
$this->nextStep->set('last', $this->data->current());
}
}
}

View File

@@ -0,0 +1,73 @@
<?php
namespace Bitrix\UI\Integration\Rest;
use Bitrix\Main\Error;
use Bitrix\UI\Avatar;
use Bitrix\Rest;
class MaskImportApp extends ImportStep
{
protected int $ownerId;
private int $groupId;
protected Avatar\Mask\Owner\DefaultOwner $owner;
public function init($event): void
{
$this->ownerId = (int) $event->getParameter('APP_ID');
if ($this->ownerId <= 0)
{
$this->errorCollection->setError(new Error('Application id is not set.'));
return;
}
if (!($app = Rest\AppTable::getById($this->ownerId)->fetch()))
{
$this->errorCollection->setError(new Error('Application is not found.'));
return;
}
$this->owner = new Avatar\Mask\Owner\RestApp($this->ownerId);
if ($group = Avatar\Mask\GroupTable::getList([
'select' => ['ID'],
'filter' => [
'=OWNER_TYPE' => Avatar\Mask\Owner\RestApp::class,
'=OWNER_ID' => $this->ownerId,
]
])->fetch())
{
$this->groupId = $group['ID'];
}
else
{
$this->groupId = Avatar\Mask\Group::createOrGet($this->owner, $app['APP_NAME'])->getId();
}
}
public function makeAStep(): void
{
foreach ($this->data as $res)
{
$fileInfo = $this->structure->getUnpackFile((int)$res['FILE_ID']);
$file = !empty($fileInfo['PATH']) ? \CFile::makeFileArray($fileInfo['PATH']) : null;
$file['name'] = $fileInfo['NAME'];
if ($file)
{
$result = Avatar\Mask\Item::create(
$this->owner,
$file,
[
'TITLE' => $res['TITLE'],
'DESCRIPTION' => $res['DESCRIPTION'],
'GROUP_ID' => $this->groupId,
'ACCESS_CODE' => $this->owner->getDefaultAccess()
]
);
if (!$result->isSuccess())
{
$this->errorCollection->add($result->getErrors());
}
}
}
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace Bitrix\UI\Integration\Rest;
use Bitrix\Main\Error;
use Bitrix\UI\Avatar;
class MaskImportPersonal extends ImportStep
{
protected int $ownerId;
protected Avatar\Mask\Owner\DefaultOwner $owner;
public function init($event): void
{
$this->ownerId = (int) $event->getParameter('USER_ID');
if ($this->ownerId <= 0)
{
$this->errorCollection->setError(new Error('User owner is not set'));
return;
}
$this->owner = new Avatar\Mask\Owner\User($this->ownerId);
}
public function makeAStep(): void
{
foreach ($this->data as $res)
{
$fileInfo = $this->structure->getUnpackFile((int)$res['FILE_ID']);
$file = !empty($fileInfo['PATH']) ? \CFile::makeFileArray($fileInfo['PATH']) : null;
$file['name'] = $fileInfo['NAME'];
if ($file)
{
$result = Avatar\Mask\Item::create(
$this->owner,
$file,
[
'TITLE' => $res['TITLE'],
'DESCRIPTION' => $res['DESCRIPTION'],
'ACCESS_CODE' => $this->owner->getDefaultAccess()
]
);
if (!$result->isSuccess())
{
$this->errorCollection->add($result->getErrors());
}
}
}
}
}

View File

@@ -0,0 +1,160 @@
<?php
namespace Bitrix\UI\Integration\Rest;
use Bitrix\Main\Localization\Loc;
use Bitrix\Main\Event;
use Bitrix\Main;
Loc::loadMessages(__FILE__);
class MaskManifest
{
private const USER_MASKS_MANIFEST_CODE = 'ui_masks';
private const SYSTEM_MASKS_MANIFEST_CODE = 'ui_masks_system';
public const CODE = 'ui_masks';
private static $manifestList = [
self::USER_MASKS_MANIFEST_CODE,
self::SYSTEM_MASKS_MANIFEST_CODE
];
private static $entityList = [
'UI_MASK' => 10000,
];
/**
* Returns list of available manifests.
*/
public static function onRestApplicationConfigurationGetManifest(): array
{
return [[
'CODE' => static::USER_MASKS_MANIFEST_CODE,
'VERSION' => 1,
'ACTIVE' => 'Y',
'USES' => [
'ui_masks',
],
'DISABLE_CLEAR_FULL' => 'N',
'DISABLE_NEED_START_BTN' => 'Y',
'SKIP_CLEARING' => 'Y',
'PLACEMENT' => [],
'TITLE' => Loc::getMessage('UI_REST_MAIN_TITLE_PAGE'),
'DESCRIPTION' => Loc::getMessage('UI_REST_MAIN_DESCRIPTION_PAGE'),
'IMPORT_TITLE_PAGE' => Loc::getMessage('UI_REST_IMPORT_TITLE_PAGE'),
'IMPORT_TITLE_BLOCK' => Loc::getMessage('UI_REST_IMPORT_TITLE_BLOCK'),
'IMPORT_DESCRIPTION_UPLOAD' => Loc::getMessage('UI_REST_IMPORT_ACTION_DESCRIPTION'),
'IMPORT_DESCRIPTION_START' => Loc::getMessage('UI_REST_IMPORT_DESCRIPTION_START'),
'EXPORT_TITLE_PAGE' => Loc::getMessage('UI_REST_EXPORT_TITLE_PAGE'),
'EXPORT_TITLE_BLOCK' => Loc::getMessage('UI_REST_EXPORT_TITLE_BLOCK'),
'EXPORT_ACTION_DESCRIPTION' => Loc::getMessage('UI_REST_EXPORT_ACTION_DESCRIPTION'),
'IMPORT_FINISH_DESCRIPTION' => Loc::getMessage('UI_REST_IMPORT_FINISH_DESCRIPTION'),
'IMPORT_INSTALL_FINISH_TEXT' => '',
'REST_IMPORT_AVAILABLE' => 'Y',
'ACCESS' => [
'MODULE_ID' => 'ui',
'CALLBACK' => [
static::class,
'onCheckAccess'
]
]
]];
}
/**
* Checks access to export and import.
* @param string $type Export or import.
* @param array $manifest Manifest data.
* @return array
*/
public static function onCheckAccess(string $type, array $manifest): array
{
return [
'result' => true
];
}
/**
* Step before active actions: import/export.
*/
public static function OnRestApplicationConfigurationGetManifestSetting(Event $event): ?array
{
$manifestCode = $event->getParameter('CODE');
if (!in_array($manifestCode, static::$manifestList))
{
return null;
}
$result = [
'SETTING' => $event->getParameter('SETTINGS'),
'NEXT' => false
];
return $result;
}
/**
* Returns entity list with sorting
*/
public static function onRestApplicationConfigurationEntity(): array
{
return static::$entityList;
}
public static function OnRestApplicationConfigurationExport(Event $event)
{
//region Check manifests intersection
$manifest = $event->getParameter('MANIFEST');
$intersection = array_intersect($manifest['USES'], static::$manifestList);
if (!$intersection)
{
return null;
}
//endregion
$entityCode = $event->getParameter('CODE');
if ($entityCode === 'UI_MASK')
{
return MaskExport::fulfill($event);
}
return null;
}
public static function onRestApplicationConfigurationImport(Event $event): ?array
{
//region Check manifests intersection
$manifest = $event->getParameter('IMPORT_MANIFEST');
$intersection = array_intersect($manifest['USES'], static::$manifestList);
if (!$intersection)
{
return null;
}
//endregion
$entityCode = $event->getParameter('CODE');
// TODO: Remove 2 string
// $event->setParameter('APP_ID', 6);
// $event->setParameter('CONTEXT', 'app6');
if ($entityCode === 'UI_MASK')
{
if (preg_match('/app(\d+)/is', $event->getParameter('CONTEXT')))
{
return MaskImportApp::fulfill($event);
}
return MaskImportPersonal::fulfill($event);
}
return null;
}
public static function bind()
{
$eventManager = Main\EventManager::getInstance();
foreach ([
'onRestApplicationConfigurationGetManifest',
'onRestApplicationConfigurationGetManifestSetting',
'onRestApplicationConfigurationExport',
'onRestApplicationConfigurationEntity',
'onRestApplicationConfigurationImport',
] as $eventCode)
{
$eventManager->registerEventHandler('rest', $eventCode, 'ui', static::class, $eventCode);
}
}
}