diff --git a/.gitignore b/.gitignore index d2beed8..197dea4 100644 --- a/.gitignore +++ b/.gitignore @@ -95,6 +95,8 @@ composer.phar /local/vendor/* /files/* .well-known/* +/integration/contacts/settings.php +/integration/contacts/logs/* !/bitrix/php_interface/migrations/* !/bitrix/php_interface/migrations/.xml diff --git a/integration/contacts/checkserver.php b/integration/contacts/checkserver.php new file mode 100644 index 0000000..b5282d6 --- /dev/null +++ b/integration/contacts/checkserver.php @@ -0,0 +1,4 @@ + 0){ + + $result = CRest::call('crm.activity.get', [ + 'id' => $activityId + ]); + + if (!isset($result['error'])) { + $contactId = $result['result']['OWNER_ID']; + } + } + + break; + + //Возможно это для чата + case 'ONIMCONNECTORMESSAGEADD': + break; + + //Возможно это для звонка + case 'OnExternalCallStart': + break; + } + + + if($contactId > 0){ + + $now = date('Y-m-d\TH:i:sP'); + + $updateResult = CRest::call('crm.contact.update', [ + 'id' => $contactId, + 'fields' => [ + 'UF_CRM_LAST_COMM_DATETIME' => $now + ] + ]); + } + +} \ No newline at end of file diff --git a/integration/contacts/crest.php b/integration/contacts/crest.php new file mode 100644 index 0000000..4f9a2a3 --- /dev/null +++ b/integration/contacts/crest.php @@ -0,0 +1,614 @@ + true, + 'install' => false + ]; + if($_REQUEST[ 'event' ] == 'ONAPPINSTALL' && !empty($_REQUEST[ 'auth' ])) + { + $result['install'] = static::setAppSettings($_REQUEST[ 'auth' ], true); + } + elseif($_REQUEST['PLACEMENT'] == 'DEFAULT') + { + $result['rest_only'] = false; + $result['install'] = static::setAppSettings( + [ + 'access_token' => htmlspecialchars($_REQUEST['AUTH_ID']), + 'expires_in' => htmlspecialchars($_REQUEST['AUTH_EXPIRES']), + 'application_token' => htmlspecialchars($_REQUEST['APP_SID']), + 'refresh_token' => htmlspecialchars($_REQUEST['REFRESH_ID']), + 'domain' => htmlspecialchars($_REQUEST['DOMAIN']), + 'client_endpoint' => 'https://' . htmlspecialchars($_REQUEST['DOMAIN']) . '/rest/', + ], + true + ); + } + + static::setLog( + [ + 'request' => $_REQUEST, + 'result' => $result + ], + 'installApp' + ); + return $result; + } + + /** + * @var $arParams array + * $arParams = [ + * 'method' => 'some rest method', + * 'params' => []//array params of method + * ]; + * @return mixed array|string|boolean curl-return or error + * + */ + protected static function callCurl($arParams) + { + if(!function_exists('curl_init')) + { + return [ + 'error' => 'error_php_lib_curl', + 'error_information' => 'need install curl lib' + ]; + } + $arSettings = static::getAppSettings(); + if($arSettings !== false) + { + if(isset($arParams[ 'this_auth' ]) && $arParams[ 'this_auth' ] == 'Y') + { + $url = 'https://oauth.bitrix.info/oauth/token/'; + } + else + { + $url = $arSettings[ "client_endpoint" ] . $arParams[ 'method' ] . '.' . static::TYPE_TRANSPORT; + if(empty($arSettings[ 'is_web_hook' ]) || $arSettings[ 'is_web_hook' ] != 'Y') + { + $arParams[ 'params' ][ 'auth' ] = $arSettings[ 'access_token' ]; + } + } + + $sPostFields = http_build_query($arParams[ 'params' ]); + + try + { + $obCurl = curl_init(); + curl_setopt($obCurl, CURLOPT_URL, $url); + curl_setopt($obCurl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($obCurl, CURLOPT_POSTREDIR, 10); + curl_setopt($obCurl, CURLOPT_USERAGENT, 'Bitrix24 CRest PHP 1.36'); + if($sPostFields) + { + curl_setopt($obCurl, CURLOPT_POST, true); + curl_setopt($obCurl, CURLOPT_POSTFIELDS, $sPostFields); + } + curl_setopt( + $obCurl, CURLOPT_FOLLOWLOCATION, (isset($arParams[ 'followlocation' ])) + ? $arParams[ 'followlocation' ] : 1 + ); + if(defined("C_REST_IGNORE_SSL") && C_REST_IGNORE_SSL === true) + { + curl_setopt($obCurl, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($obCurl, CURLOPT_SSL_VERIFYHOST, false); + } + $out = curl_exec($obCurl); + $info = curl_getinfo($obCurl); + if(curl_errno($obCurl)) + { + $info[ 'curl_error' ] = curl_error($obCurl); + } + if(static::TYPE_TRANSPORT == 'xml' && (!isset($arParams[ 'this_auth' ]) || $arParams[ 'this_auth' ] != 'Y'))//auth only json support + { + $result = $out; + } + else + { + $result = static::expandData($out); + } + curl_close($obCurl); + + if(!empty($result[ 'error' ])) + { + if($result[ 'error' ] == 'expired_token' && empty($arParams[ 'this_auth' ])) + { + $result = static::GetNewAuth($arParams); + } + else + { + $arErrorInform = [ + 'expired_token' => 'expired token, cant get new auth? Check access oauth server.', + 'invalid_token' => 'invalid token, need reinstall application', + 'invalid_grant' => 'invalid grant, check out define C_REST_CLIENT_SECRET or C_REST_CLIENT_ID', + 'invalid_client' => 'invalid client, check out define C_REST_CLIENT_SECRET or C_REST_CLIENT_ID', + 'QUERY_LIMIT_EXCEEDED' => 'Too many requests, maximum 2 query by second', + 'ERROR_METHOD_NOT_FOUND' => 'Method not found! You can see the permissions of the application: CRest::call(\'scope\')', + 'NO_AUTH_FOUND' => 'Some setup error b24, check in table "b_module_to_module" event "OnRestCheckAuth"', + 'INTERNAL_SERVER_ERROR' => 'Server down, try later' + ]; + if(!empty($arErrorInform[ $result[ 'error' ] ])) + { + $result[ 'error_information' ] = $arErrorInform[ $result[ 'error' ] ]; + } + } + } + if(!empty($info[ 'curl_error' ])) + { + $result[ 'error' ] = 'curl_error'; + $result[ 'error_information' ] = $info[ 'curl_error' ]; + } + + static::setLog( + [ + 'url' => $url, + 'info' => $info, + 'params' => $arParams, + 'result' => $result + ], + 'callCurl' + ); + + return $result; + } + catch(Exception $e) + { + static::setLog( + [ + 'message' => $e->getMessage(), + 'code' => $e->getCode(), + 'trace' => $e->getTrace(), + 'params' => $arParams + ], + 'exceptionCurl' + ); + + return [ + 'error' => 'exception', + 'error_exception_code' => $e->getCode(), + 'error_information' => $e->getMessage(), + ]; + } + } + else + { + static::setLog( + [ + 'params' => $arParams + ], + 'emptySetting' + ); + } + + return [ + 'error' => 'no_install_app', + 'error_information' => 'error install app, pls install local application ' + ]; + } + + /** + * Generate a request for callCurl() + * + * @var $method string + * @var $params array method params + * @return mixed array|string|boolean curl-return or error + */ + + public static function call($method, $params = []) + { + $arPost = [ + 'method' => $method, + 'params' => $params + ]; + if(defined('C_REST_CURRENT_ENCODING')) + { + $arPost[ 'params' ] = static::changeEncoding($arPost[ 'params' ]); + } + + $result = static::callCurl($arPost); + return $result; + } + + /** + * @example $arData: + * $arData = [ + * 'find_contact' => [ + * 'method' => 'crm.duplicate.findbycomm', + * 'params' => [ "entity_type" => "CONTACT", "type" => "EMAIL", "values" => array("info@bitrix24.com") ] + * ], + * 'get_contact' => [ + * 'method' => 'crm.contact.get', + * 'params' => [ "id" => '$result[find_contact][CONTACT][0]' ] + * ], + * 'get_company' => [ + * 'method' => 'crm.company.get', + * 'params' => [ "id" => '$result[get_contact][COMPANY_ID]', "select" => ["*"],] + * ] + * ]; + * + * @var $arData array + * @var $halt integer 0 or 1 stop batch on error + * @return array + * + */ + + public static function callBatch($arData, $halt = 0) + { + $arResult = []; + if(is_array($arData)) + { + if(defined('C_REST_CURRENT_ENCODING')) + { + $arData = static::changeEncoding($arData); + } + $arDataRest = []; + $i = 0; + foreach($arData as $key => $data) + { + if(!empty($data[ 'method' ])) + { + $i++; + if(static::BATCH_COUNT >= $i) + { + $arDataRest[ 'cmd' ][ $key ] = $data[ 'method' ]; + if(!empty($data[ 'params' ])) + { + $arDataRest[ 'cmd' ][ $key ] .= '?' . http_build_query($data[ 'params' ]); + } + } + } + } + if(!empty($arDataRest)) + { + $arDataRest[ 'halt' ] = $halt; + $arPost = [ + 'method' => 'batch', + 'params' => $arDataRest + ]; + $arResult = static::callCurl($arPost); + } + } + return $arResult; + } + + /** + * Getting a new authorization and sending a request for the 2nd time + * + * @var $arParams array request when authorization error returned + * @return array query result from $arParams + * + */ + + private static function GetNewAuth($arParams) + { + $result = []; + $arSettings = static::getAppSettings(); + if($arSettings !== false) + { + $arParamsAuth = [ + 'this_auth' => 'Y', + 'params' => + [ + 'client_id' => $arSettings[ 'C_REST_CLIENT_ID' ], + 'grant_type' => 'refresh_token', + 'client_secret' => $arSettings[ 'C_REST_CLIENT_SECRET' ], + 'refresh_token' => $arSettings[ "refresh_token" ], + ] + ]; + $newData = static::callCurl($arParamsAuth); + if(isset($newData[ 'C_REST_CLIENT_ID' ])) + { + unset($newData[ 'C_REST_CLIENT_ID' ]); + } + if(isset($newData[ 'C_REST_CLIENT_SECRET' ])) + { + unset($newData[ 'C_REST_CLIENT_SECRET' ]); + } + if(isset($newData[ 'error' ])) + { + unset($newData[ 'error' ]); + } + if(static::setAppSettings($newData)) + { + $arParams[ 'this_auth' ] = 'N'; + $result = static::callCurl($arParams); + } + } + return $result; + } + + /** + * @var $arSettings array settings application + * @var $isInstall boolean true if install app by installApp() + * @return boolean + */ + + private static function setAppSettings($arSettings, $isInstall = false) + { + $return = false; + if(is_array($arSettings)) + { + $oldData = static::getAppSettings(); + if($isInstall != true && !empty($oldData) && is_array($oldData)) + { + $arSettings = array_merge($oldData, $arSettings); + } + $return = static::setSettingData($arSettings); + } + return $return; + } + + /** + * @return mixed setting application for query + */ + + private static function getAppSettings() + { + if(defined("C_REST_WEB_HOOK_URL") && !empty(C_REST_WEB_HOOK_URL)) + { + $arData = [ + 'client_endpoint' => C_REST_WEB_HOOK_URL, + 'is_web_hook' => 'Y' + ]; + $isCurrData = true; + } + else + { + $arData = static::getSettingData(); + $isCurrData = false; + if( + !empty($arData[ 'access_token' ]) && + !empty($arData[ 'domain' ]) && + !empty($arData[ 'refresh_token' ]) && + !empty($arData[ 'application_token' ]) && + !empty($arData[ 'client_endpoint' ]) + ) + { + $isCurrData = true; + } + } + + return ($isCurrData) ? $arData : false; + } + + /** + * Can overridden this method to change the data storage location. + * + * @return array setting for getAppSettings() + */ + + protected static function getSettingData() + { + $return = []; + if(file_exists(__DIR__ . '/settings.json')) + { + $return = static::expandData(file_get_contents(__DIR__ . '/settings.json')); + if(defined("C_REST_CLIENT_ID") && !empty(C_REST_CLIENT_ID)) + { + $return['C_REST_CLIENT_ID'] = C_REST_CLIENT_ID; + } + if(defined("C_REST_CLIENT_SECRET") && !empty(C_REST_CLIENT_SECRET)) + { + $return['C_REST_CLIENT_SECRET'] = C_REST_CLIENT_SECRET; + } + } + return $return; + } + + /** + * @var $data mixed + * @var $encoding boolean true - encoding to utf8, false - decoding + * + * @return string json_encode with encoding + */ + protected static function changeEncoding($data, $encoding = true) + { + if(is_array($data)) + { + $result = []; + foreach ($data as $k => $item) + { + $k = static::changeEncoding($k, $encoding); + $result[$k] = static::changeEncoding($item, $encoding); + } + } + else + { + if($encoding) + { + $result = iconv(C_REST_CURRENT_ENCODING, "UTF-8//TRANSLIT", $data); + } + else + { + $result = iconv( "UTF-8",C_REST_CURRENT_ENCODING, $data); + } + } + + return $result; + } + + /** + * @var $data mixed + * @var $debag boolean + * + * @return string json_encode with encoding + */ + protected static function wrapData($data, $debag = false) + { + if(defined('C_REST_CURRENT_ENCODING')) + { + $data = static::changeEncoding($data, true); + } + $return = json_encode($data, JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS|JSON_HEX_QUOT); + + if($debag) + { + $e = json_last_error(); + if ($e != JSON_ERROR_NONE) + { + if ($e == JSON_ERROR_UTF8) + { + return 'Failed encoding! Recommended \'UTF - 8\' or set define C_REST_CURRENT_ENCODING = current site encoding for function iconv()'; + } + } + } + + return $return; + } + + /** + * @var $data mixed + * @var $debag boolean + * + * @return string json_decode with encoding + */ + protected static function expandData($data) + { + $return = json_decode($data, true); + if(defined('C_REST_CURRENT_ENCODING')) + { + $return = static::changeEncoding($return, false); + } + return $return; + } + + /** + * Can overridden this method to change the data storage location. + * + * @var $arSettings array settings application + * @return boolean is successes save data for setSettingData() + */ + + protected static function setSettingData($arSettings) + { + return (boolean)file_put_contents(__DIR__ . '/settings.json', static::wrapData($arSettings)); + } + + /** + * Can overridden this method to change the log data storage location. + * + * @var $arData array of logs data + * @var $type string to more identification log data + * @return boolean is successes save log data + */ + + public static function setLog($arData, $type = '') + { + $return = false; + if(!defined("C_REST_BLOCK_LOG") || C_REST_BLOCK_LOG !== true) + { + if(defined("C_REST_LOGS_DIR")) + { + $path = C_REST_LOGS_DIR; + } + else + { + $path = __DIR__ . '/logs/'; + } + $path .= date("Y-m-d/H") . '/'; + + if (!file_exists($path)) + { + @mkdir($path, 0775, true); + } + + $path .= time() . '_' . $type . '_' . rand(1, 9999999) . 'log'; + if(!defined("C_REST_LOG_TYPE_DUMP") || C_REST_LOG_TYPE_DUMP !== true) + { + $jsonLog = static::wrapData($arData); + if ($jsonLog === false) + { + $return = file_put_contents($path . '_backup.txt', var_export($arData, true)); + } + else + { + $return = file_put_contents($path . '.json', $jsonLog); + } + } + else + { + $return = file_put_contents($path . '.txt', var_export($arData, true)); + } + } + return $return; + } + + /** + * check minimal settings server to work CRest + * @var $print boolean + * @return array of errors + */ + public static function checkServer($print = true) + { + $return = []; + + //check curl lib install + if(!function_exists('curl_init')) + { + $return['curl_error'] = 'Need install curl lib.'; + } + + //creat setting file + file_put_contents(__DIR__ . '/settings_check.json', static::wrapData(['test'=>'data'])); + if(!file_exists(__DIR__ . '/settings_check.json')) + { + $return['setting_creat_error'] = 'Check permission! Recommended: folders: 775, files: 664'; + } + unlink(__DIR__ . '/settings_check.json'); + //creat logs folder and files + $path = __DIR__ . '/logs/'.date("Y-m-d/H") . '/'; + if(!mkdir($path, 0775, true) && !file_exists($path)) + { + $return['logs_folder_creat_error'] = 'Check permission! Recommended: folders: 775, files: 664'; + } + else + { + file_put_contents($path . 'test.txt', var_export(['test'=>'data'], true)); + if(!file_exists($path . 'test.txt')) + { + $return['logs_file_creat_error'] = 'check permission! recommended: folders: 775, files: 664'; + } + unlink($path . 'test.txt'); + } + + if($print === true) + { + if(empty($return)) + { + $return['success'] = 'Success!'; + } + echo '
';
+				print_r($return);
+				echo '
'; + + } + + return $return; + } + } \ No newline at end of file diff --git a/integration/contacts/crestcurrent.php b/integration/contacts/crestcurrent.php new file mode 100644 index 0000000..75c5a80 --- /dev/null +++ b/integration/contacts/crestcurrent.php @@ -0,0 +1,36 @@ +getHelperManager(); + $helper->UserTypeEntity()->saveUserTypeEntity(array ( + 'ENTITY_ID' => 'CRM_CONTACT', + 'FIELD_NAME' => 'UF_CRM_LAST_COMM_DATETIME', + 'USER_TYPE_ID' => 'datetime', + 'XML_ID' => '', + 'SORT' => '100', + 'MULTIPLE' => 'N', + 'MANDATORY' => 'N', + 'SHOW_FILTER' => 'N', + 'SHOW_IN_LIST' => 'Y', + 'EDIT_IN_LIST' => 'Y', + 'IS_SEARCHABLE' => 'N', + 'SETTINGS' => + array ( + 'DEFAULT_VALUE' => + array ( + 'TYPE' => 'NONE', + 'VALUE' => '', + ), + 'USE_SECOND' => 'Y', + 'USE_TIMEZONE' => 'N', + ), + 'EDIT_FORM_LABEL' => + array ( + 'en' => 'Дата последней коммуникации', + 'ru' => 'Дата последней коммуникации', + ), + 'LIST_COLUMN_LABEL' => + array ( + 'en' => '', + 'ru' => '', + ), + 'LIST_FILTER_LABEL' => + array ( + 'en' => '', + 'ru' => '', + ), + 'ERROR_MESSAGE' => + array ( + 'en' => '', + 'ru' => '', + ), + 'HELP_MESSAGE' => + array ( + 'en' => '', + 'ru' => '', + ), +)); + } + +}