5use Bitrix\Main\ArgumentException;
6use Bitrix\Main\Data\Cache;
7use Bitrix\Main\Engine\CurrentUser;
9use Bitrix\Main\EventManager;
10use Bitrix\Main\EventResult;
11use Bitrix\Main\Localization\Loc;
12use Bitrix\Main\ObjectPropertyException;
13use Bitrix\Main\SystemException;
14use Bitrix\Main\Web\HttpClient;
15use Bitrix\Main\Web\Uri;
16use Bitrix\Rest\Engine\Access;
17use Bitrix\Rest\Event\Sender;
18use Bitrix\Rest\FormConfig\EventType;
19use Bitrix\Rest\Internals\FreeAppTable;
20use Bitrix\Rest\Marketplace\Client;
21use Bitrix\Main\ORM\Fields\BooleanField;
22use Bitrix\Main\ORM\Fields\Relations\OneToMany;
23use Bitrix\Rest\Preset\EventController;
25Loc::loadMessages(__FILE__);
97 private static $skipRemoteUpdate =
false;
104 'landing_cloud',
'rating',
126 'data_type' =>
'integer',
128 'autocomplete' =>
true,
130 'CLIENT_ID' =>
array(
131 'data_type' =>
'string',
133 'validation' =>
array(__CLASS__,
'validateClientId'),
136 'data_type' =>
'string',
138 'validation' =>
array(__CLASS__,
'validateCode'),
141 'data_type' =>
'boolean',
142 'values' =>
array(static::INACTIVE, static::ACTIVE),
144 'INSTALLED' =>
array(
145 'data_type' =>
'boolean',
146 'values' =>
array(static::NOT_INSTALLED, static::INSTALLED),
149 'data_type' =>
'string',
150 'validation' =>
array(__CLASS__,
'validateUrl'),
153 'data_type' =>
'string',
154 'validation' =>
array(__CLASS__,
'validateUrlDemo'),
156 'URL_INSTALL' =>
array(
157 'data_type' =>
'string',
158 'validation' =>
array(__CLASS__,
'validateUrlInstall'),
160 'URL_SETTINGS' =>
array(
161 'data_type' =>
'string',
162 'validation' =>
array(__CLASS__,
'validateUrl'),
165 'data_type' =>
'string',
166 'validation' =>
array(__CLASS__,
'validateVersion'),
169 'data_type' =>
'string',
171 'validation' =>
array(__CLASS__,
'validateScope'),
174 'data_type' =>
'enum',
177 static::STATUS_LOCAL,
181 static::STATUS_TRIAL,
182 static::STATUS_SUBSCRIPTION,
185 'DATE_FINISH' =>
array(
186 'data_type' =>
'date',
188 'IS_TRIALED' =>
array(
189 'data_type' =>
'boolean',
190 'values' =>
array(static::NOT_TRIALED, static::TRIALED),
192 'SHARED_KEY' =>
array(
193 'data_type' =>
'string',
194 'validation' =>
array(__CLASS__,
'validateSharedKey'),
196 'CLIENT_SECRET' =>
array(
197 'data_type' =>
'string',
198 'validation' =>
array(__CLASS__,
'validateClientSecret'),
201 'data_type' =>
'string',
202 'validation' =>
array(__CLASS__,
'validateAppName'),
205 'data_type' =>
'string',
206 'validation' =>
array(__CLASS__,
'validateAccess'),
208 'APPLICATION_TOKEN' =>
array(
209 'data_type' =>
'string',
212 'data_type' =>
'boolean',
213 'values' =>
array(static::INACTIVE, static::ACTIVE),
215 'USER_INSTALL' =>
array(
216 'data_type' =>
'boolean',
217 'values' =>
array(static::INACTIVE, static::ACTIVE),
220 'data_type' =>
'Bitrix\Rest\AppLangTable',
221 'reference' =>
array(
222 '=this.ID' =>
'ref.APP_ID',
226 'LANG_DEFAULT' =>
array(
227 'data_type' =>
'Bitrix\Rest\AppLangTable',
228 'reference' =>
array(
229 '=this.ID' =>
'ref.APP_ID',
233 'LANG_LICENSE' =>
array(
234 'data_type' =>
'Bitrix\Rest\AppLangTable',
235 'reference' =>
array(
236 '=this.ID' =>
'ref.APP_ID',
240 (
new OneToMany(
'LANG_ALL', AppLangTable::class,
'APP'))
241 ->configureJoinType(
'left'),
249 'CASE WHEN %s IS NOT NULL THEN 1 ELSE 0 END',
250 [
'FREE_APP.APP_CODE'],
262 static::$skipRemoteUpdate = $v;
273 $result =
new Main\Entity\EventResult();
276 if(
$data[
'fields'][
'STATUS'] == static::STATUS_LOCAL && !
$data[
'fields'][
'CLIENT_ID'])
279 $dummyClientId =
'no_client_id_'.$rnd;
280 $dummyClientSecret =
'no_client_secret_'.$rnd;
283 "CLIENT_ID" => $dummyClientId,
284 "CLIENT_SECRET" => $dummyClientSecret,
285 "CODE" => $dummyClientId,
302 EventController::onAddApp(
$event);
304 if(!static::$skipRemoteUpdate)
307 $data[
'fields'][
'STATUS'] === static::STATUS_LOCAL
314 'TITLE' =>
$data[
'fields'][
'APP_NAME'],
315 'REDIRECT_URI' =>
$data[
'fields'][
'URL'],
316 'SCOPE' =>
$data[
'fields'][
'SCOPE'],
321 ->addApplication($appFields);
326 "error" => $e->getCode(),
327 "error_description" => $e->getMessage(),
331 if(is_array($clientData))
333 if($clientData[
'result'])
335 static::$skipRemoteUpdate =
true;
337 static::clearClientCache($clientData[
'result'][
'client_id']);
339 $updateResult = static::update(
$data[
'id'],
array(
340 'CLIENT_ID' => $clientData[
'result'][
'client_id'],
341 'CLIENT_SECRET' => $clientData[
'result'][
'client_secret'],
342 'STATUS' => static::STATUS_LOCAL,
343 'SHARED_KEY' => md5(\CRestUtil::getMemberId().$clientData[
'result'][
'client_secret']),
344 'CODE' => $clientData[
'result'][
'client_id'],
346 static::$skipRemoteUpdate =
false;
348 if($updateResult->isSuccess())
354 $clientData =
array(
'error' => $updateResult->getErrorMessages());
360 $clientData =
array(
'error' =>
'Unknown error');
363 static::$skipRemoteUpdate =
true;
364 static::delete(
$data[
'id']);
365 static::$skipRemoteUpdate =
false;
371 if(
$data[
'fields'][
'STATUS'] !== static::STATUS_LOCAL)
373 \Bitrix\Rest\Engine\Access::getActiveEntity(
true);
390 static::clearClientCache(
$data[
'primary'][
'ID']);
392 if(!static::$skipRemoteUpdate)
395 isset(
$data[
'fields'][
'STATUS'])
396 &&
$data[
'fields'][
'STATUS'] === static::STATUS_LOCAL
400 $app = static::getByClientId(
$data[
'primary'][
'ID']);
406 ->updateApplication(
array(
407 "CLIENT_ID" =>
$app[
'CLIENT_ID'],
408 'TITLE' =>
$data[
'fields'][
'APP_NAME'],
409 'REDIRECT_URI' =>
$data[
'fields'][
'URL'],
410 'SCOPE' =>
$data[
'fields'][
'SCOPE'],
413 if($updateResult[
'result'])
420 $updateResult =
array(
421 "error" => $e->getCode(),
422 "error_description" => $e->getMessage(),
430 if(isset(
$data[
'fields'][
'STATUS']) &&
$data[
'fields'][
'STATUS'] !== static::STATUS_LOCAL)
432 \Bitrix\Rest\Engine\Access::getActiveEntity(
true);
445 if(!static::$skipRemoteUpdate)
448 $app = static::getByClientId(
$data[
'primary'][
'ID']);
454 \CRestUtil::cleanApp(
$app[
"ID"],
true);
460 ->deleteApplication(
array(
461 'CLIENT_ID' =>
$app[
'CLIENT_ID'],
482 static::clearClientCache(
$data[
'primary'][
'ID']);
488 $row = self::getRowById($appId);
494 return $row[
'INSTALLED'] === self::INSTALLED;
499 $appInfo = static::getByClientId($appId);
502 $eventFields =
array(
504 'VERSION' => $appInfo[
'VERSION'],
505 'ACTIVE' => $appInfo[
'ACTIVE'],
506 'INSTALLED' => $appInfo[
'INSTALLED'],
509 if ($appInfo[
'ACTIVE'] === self::ACTIVE && $appInfo[
'INSTALLED'] === self::INSTALLED)
511 $res = PlacementTable::getList(
514 '=APP_ID' => $appInfo[
'ID'],
523 while ($item =
$res->fetch())
530 'PLACEMENT' => $item[
'PLACEMENT'],
531 'USER_ID' => $item[
'USER_ID'],
534 EventManager::getInstance()->send(
$event);
538 foreach(
GetModuleEvents(
"rest",
"OnRestAppInstall",
true) as $eventHandler)
553 $appInfo = static::getByClientId($appId);
556 \CRestUtil::cleanApp($appId, $clean);
558 if($appInfo[
'STATUS'] !== static::STATUS_LOCAL)
561 'CLIENT_ID' => $appInfo[
'CLIENT_ID']
574 public static function checkUninstallAvailability($appId, $clean = 0)
586 foreach (
$event->getResults() as $eventResult)
588 if($eventResult->getType() === EventResult::ERROR)
590 $eventResultData = $eventResult->getParameters();
591 if ($eventResultData instanceof
Main\
Error)
593 $result->add([$eventResultData]);
613 if(is_array($appList) && is_array($appList[
'result']))
615 $dbApps = static::getList(
array(
617 '!=STATUS' => static::STATUS_LOCAL,
620 'ID',
'CLIENT_ID',
'STATUS',
'DATE_FINISH',
624 $localApps =
array();
625 while(
$app = $dbApps->fetch())
627 $localApps[
$app[
'CLIENT_ID']] =
$app;
630 foreach($appList[
'result'] as
$app)
632 if(array_key_exists(
$app[
'client_id'], $localApps))
634 $dateFinishLocal = $localApps[
$app[
'client_id']][
'DATE_FINISH']
635 ? $localApps[
$app[
'client_id']][
'DATE_FINISH']->getTimestamp()
637 $dateFinishRemote = (
$app[
'date_finish'] ??
null) ?
Main\
Type\Date::createFromTimestamp(
$app[
'date_finish'])->getTimestamp() :
'';
640 $localApps[
$app[
'client_id']][
'STATUS'] !==
$app[
'status']
641 || $dateFinishRemote != $dateFinishLocal
645 'STATUS' =>
$app[
'status'],
646 'DATE_FINISH' =>
$app[
'date_finish']
647 ?
Main\
Type\Date::createFromTimestamp(
$app[
'date_finish'])
651 static::setSkipRemoteUpdate(
true);
652 $result = static::update($localApps[
$app[
'client_id']][
'ID'], $appFields);
653 static::setSkipRemoteUpdate(
false);
657 && $appFields[
'STATUS'] === static::STATUS_PAID
660 static::callAppPaymentEvent($localApps[
$app[
'client_id']][
'ID']);
667 'CLIENT_ID' =>
$app[
'client_id'],
668 'CODE' =>
$app[
'code'],
669 'ACTIVE' =>
$app[
'active'] ? static::ACTIVE : static::INACTIVE,
670 'INSTALLED' => static::NOT_INSTALLED,
671 'VERSION' =>
$app[
'version'],
672 'STATUS' =>
$app[
'status'],
673 'SCOPE' =>
$app[
'scope'],
676 if(!empty(
$app[
'date_finish']))
681 $result = static::add($appFields);
683 if(
$result->isSuccess() && $appFields[
'STATUS'] === static::STATUS_PAID)
685 static::callAppPaymentEvent(
$result->getId());
725 $appInfo =
$app = static::getByClientId(
$app);
729 $appInfo = static::getByClientId(
$app[
'CODE']);
735 $res[
'PAYMENT_NOTIFY'] =
'N';
736 $res[
'PAYMENT_EXPIRED'] =
'N';
737 $res[
'PAYMENT_ALLOW'] =
'Y';
739 if (
$app[
'STATUS'] === self::STATUS_SUBSCRIPTION)
744 '#DETAIL_URL#' => $detailUrl,
746 '#CODE#' => urlencode(
$app[
'CODE'])
748 $res[
'PAYMENT_NOTIFY'] =
'Y';
749 $res[
'PAYMENT_EXPIRED'] =
'Y';
750 $res[
'PAYMENT_ALLOW'] =
'N';
755 if (!is_null($dateFinish))
757 $res[
'DAYS_LEFT'] = floor(($dateFinish->getTimestamp() - \CTimeZone::getOffset() - time()) / 86400);
758 if(
$res[
'DAYS_LEFT'] < 0)
761 '#DETAIL_URL#' => $detailUrl,
762 '#DAYS#' =>
$res[
'DAYS_LEFT'],
763 '#CODE#' => urlencode(
$app[
'CODE'])
765 $res[
'PAYMENT_NOTIFY'] =
'Y';
766 $res[
'PAYMENT_EXPIRED'] =
'Y';
767 $res[
'PAYMENT_ALLOW'] =
'N';
769 elseif (
$res[
'DAYS_LEFT'] < static::PAID_NOTIFY_DAYS)
772 '#DETAIL_URL#' => $detailUrl,
773 '#DAYS#' =>
$res[
'DAYS_LEFT'],
774 '#CODE#' => urlencode(
$app[
'CODE'])
776 $res[
'PAYMENT_NOTIFY'] =
'Y';
781 elseif(
$app[
'DATE_FINISH'] <>
'' &&
$app[
'STATUS'] != self::STATUS_FREE)
783 $res[
'DAYS_LEFT'] = floor(
788 $res[
'DAYS_LEFT'] < static::PAID_NOTIFY_DAYS
789 ||
$app[
'STATUS'] == static::STATUS_TRIAL)
791 $res[
'PAYMENT_NOTIFY'] =
'Y';
793 if(
$res[
'DAYS_LEFT'] < 0)
795 $res[
'PAYMENT_EXPIRED'] =
'Y';
797 if(
$app[
'STATUS'] == static::STATUS_TRIAL)
799 $res[
'PAYMENT_ALLOW'] =
'N';
802 $app[
'STATUS'] == static::STATUS_PAID
803 &&
$res[
'DAYS_LEFT'] < static::PAID_GRACE_PERIOD
806 if(
$app[
'IS_TRIALED'] ==
'N' &&
$app[
'URL_DEMO'] <>
'')
808 $res[
'STATUS'] = static::STATUS_DEMO;
812 $res[
'PAYMENT_ALLOW'] =
'N';
819 "#DETAIL_URL#" => $detailUrl,
820 "#DAYS#" =>
$res[
'DAYS_LEFT'],
821 "#CODE#" => urlencode(
$app[
'CODE']),
826 $res[
'PAYMENT_NOTIFY'] =
'Y';
828 "#DETAIL_URL#" => $detailUrl,
829 "#CODE#" => urlencode(
$app[
'CODE'])
835 "#DETAIL_URL#" => $detailUrl,
836 "#CODE#" => urlencode(
$app[
'CODE'])
840 $res[
'MESSAGE_SUFFIX'] =
'_'.$res[
'STATUS'].
'_'.
$res[
'PAYMENT_EXPIRED'].
'_'.
$res[
'PAYMENT_ALLOW'];
844 if (!empty($appInfo[
'CLIENT_ID']))
848 $appInfo[
'CLIENT_ID']
852 $res[
'MESSAGE_SUFFIX'] =
'_HOLD_OVERLOAD';
853 $res[
'PAYMENT_NOTIFY'] =
'Y';
870 public static function getStatusMessage($suffix, $replace =
null, $checkAdmin =
true, $language =
null)
872 if ($checkAdmin && \CRestUtil::isAdmin())
879 && array_key_exists(
'#DAYS#', $replace)
881 is_int($replace[
'#DAYS#'])
882 || preg_match(
'/^(-|)\d+$/', $replace[
'#DAYS#'])
886 $replace[
'#DAYS#'] =
FormatDate(
'ddiff', time(), time() + 24 * 60 * 60 * $replace[
'#DAYS#']);
889 return Loc::getMessage(
'PAYMENT_MESSAGE' . $suffix, $replace, $language);
898 $appInfo = static::getByClientId($appId);
901 if($appInfo[
'ACCESS'] <>
'')
903 $rightsList = explode(
",", $appInfo[
"ACCESS"]);
906 $accessNames =
$access->getNames($rightsList);
909 foreach($rightsList as
$right)
913 "provider" => $accessNames[
$right][
"provider_id"],
914 "name" => $accessNames[
$right][
"name"]
931 $appInfo = static::getByClientId($appId);
935 if(is_array($newRights) && !empty($newRights))
937 $rightIdList =
array();
938 foreach($newRights as
$key => $rightsList)
940 foreach($rightsList as $rightId =>
$ar)
942 $rightIdList[] = $rightId;
945 $rights = implode(
",", $rightIdList);
948 static::update($appId,
array(
953 if(defined(
"BX_COMP_MANAGED_CACHE"))
969 if(!array_key_exists(
$clientId, static::$applicationCache))
991 'MENU_NAME' =>
'LANG.MENU_NAME',
992 'MENU_NAME_DEFAULT' =>
'LANG_DEFAULT.MENU_NAME',
993 'MENU_NAME_LICENSE' =>
'LANG_LICENSE.MENU_NAME',
1002 'ID' =>
$app->getId(),
1003 'MENU_NAME' => !is_null(
$app->getLang()) ?
$app->getLang()->getMenuName() :
'',
1004 'MENU_NAME_DEFAULT' => !is_null(
$app->getLangDefault()) ?
$app->getLangDefault()->getMenuName() :
'',
1005 'MENU_NAME_LICENSE' => !is_null(
$app->getLangLicense()) ?
$app->getLangLicense()->getMenuName() :
'',
1007 foreach (
$app->sysGetEntity()->getScalarFields() as $field)
1009 $fieldName = $field->getName();
1012 $appInfo[$fieldName] =
$app->get($fieldName) ?
'Y' :
'N';
1016 $appInfo[$fieldName] =
$app->get($fieldName);
1019 $app->fillLangAll();
1020 if (!is_null(
$app->getLangAll()))
1024 $appInfo[
'LANG_ALL'][
$lang->getLanguageId()] = [
1025 'MENU_NAME' =>
$lang->getMenuName(),
1029 if ($appInfo[
'MENU_NAME'] ===
'')
1035 if (isset($appInfo) && is_array($appInfo))
1037 static::$applicationCache[$appInfo[
'ID']] = $appInfo;
1038 static::$applicationCache[$appInfo[
'CLIENT_ID']] = $appInfo;
1039 static::$applicationCache[$appInfo[
'CODE']] = $appInfo;
1043 return static::$applicationCache[
$clientId] ??
null;
1048 if(array_key_exists(
$clientId, static::$applicationCache))
1053 unset(static::$applicationCache[
$app[
'ID']]);
1054 unset(static::$applicationCache[
$app[
'CLIENT_ID']]);
1058 unset(static::$applicationCache[
$clientId]);
1065 if(static::$licenseLang ===
null)
1067 if(
Main\Loader::includeModule(
'bitrix24'))
1069 static::$licenseLang = \CBitrix24::getLicensePrefix();
1073 $dbSites = \CSite::getList(
'sort',
'asc',
array(
'DEFAULT' =>
'Y',
'ACTIVE' =>
'Y'));
1076 static::$licenseLang = is_array(
$site) && isset(
$site[
'LANGUAGE_ID']) ?
$site[
'LANGUAGE_ID'] : LANGUAGE_ID;
1079 if(static::$licenseLang ===
null)
1081 static::$licenseLang =
'en';
1085 return static::$licenseLang;
1123 new Main\
Entity\Validator\Length(
null, 1000),
1135 new Main\
Entity\Validator\Length(
null, 1000),
1147 new Main\
Entity\Validator\Length(
null, 1000),
1150 $checkResult =
true;
1158 $checkResult =
false;
1163 $checkResult =
false;
1168 return Loc::getMessage(
"MP_ERROR_INCORRECT_URL_INSTALL");
1197 new Main\
Entity\Validator\Length(
null, 2000),
1233 new Main\
Entity\Validator\Length(
null, 1000),
1245 new Main\
Entity\Validator\Length(
null, 2000),
1255 foreach($permissionList as
$key =>
$perm)
1257 if(in_array(
$perm, static::$localAppDeniedScope))
1259 unset($permissionList[
$key]);
1263 return array_values($permissionList);
1276 if(
$type == static::TYPE_CONFIGURATION)
1279 if(in_array(
$code, $appList))
1296 $cache = Cache::createInstance();
1297 if ($cache->initCache(static::CACHE_TTL,
'appType'.md5(
$code.$version), static::CACHE_PATH))
1301 elseif ($cache->startDataCache())
1303 $appDetailInfo = Client::getInstall(
$code, $version);
1304 $result = ($appDetailInfo[
'ITEMS'][
'TYPE'])?:
false;
1305 $cache->endDataCache(
$result);
1328 if (empty($appData[
'URL_SETTINGS']))
1330 throw new ArgumentException(
'Property "URL_SETTINGS" is empty',
'URL_SETTINGS');
1332 $uri =
new Uri($appData[
'URL_SETTINGS']);
1334 $params = Sender::getDefaultEventParams();
1335 $params[
'sendRefreshToken'] =
true;
1337 'event' =>
$type->value,
1338 'data' => $formData,
1339 'auth' => Sender::getAuth(
1341 CurrentUser::get()->getId() ?? 0,
static getString($length, $caseSensitive=false)
static createFromTimestamp($timestamp)
fetchAppFormConfig(array $formData, EventType $type)
__construct(private string $clientId)
static deleteByApp($appId)
static validateClientId()
static getStatusMessage($suffix, $replace=null, $checkAdmin=true, $language=null)
static isInstalled(int $appId)
static canUninstallByType($code, $version=false)
static getAppType($code, $version=false)
static getAppStatusInfo($app, $detailUrl)
static onBeforeAdd(Main\Entity\Event $event)
static clearClientCache($clientId)
static onAfterDelete(Main\Entity\Event $event)
static validateUrlInstall()
static getByClientId($clientId)
static $localAppDeniedScope
static uninstall($appId, $clean=0)
static onDelete(Main\Entity\Event $event)
static getLicenseLanguage()
static onAfterUpdate(Main\Entity\Event $event)
static cleanLocalPermissionList(array $permissionList)
static validateSharedKey()
static setAccess($appId, $newRights=array())
const STATUS_SUBSCRIPTION
static onAfterAdd(Main\Entity\Event $event)
static setSkipRemoteUpdate($v)
static updateAppStatusInfo()
static callAppPaymentEvent($appId)
static validateClientSecret()
static is(string $type, string $code)
static checkCallback($handlerUrl, $appInfo=array(), $checkInstallUrl=true)
static mergeFromLangAll($data)
static getSubscriptionFinalDate()
const PREFIX_EVENT_ON_AFTER_ADD
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
if(!is_null($config))($config as $configItem)(! $configItem->isVisible()) $code
if(file_exists($_SERVER['DOCUMENT_ROOT'] . "/urlrewrite.php")) $uri
if(!defined('SITE_ID')) $lang
if(!is_array($deviceNotifyCodes)) $access
ExecuteModuleEventEx($arEvent, $arParams=[])
FormatDate($format="", $timestamp=false, $now=false, ?string $languageId=null)
GetModuleEvents($MODULE_ID, $MESSAGE_ID, $bReturnArray=false)
MakeTimeStamp($datetime, $format=false)
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
if(empty($signedUserToken)) $key
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']