├── README.en.md ├── README.md ├── clientExamples └── instantcms │ ├── README.md │ └── api.php ├── icon.png ├── install.php ├── install.sql ├── manifest.en.ini ├── manifest.ru.ini └── package ├── system ├── controllers │ └── api │ │ ├── actions │ │ └── method.php │ │ ├── api_actions │ │ ├── api_auth_confirm.php │ │ ├── api_auth_login.php │ │ ├── api_auth_logout.php │ │ ├── api_auth_reset.php │ │ ├── api_auth_restore.php │ │ ├── api_auth_signup.php │ │ ├── api_auth_signup_fields.php │ │ ├── api_content_add_item.php │ │ ├── api_content_get.php │ │ ├── api_content_get_categories.php │ │ ├── api_content_get_ctypes.php │ │ ├── api_content_get_datasets.php │ │ ├── api_content_get_fields.php │ │ ├── api_content_get_folders.php │ │ ├── api_content_get_item.php │ │ ├── api_content_get_props.php │ │ ├── api_content_get_props_values.php │ │ ├── api_content_update_item.php │ │ ├── api_geo_get.php │ │ ├── api_geo_get_current_country.php │ │ ├── api_images_get_presets.php │ │ ├── api_images_upload.php │ │ ├── api_messages_delete_contact.php │ │ ├── api_messages_delete_mesages.php │ │ ├── api_messages_delete_notice.php │ │ ├── api_messages_forgive.php │ │ ├── api_messages_get.php │ │ ├── api_messages_get_notices.php │ │ ├── api_messages_ignore.php │ │ ├── api_messages_readed.php │ │ ├── api_messages_restore_mesage.php │ │ ├── api_messages_send.php │ │ ├── api_users_add.php │ │ ├── api_users_add_to_groups.php │ │ ├── api_users_email_exists.php │ │ ├── api_users_get_groups.php │ │ ├── api_users_get_sig.php │ │ ├── api_users_remove_from_groups.php │ │ ├── api_users_update_password.php │ │ ├── api_users_update_password_fields.php │ │ ├── api_widgets_get_pages.php │ │ └── api_widgets_get_widgets.php │ │ ├── backend.php │ │ ├── backend │ │ ├── actions │ │ │ ├── keys.php │ │ │ ├── keys_add.php │ │ │ ├── keys_delete.php │ │ │ └── keys_edit.php │ │ ├── forms │ │ │ ├── form_key.php │ │ │ └── form_options.php │ │ └── grids │ │ │ └── grid_keys.php │ │ ├── frontend.php │ │ ├── hooks │ │ └── admin_dashboard_chart.php │ │ └── model.php └── languages │ ├── en │ └── controllers │ │ └── api │ │ └── api.php │ └── ru │ └── controllers │ └── api │ └── api.php └── templates └── default └── controllers └── api └── backend ├── key.tpl.php └── keys.tpl.php /README.en.md: -------------------------------------------------------------------------------- 1 | # InstantCMS JSON API 2 | 3 | This component is for InstantCMS/Mobile app developers who want to use InstantCMS as mobile app data backend. 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # InstantCMS JSON API 2 | 3 | Компонент для InstantCMS. Реализует легкое API между сайтом и сторонним сервисом, например, мобильным приложением. 4 | 5 | ## Основные преимущества и функциональность 6 | 7 | * Бесплатный (GNU/GPL v2); 8 | * Удобная обработка ошибок; 9 | * Логирование запросов; 10 | * Автоматическая валидация входных данных; 11 | * Одна точка входа для всех методов API; 12 | * Поддержка универсального запроса, в котором можно запросить несколько методов API; 13 | * Стиль API Вконтакте для лёгкого внедрения и понимания. 14 | 15 | ## Ссылки 16 | 17 | * [Официальный сайт InstantCMS](https://instantcms.ru/) 18 | * [Документация компонента](https://docs.instantcms.ru/manual/components/api) 19 | * [English README](https://github.com/instantsoft/icms2-json-api-component/blob/master/README.en.md) 20 | -------------------------------------------------------------------------------- /clientExamples/instantcms/README.md: -------------------------------------------------------------------------------- 1 | # InstantCMS JSON API client class 2 | 3 | Класс для работы с API с сайта на базе InstantCMS 4 | 5 | ## Установка 6 | 7 | Файл api.php скопировать по пути /system/core/api.php 8 | 9 | ## Использование 10 | 11 | Заполнить константы api_key, api_point, api_point_execute своими данными (example.com заменить на свой домен). 12 | Создать директорию /cache/api/. В ней будут кэшироваться ответы. 13 | 14 | Вызовы можно осуществлять из любого места кода InstantCMS 15 | 16 | Обычные методы 17 | ```php 18 | // Без кэширования ответа 19 | $result = cmsApi::getMethod('auth.login', ['sig' => 'qwerty', 'email' => 'test@example.com', 'password' => '123456']); 20 | // С кэшированием ответа 21 | $result = cmsApi::getMethod('auth.login', ['sig' => 'qwerty', 'email' => 'test@example.com', 'password' => '123456'], true); 22 | ``` 23 | 24 | Метод execute 25 | ```php 26 | $result = cmsApi::getExecute([ 27 | [ 28 | 'method' => 'geo.get', 29 | 'key' => 'countries', 30 | 'params' => [ 31 | 'type' => 'countries' 32 | ] 33 | ], 34 | [ 35 | 'method' => 'users.get_user', 36 | 'key' => 'profile', 37 | 'params' => [ 38 | 'user_id' => $user_id 39 | ] 40 | ] 41 | ]); 42 | ``` 43 | 44 | ## Ссылки 45 | 46 | * [Официальный сайт InstantCMS](https://instantcms.ru/) 47 | * [Документация компонента](https://docs.instantcms.ru/manual/components/api) -------------------------------------------------------------------------------- /clientExamples/instantcms/api.php: -------------------------------------------------------------------------------- 1 | [ 80 | 'error_msg' => 'Please, install curl' 81 | ] 82 | ]; 83 | } 84 | 85 | if(!$api_point){ 86 | $api_point = self::getApiPoint(); 87 | } 88 | 89 | if ($cacheable) { 90 | 91 | $cache_file = cmsConfig::get('cache_path') . 'api/' . md5($name . serialize($params) . cmsCore::getLanguageName()) . '.dat'; 92 | 93 | if (is_readable($cache_file)) { 94 | 95 | $time_diff = (time() - filemtime($cache_file)); 96 | 97 | if ($time_diff < self::cache_time) { 98 | 99 | $result = include $cache_file; 100 | 101 | if ($result) { 102 | return $result; 103 | } else { 104 | unlink($cache_file); 105 | } 106 | 107 | } else { 108 | unlink($cache_file); 109 | } 110 | } 111 | } 112 | 113 | $curl = curl_init(); 114 | 115 | if (isset($params['cookie'])) { 116 | 117 | $cookie = []; 118 | 119 | foreach ($params['cookie'] as $k => $v) { 120 | $cookie[] = $k . '=' . $v; 121 | } 122 | 123 | curl_setopt($curl, CURLOPT_HTTPHEADER, ['Cookie: ' . implode('; ', $cookie)]); 124 | 125 | unset($params['cookie']); 126 | 127 | } elseif (cmsUser::isLogged()) { 128 | 129 | curl_setopt($curl, CURLOPT_HTTPHEADER, ['Cookie: ' . cmsUser::sessionGet('user_session:session_name') . '=' . cmsUser::sessionGet('user_session:session_id')]); 130 | 131 | } elseif (cmsUser::isSessionSet('guest_session:session_id')) { 132 | 133 | curl_setopt($curl, CURLOPT_HTTPHEADER, ['Cookie: ' . cmsUser::sessionGet('guest_session:session_name') . '=' . cmsUser::sessionGet('guest_session:session_id')]); 134 | } 135 | 136 | $params['api_key'] = self::api_key; 137 | $params['ip'] = cmsUser::getIp(); 138 | 139 | $params_string = !$is_upload ? http_build_query($params) : $params; 140 | 141 | curl_setopt($curl, CURLOPT_URL, $api_point . $name); 142 | curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); 143 | curl_setopt($curl, CURLOPT_HEADER, false); 144 | curl_setopt($curl, CURLOPT_TIMEOUT, 5); 145 | curl_setopt($curl, CURLOPT_POSTFIELDS, $params_string); 146 | 147 | $_data = curl_exec($curl); 148 | 149 | if (!$_data) { 150 | return [ 151 | 'error' => [ 152 | 'error_msg' => LANG_API_ERROR 153 | ] 154 | ]; 155 | } 156 | 157 | $data = json_decode($_data, true); 158 | 159 | curl_close($curl); 160 | 161 | if ($data === false) { 162 | return [ 163 | 'error' => [ 164 | 'error_msg' => json_last_error_msg() 165 | ] 166 | ]; 167 | } 168 | 169 | if (isset($data['session'])) { 170 | cmsUser::sessionSet('guest_session:session_name', $data['session']['session_name']); 171 | cmsUser::sessionSet('guest_session:session_id', $data['session']['session_id']); 172 | } 173 | 174 | if ($cacheable) { 175 | file_put_contents($cache_file, ' json_encode($params)], $cacheable, $is_upload, self::getApiExecutePoint()); 193 | } 194 | 195 | public static function arrayToForm($data) { 196 | 197 | $form = new cmsForm(); 198 | 199 | $form->addFieldset('', 'basic'); 200 | 201 | foreach ($data as $fsets) { 202 | foreach ($fsets['fields'] as $field) { 203 | 204 | if($field['name'] == 'csrf_token'){ 205 | cmsUser::sessionSet('csrf_token', $field['default']); 206 | continue; 207 | } 208 | 209 | $field_class = 'field' . string_to_camel('_', $field['field_type'] ); 210 | 211 | $form->addField('basic', 212 | new $field_class($field['name'], $field) 213 | ); 214 | 215 | } 216 | } 217 | 218 | return $form; 219 | 220 | } 221 | 222 | } 223 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/instantsoft/icms2-json-api-component/13ae80e4d5e3c750dac0cc4d8950f9e5571db616/icon.png -------------------------------------------------------------------------------- /install.php: -------------------------------------------------------------------------------- 1 | loadApiKey(); 33 | 34 | } 35 | 36 | /** 37 | * Инициализирует метод: 38 | * загружает контроллер, экшен 39 | * @param string $method_name 40 | * @return \actionApiMethod 41 | */ 42 | private function initMethod($method_name) { 43 | 44 | $this->method_name = $method_name; 45 | 46 | if (!$this->method_name) { 47 | return $this; 48 | } 49 | 50 | $segments = explode('.', $method_name); 51 | 52 | // контроллер 53 | if (isset($segments[0])) { 54 | 55 | $this->method_controller_name = trim($segments[0]); 56 | 57 | if ($this->method_controller_name && !preg_match('/^[a-z]{1}[a-z0-9_]*$/', $this->method_controller_name)) { 58 | $this->method_controller_name = null; 59 | } 60 | 61 | if ($this->method_controller_name && !cmsCore::isControllerExists($this->method_controller_name)) { 62 | $this->method_controller_name = null; 63 | } 64 | 65 | if ($this->method_controller_name) { 66 | $this->method_controller = cmsCore::getController($this->method_controller_name, $this->request); 67 | } 68 | } 69 | // действие 70 | if (isset($segments[1])) { 71 | 72 | $this->method_action_name = trim($segments[1]); 73 | 74 | if ($this->method_action_name && !preg_match('/^[a-z]{1}[a-z0-9_]*$/', $this->method_action_name)) { 75 | $this->method_action_name = null; 76 | } 77 | 78 | if ($this->method_action_name && $this->method_controller !== null) { 79 | $this->method_controller->current_action = 'api_' . $this->method_controller_name . '_' . $this->method_action_name; 80 | } 81 | } 82 | // Параметры действия 83 | if (count($segments) > 2) { 84 | $this->method_params = array_slice($segments, 2); 85 | } 86 | 87 | return $this; 88 | } 89 | 90 | /** 91 | * Выполняет метод api запроса 92 | * Метод строится по принципу controller.action_name 93 | * action_name - это специальный экшен. В самом контроллере-родителе он 94 | * называться должен с префиксом api_request_, например api_request_action_name 95 | * @param string $method_name Название метода API 96 | */ 97 | public function run($method_name = null){ 98 | 99 | // устанавливаем метод и проверяем запрос 100 | if(!$this->initMethod($method_name)->checkRequest()){ 101 | return false; 102 | } 103 | 104 | // проверяем сначала экшен 105 | // Важно! Болокируйте экшен от прямого выполнения свойством lock_explicit_call 106 | // https://docs.instantcms.ru/dev/controllers/actions#действия-во-внешних-файлах 107 | 108 | $api_dir_action_file = $this->root_path.'api_actions/'.$this->method_controller->current_action.'.php'; 109 | $action_file = $this->method_controller->root_path.'actions/'.$this->method_controller->current_action.'.php'; 110 | $action_file = is_readable($api_dir_action_file) ? $api_dir_action_file : $action_file; 111 | 112 | if(is_readable($action_file)){ 113 | 114 | $class_name = 'action'.string_to_camel('_', $this->method_controller_name).string_to_camel('_', $this->method_controller->current_action); 115 | 116 | include_once $action_file; 117 | 118 | if(!class_exists($class_name, false)){ 119 | cmsCore::error(sprintf(ERR_CLASS_NOT_DEFINED, str_replace(PATH, '', $action_file), $class_name)); 120 | } 121 | 122 | $this->method_action = new $class_name($this->method_controller); 123 | 124 | } else { 125 | 126 | // теперь проверяем хук 127 | $hook_file = $this->method_controller->root_path . 'hooks/'.$this->method_controller->current_action.'.php'; 128 | 129 | $class_name = 'on'.string_to_camel('_', $this->method_controller_name).string_to_camel('_', $this->method_controller->current_action); 130 | 131 | if (is_readable($hook_file)){ 132 | 133 | if (!class_exists($class_name, false)){ 134 | include_once $hook_file; 135 | } 136 | 137 | if(!class_exists($class_name, false)){ 138 | cmsCore::error(sprintf(ERR_CLASS_NOT_DEFINED, str_replace(PATH, '', $hook_file), $class_name)); 139 | } 140 | 141 | $this->method_action = new $class_name($this->method_controller); 142 | 143 | } 144 | 145 | } 146 | 147 | // нечего запускать 148 | if($this->method_action === null){ 149 | return $this->error(3); 150 | } 151 | 152 | // ставим свойство результирующего массива, если такового нет 153 | if(!isset($this->method_action->result)){ 154 | $this->method_action->result = array( 155 | 'count' => 0, 156 | 'items' => array() 157 | ); 158 | } 159 | 160 | // если передан ip адрес, считаем его адресом посетителя 161 | // для различных проверок компонентов 162 | // т.к. движок определяет ip адрес места запроса 163 | if($this->request->has('ip')){ 164 | 165 | $ip = $this->request->get('ip', ''); 166 | 167 | if (!$ip || filter_var($ip, FILTER_VALIDATE_IP) !== $ip) { 168 | return $this->error(777); 169 | } 170 | 171 | // совместимость 172 | if(method_exists('cmsUser', 'setIp')){ 173 | cmsUser::setIp($ip); 174 | } 175 | 176 | } 177 | 178 | // проверяем csrf, если включена проверка 179 | if(!empty($this->method_action->check_csrf)){ 180 | if (!cmsForm::validateCSRFToken($this->request->get('csrf_token', ''))){ 181 | return $this->error(0, LANG_API_ERROR_CSRF_TOKEN); 182 | } 183 | } 184 | 185 | // проверяем sig, если включена проверка 186 | if(!empty($this->method_action->check_sig)){ 187 | if(!check_sig($this->request->get('sig', ''))){ 188 | return $this->error(115); 189 | } 190 | } 191 | 192 | // проверяем авторизацию, если метод её требует 193 | if(!empty($this->method_action->auth_required)){ 194 | if(!$this->cms_user->is_logged){ 195 | return $this->error(71); 196 | } 197 | } 198 | 199 | // проверяем админ доступ, если метод этого требует 200 | if(!empty($this->method_action->admin_required)){ 201 | if(!$this->cms_user->is_logged){ 202 | return $this->error(71); 203 | } 204 | if(!$this->cms_user->is_admin){ 205 | return $this->error(710); 206 | } 207 | // грузим язык админки 208 | cmsCore::loadControllerLanguage('admin'); 209 | } 210 | 211 | // ставим ключ API в свойство 212 | $this->method_action->key = $this->key; 213 | $this->method_action->method_name = $this->method_name; 214 | // опции api в свойство 215 | $this->method_action->api_options = $this->options; 216 | 217 | // валидация параметров запроса 218 | $params_error = $this->validateMethodParams(); 219 | if($params_error !== false){ 220 | return $this->error(100, '', $params_error); 221 | } 222 | 223 | // валидация запроса, если нужна 224 | if(method_exists($this->method_action, 'validateApiRequest')){ 225 | $error = call_user_func_array(array($this->method_action, 'validateApiRequest'), $this->method_params); 226 | if($error !== false){ 227 | return $this->error( 228 | (isset($error['error_code']) ? $error['error_code'] : 100), 229 | (isset($error['error_msg']) ? $error['error_msg'] : ''), 230 | (isset($error['request_params']) ? $error['request_params'] : array()) 231 | ); 232 | } 233 | } 234 | 235 | // сам запрос 236 | // экшен/хук формирует данные в свойство $this->method_action->result 237 | // вся обработка ошибок на этом этапе должна быть закончена 238 | call_user_func_array(array($this->method_action, 'run'), $this->method_params); 239 | 240 | // если нужно убрать ячейки 241 | if(isset($this->method_action->unset_fields)){ 242 | foreach ($this->method_action->unset_fields as $key_name => $unset) { 243 | 244 | if($unset['type'] == 'item'){ 245 | 246 | foreach ($unset['unsets'] as $unset_field) { 247 | unset($this->method_action->result[$key_name][$unset_field]); 248 | } 249 | 250 | } else { 251 | 252 | foreach ($this->method_action->result[$key_name] as $key => $item) { 253 | foreach ($unset['unsets'] as $unset_field) { 254 | unset($this->method_action->result[$key_name][$key][$unset_field]); 255 | } 256 | } 257 | 258 | } 259 | 260 | } 261 | } 262 | 263 | // если передали разбивку на страницы, формируем флаг наличия следующей страницы 264 | if(!empty($this->method_action->result['paging'])){ 265 | 266 | $pages = ceil($this->method_action->result['count'] / $this->method_action->result['paging']['per_page']); 267 | if($pages > $this->method_action->result['paging']['page']){ 268 | $this->method_action->result['paging']['has_next'] = true; 269 | } else { 270 | $this->method_action->result['paging']['has_next'] = false; 271 | } 272 | 273 | } 274 | 275 | // фиксируем результат запроса 276 | $this->setSuccess($this->method_action->result); 277 | 278 | // действия после успешного запроса 279 | return $this->afterRequest(); 280 | } 281 | 282 | /** 283 | * Действия после успешного запроса 284 | * @return boolean 285 | */ 286 | private function afterRequest() { 287 | 288 | // записываем в лог, если включено 289 | if (!empty($this->options['log_success'])) { 290 | 291 | $this->model->log([ 292 | 'request_time' => number_format((microtime(true) - $this->start_time), 4), 293 | 'method' => $this->method_name, 294 | 'key_id' => $this->key['id'] 295 | ]); 296 | } 297 | 298 | return true; 299 | } 300 | 301 | private function validateMethodParams() { 302 | 303 | if (empty($this->method_action->request_params)) { 304 | return false; 305 | } 306 | 307 | $errors = []; 308 | 309 | // валидация аналогична валидации форм 310 | foreach ($this->method_action->request_params as $param_name => $rules) { 311 | 312 | $value = $this->request->get($param_name, null); 313 | 314 | if (is_null($value) && isset($rules['default'])) { 315 | 316 | $value = $rules['default']; 317 | 318 | $this->request->set($param_name, $value); 319 | 320 | } elseif (!is_null($value) && isset($rules['default'])) { 321 | 322 | $value = $this->request->get($param_name, $rules['default']); 323 | 324 | // для применения типизации переменной 325 | $this->request->set($param_name, $value); 326 | } 327 | 328 | if (!empty($rules['rules'])) { 329 | foreach ($rules['rules'] as $rule) { 330 | 331 | if (!$rule) { 332 | continue; 333 | } 334 | 335 | $validate_function = "validate_{$rule[0]}"; 336 | 337 | $rule[] = $value; 338 | 339 | unset($rule[0]); 340 | 341 | $result = call_user_func_array([$this, $validate_function], $rule); 342 | 343 | // если получилось false, то дальше не проверяем, т.к. 344 | // ошибка уже найдена 345 | if ($result !== true) { 346 | $errors[$param_name] = $result; 347 | break; 348 | } 349 | } 350 | } 351 | } 352 | 353 | if (!sizeof($errors)) { 354 | return false; 355 | } 356 | 357 | return $errors; 358 | } 359 | 360 | /** 361 | * Проверяет запрос на ошибки 362 | * @return boolean 363 | */ 364 | public function checkRequest() { 365 | 366 | $parent_succes = parent::checkRequest(); 367 | 368 | if (!$parent_succes) { 369 | return false; 370 | } 371 | 372 | if (empty($this->method_name) || 373 | empty($this->method_controller_name) || 374 | $this->method_controller === null) { 375 | 376 | return $this->error(3); 377 | } 378 | 379 | if (empty($this->method_action_name)) { 380 | return $this->error(8); 381 | } 382 | 383 | if (!$this->method_controller->isEnabled()) { 384 | return $this->error(23); 385 | } 386 | 387 | $check_method_name = $this->method_controller_name . '.' . $this->method_action_name; 388 | 389 | $is_view = !$this->key['key_methods']['allow'] || in_array($check_method_name, $this->key['key_methods']['allow']); 390 | $is_hide = $this->key['key_methods']['disallow'] && in_array($check_method_name, $this->key['key_methods']['disallow']); 391 | 392 | // проверяем доступ к методу 393 | if (!$is_view || $is_hide) { 394 | return $this->error(24); 395 | } 396 | 397 | return true; 398 | } 399 | 400 | } 401 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_auth_confirm.php: -------------------------------------------------------------------------------- 1 | array( 27 | 'default' => '', 28 | 'rules' => array( 29 | array('required'), 30 | array('regexp', '/^[0-9a-f]{32}$/i') 31 | ) 32 | ) 33 | ); 34 | 35 | private $user; 36 | 37 | public function validateApiRequest() { 38 | 39 | if (empty($this->options['is_reg_enabled'])){ 40 | return array('error_code' => 323); 41 | } 42 | 43 | if (!$this->isIPAllowed(cmsUser::get('ip'))){ 44 | 45 | return array( 46 | 'error_code' => 15, 47 | 'error_msg' => strip_tags(sprintf(LANG_AUTH_RESTRICTED_IP, cmsUser::get('ip'))) 48 | ); 49 | 50 | } 51 | 52 | $this->user = $this->model_users->getUserByPassToken($this->request->get('code', '')); 53 | if (!$this->user) { 54 | return array('error_code' => 1110); 55 | } 56 | 57 | return false; 58 | 59 | } 60 | 61 | public function run(){ 62 | 63 | $this->model_users->unlockUser($this->user['id']); 64 | $this->model_users->clearUserPassToken($this->user['id']); 65 | 66 | cmsEventsManager::hook('user_registered', $this->user); 67 | 68 | $auth_user = array(); 69 | 70 | if ($this->options['reg_auto_auth']){ 71 | 72 | $this->user = $this->model_users->getUser($this->user['id']); 73 | 74 | $this->user['avatar'] = cmsModel::yamlToArray($this->user['avatar']); 75 | if ($this->user['avatar']){ 76 | foreach($this->user['avatar'] as $size => $path){ 77 | $this->user['avatar'][$size] = $this->cms_config->upload_host_abs.'/'.$path; 78 | } 79 | } 80 | 81 | $this->user = cmsEventsManager::hook('user_login', $this->user); 82 | 83 | cmsUser::setUserSession($this->user); 84 | 85 | $this->model_users->updateUserIp($this->user['id']); 86 | 87 | cmsEventsManager::hook('auth_login', $this->user['id']); 88 | 89 | unset($this->user['password_hash'], $this->user['password'], $this->user['password_salt'], $this->user['pass_token'], $this->user['date_token'], $this->user['ip'], $this->user['is_admin']); 90 | 91 | $auth_user = array( 92 | 'session_name' => session_name(), 93 | 'session_id' => session_id(), 94 | 'expires_in' => ini_get('session.gc_maxlifetime'), 95 | 'user_id' => $this->user['id'], 96 | 'user_info' => $this->user 97 | ); 98 | 99 | } 100 | 101 | $this->result = array( 102 | 'auth_user' => $auth_user, 103 | 'success' => true, 104 | 'success_text' => LANG_REG_SUCCESS_VERIFIED 105 | ); 106 | 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_auth_login.php: -------------------------------------------------------------------------------- 1 | array( 33 | 'default' => '', 34 | 'rules' => array( 35 | array('required'), 36 | array('email') 37 | ) 38 | ), 39 | 'password' => array( 40 | 'default' => '', 41 | 'rules' => array( 42 | array('required') 43 | ) 44 | ), 45 | 'remember' => array( 46 | 'default' => 0 47 | ) 48 | ); 49 | 50 | /** 51 | * Массив ключей для удаления 52 | * @var array 53 | */ 54 | public $unset_fields = array( 55 | 'user_info' => array( // название ключа в $this->result 56 | 'type' => 'item', // list или item 57 | 'unsets' => array( // массив названий ключей для удаления 58 | 'password_hash', 'date_token', 'ip', 'is_admin', 'ga_secret' 59 | ) 60 | ) 61 | ); 62 | 63 | private $user = []; 64 | private $wait_2fa = false; 65 | private $twofa_type = ''; 66 | private $twofa_params = []; 67 | 68 | public function validateApiRequest() { 69 | 70 | cmsCore::loadControllerLanguage('users'); 71 | 72 | // если авторизован, проверки не выполняем 73 | if($this->cms_user->is_logged){ 74 | 75 | $this->user = $this->model_users->getUser($this->cms_user->id); 76 | 77 | return false; 78 | 79 | } 80 | 81 | $logged_user = cmsUser::login($this->request->get('email'), $this->request->get('password'), $this->request->get('remember'), false); 82 | 83 | if (!$logged_user){ 84 | return array( 85 | 'error_code' => 5 86 | ); 87 | } 88 | 89 | // Включена ли двухфакторная авторизация 90 | if(!empty($logged_user['2fa']) && !empty($this->options['2fa_params'][$logged_user['2fa']])){ 91 | 92 | $twofa_params = $this->options['2fa_params'][$logged_user['2fa']]; 93 | 94 | $context_request = clone $this->request; 95 | 96 | // Чтобы сработало свойство $lock_explicit_call в экшене $twofa_params['action'] 97 | $context_request->setContext(cmsRequest::CTX_INTERNAL); 98 | 99 | // Говорим, что это вызов из API 100 | $context_request->set('api_context', true); 101 | 102 | $result = cmsCore::getController($twofa_params['controller'], $context_request)-> 103 | executeAction($twofa_params['action'], [$logged_user, new cmsForm(), [ 104 | 'email' => $this->request->get('email'), 105 | 'password' => $this->request->get('password'), 106 | 'remember' => $this->request->get('remember') 107 | ]]); 108 | 109 | // Говорим методу run(), что нужен 2fa 110 | if($result !== true){ 111 | 112 | // Если уже был сабмит параметров 113 | // и возникли ошибки 114 | if($result['errors']){ 115 | 116 | return array( 117 | 'error_code' => 100, 118 | 'error_msg' => '', 119 | 'request_params' => $result['errors'] 120 | ); 121 | 122 | } 123 | 124 | $this->wait_2fa = true; 125 | $this->twofa_type = $logged_user['2fa']; 126 | 127 | $result['form'] = form_to_params($result['form']); 128 | 129 | $this->twofa_params = $result; 130 | 131 | // Передаём управление в метод run() 132 | return false; 133 | } 134 | 135 | } 136 | 137 | if (empty($this->api_options['allow_admin_login']) && $logged_user['is_admin']) { 138 | return array('error_code' => 15); 139 | } 140 | 141 | // Проверяем блокировку пользователя 142 | if ($logged_user['is_locked']) { 143 | 144 | $now = time(); 145 | $lock_until = !empty($logged_user['lock_until']) ? strtotime($logged_user['lock_until']) : false; 146 | 147 | if ($lock_until && ($lock_until <= $now)){ 148 | $this->model_users->unlockUser($logged_user['id']); 149 | } else { 150 | 151 | $notice_text = array(LANG_USERS_LOCKED_NOTICE); 152 | 153 | if($logged_user['lock_until']) { 154 | $notice_text[] = sprintf(LANG_USERS_LOCKED_NOTICE_UNTIL, $logged_user['lock_until']); 155 | } 156 | 157 | if($logged_user['lock_reason']) { 158 | $notice_text[] = sprintf(LANG_USERS_LOCKED_NOTICE_REASON, $logged_user['lock_reason']); 159 | } 160 | 161 | if($logged_user['lock_reason']){ 162 | $this->model_users->update('{users}', $logged_user['id'], array( 163 | 'ip' => null 164 | ), true); 165 | } 166 | 167 | return array('error_msg' => implode("\n", $notice_text)); 168 | 169 | } 170 | 171 | } 172 | 173 | // завершаем авторизацию 174 | cmsUser::loginComplete($logged_user, $this->request->get('remember')); 175 | 176 | $is_first_auth = cmsUser::getUPS('first_auth', $logged_user['id']); 177 | 178 | if ($is_first_auth){ 179 | cmsUser::deleteUPS('first_auth', $logged_user['id']); 180 | } 181 | 182 | // Всё успешно 183 | $this->user = $logged_user; 184 | 185 | $this->user['avatar'] = cmsModel::yamlToArray($this->user['avatar']); 186 | if ($this->user['avatar']){ 187 | foreach($this->user['avatar'] as $size => $path){ 188 | $this->user['avatar'][$size] = $this->cms_config->upload_host_abs.'/'.$path; 189 | } 190 | } 191 | 192 | $this->user['is_online'] = true; 193 | 194 | return false; 195 | 196 | } 197 | 198 | public function run(){ 199 | 200 | $is_first_auth = null; 201 | 202 | if(!empty($this->user['id'])){ 203 | if(cmsUser::getUPS('first_auth', $this->user['id'])){ 204 | cmsUser::deleteUPS('first_auth', $this->user['id']); 205 | $is_first_auth = true; 206 | } else { 207 | $is_first_auth = false; 208 | } 209 | } 210 | 211 | $this->result = array( 212 | 'wait_2fa' => $this->wait_2fa, 213 | '2fa_type' => $this->twofa_type, 214 | '2fa_params' => $this->twofa_params, 215 | 'is_first_auth' => $is_first_auth, 216 | 'remember_token' => (isset(cmsUser::$auth_token) ? cmsUser::$auth_token : false), 217 | 'session_name' => session_name(), 218 | 'session_id' => session_id(), 219 | 'expires_in' => ini_get('session.gc_maxlifetime'), 220 | 'user_id' => !empty($this->user['id']) ? intval($this->user['id']) : 0, 221 | 'user_info' => $this->user 222 | ); 223 | 224 | } 225 | 226 | } 227 | 228 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_auth_logout.php: -------------------------------------------------------------------------------- 1 | cms_user->id; 14 | 15 | cmsEventsManager::hook('auth_logout', $this->cms_user->id); 16 | 17 | cmsUser::logout(); 18 | 19 | $this->result = array( 20 | 'user_id' => $user_id 21 | ); 22 | 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_auth_reset.php: -------------------------------------------------------------------------------- 1 | array( 34 | 'default' => '', 35 | 'rules' => array( 36 | array('required'), 37 | array('regexp', '/^[0-9a-f]{32}$/i') 38 | ) 39 | ), 40 | 'password1' => array( 41 | 'default' => '', 42 | 'rules' => array( 43 | array('required'), 44 | array('min_length', 6) 45 | ) 46 | ), 47 | 'password2' => array( 48 | 'default' => '', 49 | 'rules' => array( 50 | array('required'), 51 | array('min_length', 6) 52 | ) 53 | ), 54 | ); 55 | 56 | private $user; 57 | 58 | public function validateApiRequest() { 59 | 60 | $pass_token = $this->request->get('code', ''); 61 | 62 | $this->user = $this->model_users->getUserByPassToken($pass_token); 63 | 64 | if (!$this->user) { 65 | return array('error_code' => 113); 66 | } 67 | 68 | if ($this->user['is_admin']) { 69 | return array('error_code' => 15); 70 | } 71 | 72 | if($this->user['is_locked']) { 73 | 74 | return array('request_params' => array( 75 | 'code' => LANG_RESTORE_BLOCK.($this->user['lock_reason'] ? '. '.$this->user['lock_reason'] : '') 76 | )); 77 | 78 | } 79 | 80 | if ((strtotime($this->user['date_token']) + 3600) < time()){ 81 | 82 | $this->model_users->clearUserPassToken($this->user['id']); 83 | 84 | return array('request_params' => array( 85 | 'code' => LANG_RESTORE_TOKEN_EXPIRED 86 | )); 87 | 88 | } 89 | 90 | if($this->request->get('password1', '') !== $this->request->get('password2', '')) { 91 | 92 | return array('request_params' => array( 93 | 'password1' => LANG_REG_PASS_NOT_EQUAL, 94 | 'password2' => LANG_REG_PASS_NOT_EQUAL 95 | )); 96 | 97 | } 98 | 99 | return false; 100 | 101 | } 102 | 103 | public function run(){ 104 | 105 | $this->model_users->updateUser($this->user['id'], array( 106 | 'password1' => $this->request->get('password1', ''), 107 | 'password2' => $this->request->get('password2', '') 108 | )); 109 | 110 | $this->model_users->clearUserPassToken($this->user['id']); 111 | 112 | $this->result = array( 113 | 'user_id' => $this->user['id'], 114 | 'success' => true, 115 | 'success_text' => LANG_PASS_CHANGED 116 | ); 117 | 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_auth_restore.php: -------------------------------------------------------------------------------- 1 | array( 27 | 'default' => '', 28 | 'rules' => array( 29 | array('required'), 30 | array('email') 31 | ) 32 | ), 33 | ); 34 | 35 | private $user; 36 | 37 | public function validateApiRequest() { 38 | 39 | $email = $this->request->get('email', ''); 40 | 41 | $this->user = $this->model_users->getUserByEmail($email); 42 | 43 | if (!$this->user) { 44 | return array('error_code' => 113); 45 | } 46 | 47 | if ($this->user['is_admin']) { 48 | return array('error_code' => 15); 49 | } 50 | 51 | if($this->user['is_locked']) { 52 | 53 | return array('request_params' => array( 54 | 'email' => LANG_RESTORE_BLOCK.($this->user['lock_reason'] ? '. '.$this->user['lock_reason'] : '') 55 | )); 56 | 57 | } elseif($this->user['pass_token']) { 58 | 59 | return array('request_params' => array( 60 | 'email' => LANG_RESTORE_TOKEN_IS_SEND 61 | )); 62 | 63 | } 64 | 65 | return false; 66 | 67 | } 68 | 69 | public function run(){ 70 | 71 | $pass_token = string_random(32, $this->user['email']); 72 | 73 | $this->model_users->updateUserPassToken($this->user['id'], $pass_token); 74 | 75 | $messenger = cmsCore::getController('messages'); 76 | 77 | $to = array('email' => $this->user['email'], 'name' => $this->user['nickname']); 78 | $letter = array('name' => 'reg_restore'); 79 | 80 | $messenger->sendEmail($to, $letter, array( 81 | 'nickname' => $this->user['nickname'], 82 | 'page_url' => href_to_abs('auth', 'reset', $pass_token), 83 | 'pass_token' => $pass_token, 84 | 'valid_until' => html_date(date('d.m.Y H:i', time() + (24 * 3600)), true), 85 | )); 86 | 87 | $this->result = array( 88 | 'user_id' => $this->user['id'], 89 | 'success' => true, 90 | 'success_text' => LANG_TOKEN_SENDED, 91 | 'sig' => get_sig() 92 | ); 93 | 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_auth_signup.php: -------------------------------------------------------------------------------- 1 | options['is_reg_enabled'])){ 38 | return array('error_code' => 323); 39 | } 40 | 41 | if (!$this->isIPAllowed(cmsUser::get('ip'))){ 42 | 43 | return array( 44 | 'error_code' => 15, 45 | 'error_msg' => strip_tags(sprintf(LANG_AUTH_RESTRICTED_IP, cmsUser::get('ip'))) 46 | ); 47 | 48 | } 49 | 50 | $form = $this->getForm('registration'); 51 | if(!$form){ return array('error_code' => 1); } 52 | 53 | // 54 | // Добавляем поле для кода приглашения, 55 | // если регистрация доступна только по приглашениям 56 | // 57 | if ($this->options['is_reg_invites']){ 58 | 59 | $fieldset_id = $form->addFieldsetToBeginning(LANG_REG_INVITED_ONLY); 60 | 61 | $form->addField($fieldset_id, new fieldString('inv', array( 62 | 'title' => LANG_REG_INVITE_CODE, 63 | 'rules' => array( 64 | array('required'), 65 | array('min_length', 10), 66 | array('max_length', 10) 67 | ) 68 | ))); 69 | 70 | } 71 | 72 | // 73 | // Добавляем поле выбора группы, 74 | // при наличии публичных групп 75 | // 76 | $public_groups = $this->model_users->getPublicGroups(); 77 | 78 | if ($public_groups) { 79 | 80 | $pb_items = array(); 81 | foreach($public_groups as $pb) { $pb_items[ $pb['id'] ] = $pb['title']; } 82 | 83 | $form->addFieldToBeginning('basic', 84 | new fieldList('group_id', array( 85 | 'title' => LANG_USER_GROUP, 86 | 'items' => $pb_items 87 | ) 88 | ) 89 | ); 90 | 91 | } 92 | 93 | // 94 | // Добавляем в форму обязательные поля профилей 95 | // 96 | $content_model = cmsCore::getModel('content'); 97 | $content_model->setTablePrefix(''); 98 | $content_model->orderBy('ordering'); 99 | $fields = $content_model->getRequiredContentFields('{users}'); 100 | 101 | // Разбиваем поля по группам 102 | $fieldsets = cmsForm::mapFieldsToFieldsets($fields); 103 | 104 | // Добавляем поля в форму 105 | foreach($fieldsets as $fieldset){ 106 | 107 | $fieldset_id = $form->addFieldset($fieldset['title']); 108 | 109 | foreach($fieldset['fields'] as $field){ 110 | if ($field['is_system']) { continue; } 111 | $form->addField($fieldset_id, $field['handler']); 112 | } 113 | 114 | } 115 | 116 | $user = $form->parse($this->request, true); 117 | 118 | $user['groups'] = array(); 119 | 120 | if (!empty($this->options['def_groups'])){ 121 | $user['groups'] = $this->options['def_groups']; 122 | } 123 | 124 | if (isset($user['group_id'])) { 125 | if (!in_array($user['group_id'], $user['groups'])){ 126 | $user['groups'][] = $user['group_id']; 127 | } 128 | } 129 | 130 | // 131 | // убираем поля которые не относятся к выбранной пользователем группе 132 | // 133 | foreach($fieldsets as $fieldset){ 134 | foreach($fieldset['fields'] as $field){ 135 | if (!$field['groups_edit']) { continue; } 136 | if (in_array(0, $field['groups_edit'])) { continue; } 137 | if (!in_array($user['group_id'], $field['groups_edit'])){ 138 | $form->disableField($field['name']); 139 | unset($user[$field['name']]); 140 | } 141 | } 142 | } 143 | 144 | $errors = $form->validate($this, $user, false); 145 | 146 | if($errors){ 147 | 148 | return array( 149 | 'error_code' => 100, 150 | 'error_msg' => '', 151 | 'request_params' => $errors 152 | ); 153 | 154 | } 155 | 156 | // 157 | // проверяем код приглашения 158 | // 159 | if ($this->options['is_reg_invites']){ 160 | $invite = $this->model->getInviteByCode($user['inv']); 161 | if (!$invite) { 162 | $errors['inv'] = LANG_REG_WRONG_INVITE_CODE; 163 | } else { 164 | if ($this->options['is_invites_strict'] && ($invite['email'] != $user['email'])) { 165 | $errors['inv'] = LANG_REG_WRONG_INVITE_CODE_EMAIL; 166 | } else { 167 | $user['inviter_id'] = $invite['user_id']; 168 | } 169 | } 170 | } 171 | 172 | // 173 | // проверяем допустимость e-mail и имени 174 | // 175 | if (!$this->isEmailAllowed($user['email'])){ 176 | $errors['email'] = sprintf(LANG_AUTH_RESTRICTED_EMAIL, $user['email']); 177 | } 178 | 179 | if (!$this->isNameAllowed($user['nickname'])){ 180 | $errors['nickname'] = sprintf(LANG_AUTH_RESTRICTED_NAME, $user['nickname']); 181 | } 182 | 183 | if($errors){ 184 | 185 | return array( 186 | 'error_code' => 100, 187 | 'error_msg' => '', 188 | 'request_params' => $errors 189 | ); 190 | 191 | } 192 | 193 | list($errors, $user) = cmsEventsManager::hook('registration_validation', array(false, $user)); 194 | 195 | if($errors){ 196 | 197 | return array( 198 | 'error_code' => 100, 199 | 'error_msg' => '', 200 | 'request_params' => $errors 201 | ); 202 | 203 | } 204 | 205 | unset($user['inv']); 206 | 207 | // 208 | // Блокируем пользователя, если включена верификация e-mail 209 | // 210 | if ($this->options['verify_email']){ 211 | $user = array_merge($user, array( 212 | 'is_locked' => true, 213 | 'lock_reason' => LANG_REG_CFG_VERIFY_LOCK_REASON, 214 | 'pass_token' => string_random(32, $user['email']), 215 | 'date_token' => '' 216 | )); 217 | } 218 | 219 | $user['nickname'] = strstr($user['email'], '@', true); 220 | 221 | $result = $this->model_users->addUser($user); 222 | 223 | if (!$result['success']){ 224 | 225 | return array( 226 | 'error_code' => 100, 227 | 'error_msg' => '', 228 | 'request_params' => (array)$result['errors'] 229 | ); 230 | 231 | } 232 | 233 | 234 | $user['id'] = $result['id']; 235 | 236 | cmsUser::setUPS('first_auth', 1, $user['id']); 237 | 238 | $this->user = $user; 239 | 240 | return false; 241 | 242 | } 243 | 244 | public function run(){ 245 | 246 | // отправляем письмо верификации e-mail 247 | if ($this->options['verify_email']){ 248 | 249 | $messenger = cmsCore::getController('messages'); 250 | $to = array('email' => $this->user['email'], 'name' => $this->user['nickname']); 251 | $letter = array('name' => 'reg_verify'); 252 | 253 | $messenger->sendEmail($to, $letter, array( 254 | 'nickname' => $this->user['nickname'], 255 | 'page_url' => href_to_abs('auth', 'verify', $this->user['pass_token']), 256 | 'pass_token' => $this->user['pass_token'], 257 | 'valid_until' => html_date(date('d.m.Y H:i', time() + ($this->options['verify_exp'] * 3600)), true) 258 | )); 259 | 260 | } else { 261 | 262 | cmsEventsManager::hook('user_registered', $this->user); 263 | 264 | } 265 | 266 | $this->result = array( 267 | 'user_id' => $this->user['id'], 268 | 'is_verify_email' => (bool) $this->options['verify_email'], 269 | 'success_text' => ($this->options['verify_email'] ? sprintf(LANG_REG_SUCCESS_NEED_VERIFY, $this->user['email']) : LANG_REG_SUCCESS) 270 | ); 271 | 272 | } 273 | 274 | } 275 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_auth_signup_fields.php: -------------------------------------------------------------------------------- 1 | options['is_reg_enabled'])){ 21 | return array('error_code' => 323); 22 | } 23 | 24 | if (!$this->isIPAllowed(cmsUser::get('ip'))){ 25 | 26 | return array( 27 | 'error_code' => 15, 28 | 'error_msg' => strip_tags(sprintf(LANG_AUTH_RESTRICTED_IP, cmsUser::get('ip'))) 29 | ); 30 | 31 | } 32 | 33 | return false; 34 | 35 | } 36 | 37 | public function run(){ 38 | 39 | $this->result = array(); 40 | 41 | $form = $this->getForm('registration'); 42 | if(!$form){ return; } 43 | 44 | // 45 | // Добавляем поле для кода приглашения, 46 | // если регистрация доступна только по приглашениям 47 | // 48 | if ($this->options['is_reg_invites']){ 49 | 50 | $fieldset_id = $form->addFieldsetToBeginning(LANG_REG_INVITED_ONLY); 51 | 52 | $form->addField($fieldset_id, new fieldString('inv', array( 53 | 'title' => LANG_REG_INVITE_CODE, 54 | 'rules' => array( 55 | array('required'), 56 | array('min_length', 10), 57 | array('max_length', 10) 58 | ) 59 | ))); 60 | 61 | } 62 | 63 | // 64 | // Добавляем поле выбора группы, 65 | // при наличии публичных групп 66 | // 67 | $public_groups = cmsCore::getModel('users')->getPublicGroups(); 68 | 69 | if ($public_groups) { 70 | 71 | $pb_items = array(); 72 | foreach($public_groups as $pb) { $pb_items[ $pb['id'] ] = $pb['title']; } 73 | 74 | $form->addFieldToBeginning('basic', 75 | new fieldList('group_id', array( 76 | 'title' => LANG_USER_GROUP, 77 | 'items' => $pb_items 78 | ) 79 | ) 80 | ); 81 | 82 | } 83 | 84 | // 85 | // Добавляем в форму обязательные поля профилей 86 | // 87 | $content_model = cmsCore::getModel('content'); 88 | $content_model->setTablePrefix(''); 89 | $content_model->orderBy('ordering'); 90 | $fields = $content_model->getRequiredContentFields('{users}'); 91 | 92 | // Разбиваем поля по группам 93 | $fieldsets = cmsForm::mapFieldsToFieldsets($fields); 94 | 95 | // Добавляем поля в форму 96 | foreach($fieldsets as $fieldset){ 97 | 98 | $fieldset_id = $form->addFieldset($fieldset['title']); 99 | 100 | foreach($fieldset['fields'] as $field){ 101 | if ($field['is_system']) { continue; } 102 | $form->addField($fieldset_id, $field['handler']); 103 | } 104 | 105 | } 106 | 107 | $this->result['item'] = form_to_params($form); 108 | $this->result['sig'] = get_sig(); 109 | 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_content_add_item.php: -------------------------------------------------------------------------------- 1 | LANG_API_EMPTY_CTYPE); 19 | } 20 | 21 | $this->ctype = $this->model->getContentTypeByName($ctype_name); 22 | 23 | if(!$this->ctype){ 24 | return array('error_code' => 322); 25 | } 26 | 27 | $permissions = cmsEventsManager::hook('content_add_permissions', array( 28 | 'can_add' => false, 29 | 'ctype' => $this->ctype 30 | )); 31 | 32 | $is_check_parent_perm = false; 33 | 34 | // проверяем наличие доступа 35 | if (!cmsUser::isAllowed($this->ctype['name'], 'add') && !$permissions['can_add']) { 36 | if (!cmsUser::isAllowed($this->ctype['name'], 'add_to_parent')) { 37 | if(!$this->cms_user->is_logged){ 38 | return array('error_code' => 71); 39 | } 40 | return array('error_code' => 322); 41 | } 42 | $is_check_parent_perm = true; 43 | } 44 | 45 | // проверяем что не превышен лимит на число записей 46 | $user_items_count = $this->model->getUserContentItemsCount($this->ctype['name'], $this->cms_user->id, false); 47 | 48 | if (cmsUser::isPermittedLimitReached($this->ctype['name'], 'limit', $user_items_count)){ 49 | return array('error_msg' => sprintf(LANG_CONTENT_COUNT_LIMIT, $this->ctype['labels']['many'])); 50 | } 51 | 52 | // Проверяем ограничение по карме 53 | if (cmsUser::isPermittedLimitHigher($this->ctype['name'], 'karma', $this->cms_user->karma)){ 54 | return array('error_msg' => sprintf(LANG_CONTENT_KARMA_LIMIT, cmsUser::getPermissionValue($this->ctype['name'], 'karma'))); 55 | } 56 | 57 | $this->item = array(); 58 | 59 | // Определяем наличие полей-свойств 60 | $props = $this->model->getContentProps($this->ctype['name']); 61 | $this->ctype['props'] = $props; 62 | 63 | // Если этот контент можно создавать в группах (сообществах) то получаем список групп 64 | $groups_list = array(); 65 | 66 | if ($this->ctype['is_in_groups'] || $this->ctype['is_in_groups_only']){ 67 | 68 | $groups = cmsCore::getModel('groups')->getUserGroups($this->cms_user->id); 69 | 70 | $groups_list = ($this->ctype['is_in_groups_only']) ? array() : array('0'=>''); 71 | $groups_list = $groups_list + array_collection_to_list($groups, 'id', 'title'); 72 | 73 | $group_id = $this->request->get('group_id', 0); 74 | // если вне групп добавление записей запрещено, даём выбор только одной группы 75 | if(!cmsUser::isAllowed($this->ctype['name'], 'add') && isset($groups_list[$group_id])){ 76 | $groups_list = array($group_id => $groups_list[$group_id]); 77 | } 78 | 79 | } 80 | 81 | // Если включены личные папки - получаем их список 82 | $folders_list = array(); 83 | 84 | if ($this->ctype['is_folders']){ 85 | $folders_list = $this->model->getContentFolders($this->ctype['id'], $this->cms_user->id); 86 | $folders_list = array_collection_to_list($folders_list, 'id', 'title'); 87 | } 88 | 89 | // Получаем поля для данного типа контента 90 | $this->fields = $this->model->orderBy('ordering')->getContentFields($this->ctype['name']); 91 | 92 | $form = $this->getItemForm($this->ctype, $this->fields, 'add', array( 93 | 'groups_list' => $groups_list, 94 | 'folders_list' => $folders_list 95 | )); 96 | 97 | $this->parents = $this->model->getContentTypeParents($this->ctype['id']); 98 | 99 | if ($this->parents){ 100 | foreach($this->parents as $parent){ 101 | 102 | if (!$this->request->has($parent['id_param_name'])){ 103 | continue; 104 | } 105 | 106 | if (!cmsUser::isAllowed($this->ctype['name'], 'add_to_parent') && !cmsUser::isAllowed($this->ctype['name'], 'bind_to_parent')) { 107 | $form->hideField($parent['id_param_name']); 108 | continue; 109 | } 110 | 111 | $parent_id = $this->request->get($parent['id_param_name'], 0); 112 | $parent_item = $parent_id ? $this->model->getContentItem($parent['ctype_name'], $parent_id) : false; 113 | 114 | if($parent_item){ 115 | 116 | if (!empty($is_check_parent_perm) && !$this->cms_user->is_admin){ 117 | if (cmsUser::isAllowed($this->ctype['name'], 'add_to_parent', 'to_own') && $parent_item['user_id'] != $this->cms_user->id){ 118 | return array('error_code' => 322); 119 | } 120 | if (cmsUser::isAllowed($this->ctype['name'], 'add_to_parent', 'to_other') && $parent_item['user_id'] == $this->cms_user->id){ 121 | return array('error_code' => 322); 122 | } 123 | } 124 | 125 | $this->item[$parent['id_param_name']] = $parent_id; 126 | $relation_id = $parent['id']; 127 | 128 | } 129 | 130 | break; 131 | 132 | } 133 | } 134 | 135 | if (!empty($is_check_parent_perm) && empty($relation_id)){ 136 | return array('error_code' => 322); 137 | } 138 | 139 | // Заполняем поля значениями по-умолчанию, взятыми из профиля пользователя 140 | // (для тех полей, в которых это включено) 141 | foreach($this->fields as $field){ 142 | if (!empty($field['options']['profile_value'])){ 143 | $this->item[$field['name']] = $this->cms_user->{$field['options']['profile_value']}; 144 | } 145 | if (!empty($field['options']['relation_id']) && !empty($relation_id)){ 146 | if ($field['options']['relation_id'] != $relation_id){ 147 | $form->hideField($field['name']); 148 | } 149 | } 150 | } 151 | 152 | $this->ctype = cmsEventsManager::hook('content_add', $this->ctype); 153 | list($form, $this->item) = cmsEventsManager::hook("content_{$this->ctype['name']}_form", array($form, $this->item)); 154 | 155 | $this->item['ctype_name'] = $this->ctype['name']; 156 | $this->item['ctype_id'] = $this->ctype['id']; 157 | $this->item['ctype_data'] = $this->ctype; 158 | 159 | if ($this->ctype['props']){ 160 | $props_cat_id = $this->request->get('category_id', 0); 161 | if ($props_cat_id){ 162 | $item_props = $this->model->getContentProps($this->ctype['name'], $props_cat_id); 163 | $item_props_fields = $this->getPropsFields($item_props); 164 | foreach($item_props_fields as $field){ 165 | $form->addField('props', $field); 166 | } 167 | } 168 | } 169 | 170 | // Парсим форму и получаем поля записи 171 | $this->item = array_merge($this->item, $form->parse($this->request, true)); 172 | 173 | // Проверям правильность заполнения 174 | $errors = $form->validate($this, $this->item); 175 | 176 | if ($this->parents && $is_check_parent_perm){ 177 | 178 | $perm = cmsUser::getPermissionValue($this->ctype['name'], 'add_to_parent'); 179 | 180 | foreach($this->parents as $parent){ 181 | if (!empty($this->item[$parent['id_param_name']])){ 182 | $ids = explode(',', $this->item[$parent['id_param_name']]); 183 | $this->model->filterIn('id', $ids); 184 | $parent_items = $this->model->getContentItems($parent['ctype_name']); 185 | if ($parent_items){ 186 | foreach($parent_items as $parent_item){ 187 | if ($perm == 'to_own' && $parent_item['user']['id'] != $this->cms_user->id) { 188 | $errors[$parent['id_param_name']] = LANG_CONTENT_WRONG_PARENT; 189 | break; 190 | } 191 | if ($perm == 'to_other' && $parent_item['user']['id'] == $this->cms_user->id) { 192 | $errors[$parent['id_param_name']] = LANG_CONTENT_WRONG_PARENT; 193 | break; 194 | } 195 | } 196 | } 197 | } 198 | } 199 | 200 | } 201 | 202 | list($this->item, $errors) = cmsEventsManager::hook('content_validate', array($this->item, $errors)); 203 | list($this->item, $errors, $this->ctype, $this->fields) = cmsEventsManager::hook("content_{$ctype['name']}_validate", array($this->item, $errors, $this->ctype, $this->fields), null, $this->request); 204 | 205 | if($errors){ 206 | 207 | if($errors === true){ 208 | $errors = array('csrf_token' => LANG_API_ERROR_CSRF_TOKEN); 209 | } 210 | 211 | return array( 212 | 'error_code' => 100, 213 | 'error_msg' => '', 214 | 'request_params' => $errors 215 | ); 216 | 217 | } 218 | 219 | return false; 220 | 221 | } 222 | 223 | public function run($ctype_name){ 224 | 225 | $succes_text = ''; 226 | 227 | // форма отправлена к контексте черновика 228 | $is_draf_submitted = $this->request->has('to_draft'); 229 | 230 | // несколько категорий 231 | if (!empty($this->ctype['options']['is_cats_multi'])){ 232 | $add_cats = $this->request->get('add_cats', array()); 233 | if (is_array($add_cats)){ 234 | foreach($add_cats as $index=>$cat_id){ 235 | if (!is_numeric($cat_id) || !$cat_id){ 236 | unset($add_cats[$index]); 237 | } 238 | } 239 | if ($add_cats){ 240 | $this->item['add_cats'] = $add_cats; 241 | } 242 | } 243 | } 244 | 245 | $is_moderator = $this->cms_user->is_admin || cmsCore::getModel('moderation')->userIsContentModerator($this->ctype['name'], $this->cms_user->id); 246 | $is_premoderation = cmsUser::isAllowed($this->ctype['name'], 'add', 'premod', true); 247 | 248 | if($is_draf_submitted){ 249 | $this->item['is_approved'] = 0; 250 | } else { 251 | $this->item['is_approved'] = !$is_premoderation || $is_moderator; 252 | } 253 | 254 | $is_pub_control = cmsUser::isAllowed($this->ctype['name'], 'pub_on'); 255 | $is_date_pub_allowed = $this->ctype['is_date_range'] && cmsUser::isAllowed($this->ctype['name'], 'pub_late'); 256 | $is_date_pub_end_allowed = $this->ctype['is_date_range'] && cmsUser::isAllowed($this->ctype['name'], 'pub_long', 'any'); 257 | $is_date_pub_days_allowed = $this->ctype['is_date_range'] && cmsUser::isAllowed($this->ctype['name'], 'pub_long', 'days'); 258 | 259 | $date_pub_time = isset($this->item['date_pub']) ? strtotime($this->item['date_pub']) : time(); 260 | $now_time = time(); 261 | $now_date = strtotime(date('Y-m-d', $now_time)); 262 | $is_pub = true; 263 | 264 | if ($is_date_pub_allowed){ 265 | $time_to_pub = $date_pub_time - $now_time; 266 | $is_pub = $is_pub && ($time_to_pub < 0); 267 | } 268 | if ($is_date_pub_end_allowed && !empty($this->item['date_pub_end'])){ 269 | $date_pub_end_time = strtotime($this->item['date_pub_end']); 270 | $days_from_pub = floor(($now_date - $date_pub_end_time)/60/60/24); 271 | $is_pub = $is_pub && ($days_from_pub < 1); 272 | } else if ($is_date_pub_days_allowed && !$this->cms_user->is_admin) { 273 | $days = $this->item['pub_days']; 274 | $date_pub_end_time = $date_pub_time + 60*60*24*$days; 275 | $days_from_pub = floor(($now_date - $date_pub_end_time)/60/60/24); 276 | $is_pub = $is_pub && ($days_from_pub < 1); 277 | $this->item['date_pub_end'] = date('Y-m-d', $date_pub_end_time); 278 | } else { 279 | $this->item['date_pub_end'] = false; 280 | } 281 | 282 | unset($this->item['pub_days']); 283 | if (!$is_pub_control) { unset($this->item['is_pub']); } 284 | if (!isset($this->item['is_pub'])) { $this->item['is_pub'] = $is_pub; } 285 | if (!empty($this->item['is_pub'])) { $this->item['is_pub'] = $is_pub; } 286 | 287 | $this->item = cmsEventsManager::hook('content_before_add', $this->item); 288 | $this->item = cmsEventsManager::hook("content_{$this->ctype['name']}_before_add", $this->item); 289 | 290 | $this->item = $this->model->addContentItem($this->ctype, $this->item, $this->fields); 291 | 292 | $this->bindItemToParents($this->ctype, $this->item, $this->parents); 293 | 294 | $this->item = cmsEventsManager::hook('content_after_add', $this->item); 295 | $this->item = cmsEventsManager::hook("content_{$this->ctype['name']}_after_add", $this->item); 296 | 297 | if(!$is_draf_submitted){ 298 | 299 | if ($this->item['is_approved']){ 300 | cmsEventsManager::hook('content_after_add_approve', array('ctype_name' => $this->ctype['name'], 'item' => $this->item)); 301 | cmsEventsManager::hook("content_{$this->ctype['name']}_after_add_approve", $this->item); 302 | } else { 303 | 304 | $this->item['page_url'] = href_to_abs($this->ctype['name'], $this->item['slug'] . '.html'); 305 | 306 | $succes_text = cmsCore::getController('moderation')->requestModeration($this->ctype['name'], $this->item); 307 | 308 | } 309 | 310 | } 311 | 312 | $this->result = array( 313 | 'success_text' => $succes_text, 314 | 'item_id' => $this->item['id'] 315 | ); 316 | 317 | } 318 | 319 | } 320 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_content_get.php: -------------------------------------------------------------------------------- 1 | array( 27 | 'default' => 1, 28 | 'rules' => array( 29 | array('digits') 30 | ) 31 | ), 32 | 'is_not_paginated' => array( 33 | 'default' => 0, 34 | 'rules' => array( 35 | array('digits') 36 | ) 37 | ), 38 | 'cat_id' => array( 39 | 'default' => 1, 40 | 'rules' => array( 41 | array('digits') 42 | ) 43 | ), 44 | 'folder_id' => array( 45 | 'default' => 0, 46 | 'rules' => array( 47 | array('digits') 48 | ) 49 | ), 50 | 'user_id' => array( 51 | 'default' => 0, 52 | 'rules' => array( 53 | array('digits') 54 | ) 55 | ), 56 | 'group_id' => array( 57 | 'default' => 0, 58 | 'rules' => array( 59 | array('digits') 60 | ) 61 | ), 62 | 'dataset_id' => array( 63 | 'default' => 0, 64 | 'rules' => array( 65 | array('digits') 66 | ) 67 | ), 68 | 'ids' => array( 69 | 'default' => '', 70 | 'rules' => array( 71 | array('regexp', '/^([0-9,]+)$/i') 72 | ) 73 | ) 74 | ); 75 | 76 | private $ctype; 77 | private $cat = array('id' => false); 78 | private $dataset, $user, $folder, $group = array(); 79 | 80 | public function validateApiRequest($ctype_name=null) { 81 | 82 | if(!$ctype_name){ 83 | return array('error_msg' => LANG_API_EMPTY_CTYPE); 84 | } 85 | 86 | $this->ctype = $this->model->getContentTypeByName($ctype_name); 87 | 88 | if(!$this->ctype){ 89 | return array('error_msg' => LANG_API_EMPTY_CTYPE); 90 | } 91 | 92 | // категория 93 | $cat_id = $this->request->get('cat_id'); 94 | if(!empty($this->ctype['is_cats']) && $cat_id > 1){ 95 | 96 | $this->cat = $this->model->getCategory($this->ctype['name'], $cat_id); 97 | if (!$this->cat){ 98 | return array('error_msg' => LANG_API_ERROR100); 99 | } 100 | 101 | } 102 | 103 | // набор 104 | $dataset_id = $this->request->get('dataset_id'); 105 | if($dataset_id){ 106 | 107 | $this->dataset = $this->model->getContentDataset($dataset_id); 108 | if (!$this->dataset){ 109 | return array('error_msg' => LANG_API_ERROR100); 110 | } 111 | 112 | } 113 | 114 | // пользователь 115 | $user_id = $this->request->get('user_id'); 116 | if($user_id){ 117 | 118 | $this->user = $this->model->getItemById('{users}', $user_id); 119 | if (!$this->user){ 120 | return array('error_msg' => LANG_API_ERROR100); 121 | } 122 | 123 | } 124 | 125 | // папка 126 | $folder_id = $this->request->get('folder_id'); 127 | if($folder_id){ 128 | 129 | $this->folder = $this->model->$this->getItemById('content_folders', $folder_id); 130 | if (!$this->folder){ 131 | return array('error_msg' => LANG_API_ERROR100); 132 | } 133 | 134 | } 135 | 136 | // группа 137 | $group_id = $this->request->get('group_id'); 138 | if($group_id){ 139 | 140 | $this->group = $this->model->getItemById('groups', $group_id); 141 | if (!$this->group){ 142 | return array('error_msg' => LANG_API_ERROR100); 143 | } 144 | 145 | } 146 | 147 | return false; 148 | 149 | } 150 | 151 | public function run($ctype_name){ 152 | 153 | // просмотр списка запрещен 154 | if (empty($this->ctype['options']['list_on'])) { return; } 155 | 156 | // параметры 157 | $perpage = (empty($this->ctype['options']['limit']) ? 10 : $this->ctype['options']['limit']); 158 | $page = $this->request->get('page'); 159 | $hide_root = !empty($this->ctype['options']['is_empty_root']) && $this->cat['id'] == 1; 160 | 161 | // разбивка на страницы если нужна 162 | if(!$this->request->get('is_not_paginated')){ 163 | $this->result['paging'] = array( 164 | 'page' => $page, 165 | 'per_page' => $perpage 166 | ); 167 | } 168 | 169 | // если записи в корне мы не показываем 170 | if($hide_root){ return; } 171 | 172 | // категории выключены, а передали категорию 173 | if (empty($this->ctype['is_cats']) && $this->cat['id'] > 1) { return; } 174 | 175 | // если нужен список по id 176 | $ids = $this->request->get('ids'); 177 | if($ids){ 178 | 179 | $ids = explode(',', $ids); 180 | $ids = array_filter($ids); 181 | 182 | if($ids){ 183 | $this->model->filterIn('id', $ids); 184 | } 185 | 186 | } 187 | 188 | // если передан набор, фильтруем по нему 189 | if($this->dataset){ 190 | $this->model->applyDatasetFilters($this->dataset); 191 | } 192 | 193 | // Фильтр по категории 194 | if ($this->cat['id'] > 1) { 195 | $this->model->filterCategory($this->ctype['name'], $this->cat, $this->ctype['is_cats_recursive']); 196 | } 197 | 198 | // фильтр по пользователю 199 | if($this->user){ 200 | $this->model->filterEqual('user_id', $this->user['id']); 201 | } 202 | 203 | // фильтр по папке 204 | if($this->folder){ 205 | $this->model->filterEqual('folder_id', $this->folder['id']); 206 | } 207 | 208 | // фильтр по группе 209 | if($this->group){ 210 | $this->model->filterEqual('parent_id', $this->group['id'])-> 211 | filterEqual('parent_type', 'group')-> 212 | orderBy('date_pub', 'desc')->forceIndex('parent_id'); 213 | } 214 | 215 | // Скрываем записи из скрытых родителей (приватных групп и т.п.) 216 | $this->model->filterHiddenParents(); 217 | 218 | // фильтрация по полям и свойствам 219 | $props = $props_fields = $filters = array(); 220 | 221 | $fields = cmsCore::getModel('content')->getContentFields($this->ctype['name']); 222 | 223 | if ($this->cat['id'] && $this->cat['id'] > 1){ 224 | // Получаем поля-свойства 225 | $props = cmsCore::getModel('content')->getContentProps($this->ctype['name'], $this->cat['id']); 226 | } 227 | 228 | // проверяем запросы фильтрации по полям 229 | foreach($fields as $name => $field){ 230 | 231 | if (!$field['is_in_filter']) { continue; } 232 | if (!$this->request->has($name)){ continue; } 233 | 234 | $value = $this->request->get($name, false, $field['handler']->getDefaultVarType(true)); 235 | if (!$value) { continue; } 236 | 237 | if($field['handler']->applyFilter($this->model, $value) !== false){ 238 | $filters[$name] = $value; 239 | } 240 | 241 | } 242 | 243 | // проверяем запросы фильтрации по свойствам 244 | if ($props && is_array($props)){ 245 | 246 | $props_fields = $this->getPropsFields($props); 247 | 248 | foreach($props as $prop){ 249 | 250 | $name = "p{$prop['id']}"; 251 | 252 | if (!$prop['is_in_filter']) { continue; } 253 | if (!$this->request->has($name)){ continue; } 254 | 255 | $prop['handler'] = $props_fields[$prop['id']]; 256 | 257 | $value = $this->request->get($name, false, $prop['handler']->getDefaultVarType(true)); 258 | if (!$value) { continue; } 259 | 260 | if($this->model->filterPropValue($this->ctype['name'], $prop, $value) !== false){ 261 | 262 | $filters[$name] = $value; 263 | 264 | } 265 | 266 | } 267 | 268 | } 269 | 270 | // Сначала проверяем настройки типа контента 271 | if (!empty($this->ctype['options']['privacy_type']) && 272 | in_array($this->ctype['options']['privacy_type'], array('show_title', 'show_all'), true)) { 273 | $this->model->disablePrivacyFilter(); 274 | } 275 | 276 | // А потом, если разрешено правами доступа, отключаем фильтр приватности 277 | if (cmsUser::isAllowed($this->ctype['name'], 'view_all')) { 278 | $this->model->disablePrivacyFilter(); 279 | } 280 | 281 | // Постраничный вывод 282 | if($this->request->get('is_not_paginated')){ 283 | $this->model->limit(0); 284 | } else { 285 | $this->model->limitPage($page, $perpage); 286 | } 287 | 288 | list($this->ctype, $this->model) = cmsEventsManager::hook('content_list_filter', array($this->ctype, $this->model)); 289 | list($this->ctype, $this->model) = cmsEventsManager::hook("content_{$this->ctype['name']}_list_filter", array($this->ctype, $this->model)); 290 | 291 | // Получаем количество и список записей 292 | $total = $this->model->getContentItemsCount($this->ctype['name']); 293 | $items = $this->model->getContentItems($this->ctype['name']); 294 | 295 | list($this->ctype, $items) = cmsEventsManager::hook('content_before_list', array($this->ctype, $items)); 296 | list($this->ctype, $items) = cmsEventsManager::hook("content_{$this->ctype['name']}_before_list", array($this->ctype, $items)); 297 | list($this->ctype, $items) = cmsEventsManager::hook('content_api_list', array($this->ctype, $items)); 298 | 299 | $result_items = array(); 300 | 301 | if($items){ 302 | foreach ($items as $key => $item) { 303 | 304 | $is_private = $item['is_private'] == 1 && !$item['user']['is_friend']; 305 | 306 | $item['ctype'] = $this->ctype; 307 | 308 | foreach($fields as $name => $field){ 309 | 310 | if (!$field['is_in_list']) { unset($items[$key][$name]); continue; } 311 | 312 | if (empty($item[$name]) || $field['is_system']) { continue; } 313 | 314 | if ($field['groups_read'] && !$this->cms_user->isInGroups($field['groups_read'])) { 315 | unset($items[$key][$name]); continue; 316 | } 317 | 318 | if($is_private){ 319 | $items[$key][$name] = null; continue; 320 | } 321 | 322 | if (in_array($field['type'], array('images','image'))){ 323 | $items[$key][$name] = api_image_src($item[$name]); 324 | } else 325 | if ($name != 'title'){ 326 | $items[$key][$name] = $field['handler']->setItem($item)->parseTeaser($item[$name]); 327 | } 328 | 329 | } 330 | 331 | $result_items[] = $items[$key]; 332 | 333 | } 334 | } 335 | 336 | foreach($fields as $name => $field){ 337 | unset($fields[$name]['handler']); 338 | } 339 | 340 | $this->result['count'] = $total; 341 | $this->result['items'] = $result_items; 342 | $this->result['additionally'] = array( 343 | 'fields' => $fields, 344 | 'props' => $props, 345 | 'filters' => $filters, 346 | 'ctype' => $this->ctype, 347 | 'category' => $this->cat, 348 | 'dataset' => $this->dataset, 349 | 'group' => $this->group 350 | ); 351 | 352 | } 353 | 354 | } 355 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_content_get_categories.php: -------------------------------------------------------------------------------- 1 | array( 27 | 'default' => '', 28 | 'rules' => array( 29 | array('regexp', '/^([0-9,]+)$/i') 30 | ) 31 | ), 32 | 'is_tree' => array( 33 | 'default' => 0, 34 | 'rules' => array( 35 | array('digits') 36 | ) 37 | ), 38 | 'cat_level' => array( 39 | 'default' => 0, 40 | 'rules' => array( 41 | array('digits') 42 | ) 43 | ), 44 | 'parent_id' => array( 45 | 'default' => 1, 46 | 'rules' => array( 47 | array('digits') 48 | ) 49 | ) 50 | ); 51 | 52 | /** 53 | * Служебное свойство типа контента 54 | * для этого экшена 55 | * @var array 56 | */ 57 | private $ctype; 58 | 59 | public function validateApiRequest($ctype_name=null) { 60 | 61 | if(!$ctype_name){ 62 | return array('error_msg' => LANG_API_EMPTY_CTYPE); 63 | } 64 | 65 | $this->ctype = $this->model->getContentTypeByName($ctype_name); 66 | 67 | if(!$this->ctype){ 68 | return array('error_msg' => LANG_API_EMPTY_CTYPE); 69 | } 70 | 71 | return false; 72 | 73 | } 74 | 75 | public function run($ctype_name){ 76 | 77 | if (empty($this->ctype['is_cats'])) { 78 | return; 79 | } 80 | 81 | $categories = array(); 82 | 83 | $cat_ids = $this->request->get('cat_ids'); 84 | if($cat_ids){ 85 | 86 | $cat_ids = explode(',', $cat_ids); 87 | $cat_ids = array_filter($cat_ids); 88 | 89 | if($cat_ids){ 90 | 91 | $this->model->filterIn('id', $cat_ids); 92 | 93 | $categories = $this->model->get($this->model->table_prefix.$ctype_name.'_cats'); 94 | 95 | } 96 | 97 | } else { 98 | 99 | if($this->request->get('is_tree')){ 100 | 101 | $categories = $this->model->getSubCategoriesTree($this->ctype['name'], $this->request->get('parent_id'), $this->request->get('cat_level')); 102 | 103 | } else { 104 | 105 | $categories = $this->model->getSubCategories($this->ctype['name'], $this->request->get('parent_id')); 106 | 107 | } 108 | 109 | } 110 | 111 | $this->result['count'] = count($categories); 112 | $this->result['items'] = $categories; 113 | 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_content_get_ctypes.php: -------------------------------------------------------------------------------- 1 | ctype = $this->model->getContentTypeByName($ctype_name); 39 | 40 | if(!$this->ctype){ 41 | return array( 42 | 'error_code' => 322 43 | ); 44 | } 45 | 46 | return false; 47 | 48 | } 49 | 50 | public function run(){ 51 | 52 | if(empty($this->ctype)){ 53 | 54 | $ctypes = $this->model->getContentTypes(); 55 | 56 | $this->result['count'] = count($ctypes); 57 | $this->result['items'] = $ctypes; 58 | 59 | } else { 60 | 61 | $this->result = $this->ctype; 62 | 63 | } 64 | 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_content_get_datasets.php: -------------------------------------------------------------------------------- 1 | array( 27 | 'default' => 0, 28 | 'rules' => array( 29 | array('digits') 30 | ) 31 | ) 32 | ); 33 | 34 | /** 35 | * Служебное свойство типа контента 36 | * для этого экшена 37 | * @var array 38 | */ 39 | private $ctype; 40 | 41 | public function validateApiRequest($ctype_name=null) { 42 | 43 | if(!$ctype_name){ 44 | return array('error_msg' => LANG_API_EMPTY_CTYPE); 45 | } 46 | 47 | $this->ctype = $this->model->getContentTypeByName($ctype_name); 48 | 49 | if(!$this->ctype){ 50 | return array('error_msg' => LANG_API_EMPTY_CTYPE); 51 | } 52 | 53 | return false; 54 | 55 | } 56 | 57 | public function run($ctype_name){ 58 | 59 | $datasets = $this->model->getContentDatasets($this->ctype['id'], !$this->request->get('show_all')); 60 | 61 | $this->result['count'] = count($datasets); 62 | $this->result['items'] = $datasets; 63 | 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_content_get_fields.php: -------------------------------------------------------------------------------- 1 | array( 27 | 'default' => 0, 28 | 'rules' => array( 29 | array('digits') 30 | ) 31 | ), 32 | 'is_in_list' => array( 33 | 'default' => 0, 34 | 'rules' => array( 35 | array('digits') 36 | ) 37 | ), 38 | 'is_in_item' => array( 39 | 'default' => 0, 40 | 'rules' => array( 41 | array('digits') 42 | ) 43 | ), 44 | 'is_in_filter' => array( 45 | 'default' => 0, 46 | 'rules' => array( 47 | array('digits') 48 | ) 49 | ), 50 | 'ids' => array( 51 | 'default' => '', 52 | 'rules' => array( 53 | array('regexp', '/^([0-9,]+)$/i') 54 | ) 55 | ) 56 | ); 57 | 58 | /** 59 | * Массив ключей для удаления 60 | * @var array 61 | */ 62 | public $unset_fields = array( 63 | 'items' => array( // название ключа в $this->result 64 | 'type' => 'list', // list или item 65 | 'unsets' => array( // массив названий ключей для удаления 66 | 'handler' 67 | ) 68 | ) 69 | ); 70 | 71 | /** 72 | * Служебное свойство типа контента 73 | * для этого экшена 74 | * @var array 75 | */ 76 | private $ctype; 77 | 78 | public function validateApiRequest($ctype_name=null) { 79 | 80 | if(!$ctype_name){ 81 | return array('error_msg' => LANG_API_EMPTY_CTYPE); 82 | } 83 | 84 | $this->ctype = $this->model->getContentTypeByName($ctype_name); 85 | 86 | if(!$this->ctype){ 87 | return array('error_msg' => LANG_API_EMPTY_CTYPE); 88 | } 89 | 90 | return false; 91 | 92 | } 93 | 94 | public function run($ctype_name){ 95 | 96 | $ids = $this->request->get('ids'); 97 | if($ids){ 98 | 99 | $ids = explode(',', $ids); 100 | $ids = array_filter($ids); 101 | 102 | $this->model->filterIn('id', $ids); 103 | 104 | } 105 | 106 | if($this->request->get('is_in_list')){ 107 | $this->model->filterEqual('is_in_list', 1); 108 | } 109 | if($this->request->get('is_in_item')){ 110 | $this->model->filterEqual('is_in_item', 1); 111 | } 112 | if($this->request->get('is_in_filter')){ 113 | $this->model->filterEqual('is_in_filter', 1); 114 | } 115 | 116 | if($this->request->get('only_required')){ 117 | $fields = $this->model->getRequiredContentFields($this->ctype['name']); 118 | } else { 119 | $fields = $this->model->getContentFields($this->ctype['name']); 120 | } 121 | 122 | $this->result['count'] = count($fields); 123 | $this->result['items'] = $fields; 124 | 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_content_get_folders.php: -------------------------------------------------------------------------------- 1 | array( 27 | 'rules' => array( 28 | array('required'), 29 | array('digits') 30 | ) 31 | ), 32 | 'ids' => array( 33 | 'default' => '', 34 | 'rules' => array( 35 | array('regexp', '/^([0-9,]+)$/i') 36 | ) 37 | ) 38 | ); 39 | 40 | /** 41 | * Массив ключей для удаления 42 | * @var array 43 | */ 44 | public $unset_fields = array( 45 | 'items' => array( // название ключа в $this->result 46 | 'type' => 'list', // list или item 47 | 'unsets' => array( // массив названий ключей для удаления 48 | 'handler' 49 | ) 50 | ) 51 | ); 52 | 53 | /** 54 | * Служебное свойство типа контента 55 | * для этого экшена 56 | * @var array 57 | */ 58 | private $ctype; 59 | 60 | public function validateApiRequest($ctype_name=null) { 61 | 62 | if(!$ctype_name){ 63 | return array('error_msg' => LANG_API_EMPTY_CTYPE); 64 | } 65 | 66 | $this->ctype = $this->model->getContentTypeByName($ctype_name); 67 | 68 | if(!$this->ctype){ 69 | return array('error_msg' => LANG_API_EMPTY_CTYPE); 70 | } 71 | 72 | return false; 73 | 74 | } 75 | 76 | public function run($ctype_name){ 77 | 78 | $ids = $this->request->get('ids'); 79 | if($ids){ 80 | 81 | $ids = explode(',', $ids); 82 | $ids = array_filter($ids); 83 | 84 | $this->model->filterIn('id', $ids); 85 | 86 | } 87 | 88 | $fields = $this->model->getContentFolders($this->ctype['id'], $this->request->get('user_id')); 89 | 90 | $this->result['count'] = count($fields); 91 | $this->result['items'] = $fields; 92 | 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_content_get_item.php: -------------------------------------------------------------------------------- 1 | array( 27 | 'default' => 0, 28 | 'rules' => array( 29 | array('required'), 30 | array('digits') 31 | ) 32 | ) 33 | ); 34 | 35 | private $ctype, $item; 36 | 37 | public function validateApiRequest($ctype_name=null) { 38 | 39 | if(!$ctype_name){ 40 | return array('error_msg' => LANG_API_EMPTY_CTYPE); 41 | } 42 | 43 | $this->ctype = $this->model->getContentTypeByName($ctype_name); 44 | 45 | if(!$this->ctype){ 46 | return array('error_msg' => LANG_API_EMPTY_CTYPE); 47 | } 48 | 49 | // получаем запись 50 | $this->item = $this->model->getContentItem($this->ctype['name'], $this->request->get('item_id')); 51 | if(!$this->item){ 52 | return array('error_msg' => LANG_API_ERROR100); 53 | } 54 | 55 | // Проверяем прохождение модерации 56 | $is_moderator = $this->cms_user->is_admin || $this->model->userIsContentTypeModerator($this->ctype['name'], $this->cms_user->id); 57 | if (!$this->item['is_approved']){ 58 | if (!$is_moderator && $this->cms_user->id != $this->item['user_id']){ 59 | return array( 60 | 'error_code' => 320 61 | ); 62 | } 63 | } 64 | 65 | // Проверяем публикацию 66 | if (!$this->item['is_pub']){ 67 | if (!$is_moderator && $this->cms_user->id != $this->item['user_id']){ 68 | return array( 69 | 'error_code' => 321 70 | ); 71 | } 72 | } 73 | 74 | // Проверяем, что не удалено 75 | if (!empty($this->item['is_deleted'])){ 76 | if (!$is_moderator){ 77 | return array('error_msg' => LANG_API_ERROR100); 78 | } 79 | } 80 | 81 | // Проверяем приватность 82 | if ($this->item['is_private'] == 1){ // доступ только друзьям 83 | 84 | $is_friend = $this->cms_user->isFriend($this->item['user_id']); 85 | $is_can_view_private = cmsUser::isAllowed($this->ctype['name'], 'view_all'); 86 | 87 | if (!$is_friend && !$is_can_view_private && !$is_moderator){ 88 | // если в настройках указано скрывать 89 | if(empty($this->ctype['options']['privacy_type']) || $this->ctype['options']['privacy_type'] == 'hide'){ 90 | return array( 91 | 'error_code' => 15 92 | ); 93 | } 94 | // иначе пишем, к кому в друзья нужно проситься 95 | return array( 96 | 'error_code' => 15, 97 | 'error_msg' => sprintf( 98 | LANG_CONTENT_PRIVATE_FRIEND_INFO, 99 | (!empty($this->ctype['labels']['one']) ? $this->ctype['labels']['one'] : LANG_PAGE), 100 | href_to('users', $this->item['user_id']), 101 | htmlspecialchars($this->item['user']['nickname']) 102 | ) 103 | ); 104 | } 105 | 106 | } 107 | 108 | // Проверяем ограничения доступа из других контроллеров 109 | if ($this->item['is_parent_hidden'] || $this->item['is_private']){ 110 | $is_parent_viewable_result = cmsEventsManager::hook('content_view_hidden', array( 111 | 'viewable' => true, 112 | 'item' => $this->item, 113 | 'is_moderator' => $is_moderator, 114 | 'ctype' => $this->ctype 115 | )); 116 | if (!$is_parent_viewable_result['viewable']){ 117 | return array( 118 | 'error_code' => 15 119 | ); 120 | } 121 | } 122 | 123 | return false; 124 | 125 | } 126 | 127 | public function run($ctype_name){ 128 | 129 | $category = $props = array(); 130 | $this->result = array(); 131 | 132 | // просмотр записей запрещен 133 | if (empty($this->ctype['options']['item_on'])) { return; } 134 | 135 | $this->item['ctype_name'] = $this->ctype['name']; 136 | 137 | if ($this->ctype['is_cats'] && $this->item['category_id'] > 1){ 138 | $category = $this->model->getCategory($this->ctype['name'], $this->item['category_id']); 139 | } 140 | 141 | // Получаем поля для данного типа контента 142 | $fields = $this->model->getContentFields($this->ctype['name']); 143 | 144 | // Получаем поля-свойства 145 | $this->item['props'] = array(); 146 | 147 | if ($this->ctype['is_cats'] && $this->item['category_id'] > 1){ 148 | $props = $this->model->getContentProps($this->ctype['name'], $this->item['category_id']); 149 | $props_values = $this->model->getPropsValues($this->ctype['name'], $this->item['id']); 150 | if ($props && array_filter((array)$props_values)) { 151 | $props_fields = $this->getPropsFields($props); 152 | $props_fieldsets = cmsForm::mapFieldsToFieldsets($props); 153 | foreach($props_fieldsets as $fieldset){ 154 | 155 | $props_result = array( 156 | 'title' => $fieldset['title'], 157 | 'fields' => array() 158 | ); 159 | if ($fieldset['fields']){ 160 | foreach($fieldset['fields'] as $prop){ 161 | if (isset($props_values[$prop['id']])) { 162 | $prop_field = $props_fields[$prop['id']]; 163 | $props_result['fields'][$prop['id']] = array( 164 | 'title' => $prop['title'], 165 | 'value' => $prop_field->setItem($this->item)->parse($props_values[$prop['id']]) 166 | ); 167 | } 168 | } 169 | } 170 | 171 | $this->item['props'][] = $props_result; 172 | 173 | } 174 | } 175 | } 176 | 177 | list($this->ctype, $this->item, $fields) = cmsEventsManager::hook('content_before_item', array($this->ctype, $this->item, $fields)); 178 | list($this->ctype, $this->item, $fields) = cmsEventsManager::hook("content_{$this->ctype['name']}_before_item", array($this->ctype, $this->item, $fields)); 179 | list($this->ctype, $this->item, $fields) = cmsEventsManager::hook('api_content_before_item', array($this->ctype, $this->item, $fields)); 180 | 181 | // парсим поля 182 | foreach($fields as $name => $field){ 183 | 184 | if (!$field['is_in_item']) { unset($this->item[$name]); continue; } 185 | 186 | if (empty($this->item[$name]) || $field['is_system']) { continue; } 187 | 188 | // проверяем что группа пользователя имеет доступ к чтению этого поля 189 | if ($field['groups_read'] && !$this->cms_user->isInGroups($field['groups_read'])) { 190 | // если группа пользователя не имеет доступ к чтению этого поля, 191 | // проверяем на доступ к нему для авторов 192 | if (!empty($this->item['user_id']) && !empty($field['options']['author_access'])){ 193 | 194 | if (!in_array('is_read', $field['options']['author_access'])){ 195 | unset($this->item[$name]); continue; 196 | } 197 | 198 | if ($this->item['user_id'] == $this->cms_user->id){ 199 | unset($this->item[$name]); continue; 200 | } 201 | 202 | } 203 | 204 | unset($this->item[$name]); continue; 205 | 206 | } 207 | 208 | if (in_array($field['type'], array('images','image'))){ 209 | $this->item[$name] = api_image_src($this->item[$name]); 210 | } else 211 | if ($name != 'title'){ 212 | $this->item[$name] = $field['handler']->setItem($this->item)->parseTeaser($this->item[$name]); 213 | } 214 | 215 | } 216 | 217 | // убираем ненужное 218 | foreach($fields as $name => $field){ 219 | unset($fields[$name]['handler']); 220 | } 221 | 222 | $this->result['item'] = $this->item; 223 | $this->result['additionally'] = array( 224 | 'ctype' => $this->ctype, 225 | 'fields' => $fields, 226 | 'props' => $props, 227 | 'category' => $category 228 | ); 229 | 230 | } 231 | 232 | } 233 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_content_get_props.php: -------------------------------------------------------------------------------- 1 | array( 27 | 'rules' => array( 28 | array('required'), 29 | array('digits') 30 | ) 31 | ), 32 | 'is_in_filter' => array( 33 | 'default' => 0, 34 | 'rules' => array( 35 | array('digits') 36 | ) 37 | ), 38 | 'ids' => array( 39 | 'default' => '', 40 | 'rules' => array( 41 | array('regexp', '/^([0-9,]+)$/i') 42 | ) 43 | ) 44 | ); 45 | 46 | /** 47 | * Служебное свойство типа контента 48 | * для этого экшена 49 | * @var array 50 | */ 51 | private $ctype; 52 | 53 | public function validateApiRequest($ctype_name=null) { 54 | 55 | if(!$ctype_name){ 56 | return array('error_msg' => LANG_API_EMPTY_CTYPE); 57 | } 58 | 59 | $this->ctype = $this->model->getContentTypeByName($ctype_name); 60 | 61 | if(!$this->ctype){ 62 | return array('error_msg' => LANG_API_EMPTY_CTYPE); 63 | } 64 | 65 | return false; 66 | 67 | } 68 | 69 | public function run($ctype_name){ 70 | 71 | $ids = $this->request->get('ids'); 72 | if($ids){ 73 | 74 | $ids = explode(',', $ids); 75 | $ids = array_filter($ids); 76 | 77 | $this->model->filterIn('p.id', $ids); 78 | 79 | } 80 | 81 | if($this->request->get('is_in_filter')){ 82 | $this->model->filterEqual('p.is_in_filter', 1); 83 | } 84 | 85 | $fields = $this->model->getContentProps($this->ctype['name'], $this->request->get('cat_id')); 86 | 87 | $this->result['count'] = count($fields); 88 | $this->result['items'] = $fields; 89 | 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_content_get_props_values.php: -------------------------------------------------------------------------------- 1 | array( 27 | 'rules' => array( 28 | array('required'), 29 | array('digits') 30 | ) 31 | ), 32 | 'cat_id' => array( 33 | 'rules' => array( 34 | array('required'), 35 | array('digits'), 36 | array('min', 2) 37 | ) 38 | ), 39 | ); 40 | 41 | /** 42 | * Служебное свойство типа контента 43 | * для этого экшена 44 | * @var array 45 | */ 46 | private $ctype; 47 | 48 | public function validateApiRequest($ctype_name=null) { 49 | 50 | if(!$ctype_name){ 51 | return array('error_msg' => LANG_API_EMPTY_CTYPE); 52 | } 53 | 54 | $this->ctype = $this->model->getContentTypeByName($ctype_name); 55 | 56 | if(!$this->ctype){ 57 | return array('error_msg' => LANG_API_EMPTY_CTYPE); 58 | } 59 | 60 | return false; 61 | 62 | } 63 | 64 | public function run($ctype_name){ 65 | 66 | // просмотр записей запрещен 67 | if (empty($this->ctype['options']['item_on']) || empty($this->ctype['is_cats'])) { return; } 68 | 69 | $props_results = array(); 70 | 71 | $props = $this->model->getContentProps($this->ctype['name'], $this->request->get('cat_id')); 72 | 73 | $props_values = $this->model->getPropsValues($this->ctype['name'], $this->request->get('item_id')); 74 | 75 | if ($props && array_filter((array)$props_values)) { 76 | 77 | $props_fields = $this->getPropsFields($props); 78 | $props_fieldsets = cmsForm::mapFieldsToFieldsets($props); 79 | 80 | foreach($props_fieldsets as $fieldset){ 81 | 82 | $props_result = array( 83 | 'title' => $fieldset['title'], 84 | 'fields' => array() 85 | ); 86 | if ($fieldset['fields']){ 87 | foreach($fieldset['fields'] as $prop){ 88 | if (isset($props_values[$prop['id']])) { 89 | $prop_field = $props_fields[$prop['id']]; 90 | $props_result['fields'][$prop['id']] = array( 91 | 'title' => $prop['title'], 92 | 'value' => $prop_field->parse($props_values[$prop['id']]) 93 | ); 94 | } 95 | } 96 | } 97 | 98 | $props_results[] = $props_result; 99 | 100 | } 101 | } 102 | 103 | $this->result['count'] = count($props_results); 104 | $this->result['items'] = $props_results; 105 | 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_content_update_item.php: -------------------------------------------------------------------------------- 1 | array( 15 | 'default' => 0, 16 | 'rules' => array( 17 | array('required'), 18 | array('digits') 19 | ) 20 | ) 21 | ); 22 | 23 | private $ctype, $item, $is_owner, $is_premoderation, $is_moderator, $is_date_pub_ext_allowed, $fields; 24 | 25 | public function validateApiRequest($ctype_name = null) { 26 | 27 | if(!$ctype_name){ 28 | return array('error_msg' => LANG_API_EMPTY_CTYPE); 29 | } 30 | 31 | $this->ctype = $this->model->getContentTypeByName($ctype_name); 32 | 33 | if(!$this->ctype){ 34 | return array('error_code' => 322); 35 | } 36 | 37 | $this->item = $this->model->getContentItem($this->ctype['name'], $this->request->get('id')); 38 | if (!$this->item) { return array('error_code' => 778); } 39 | 40 | $this->item['ctype_id'] = $this->ctype['id']; 41 | $this->item['ctype_name'] = $this->ctype['name']; 42 | $this->item['ctype_data'] = $this->ctype; 43 | 44 | // автор записи? 45 | $this->is_owner = $this->item['user_id'] == $this->cms_user->id; 46 | 47 | // проверяем наличие доступа 48 | if (!cmsUser::isAllowed($this->ctype['name'], 'edit')) { return array('error_code' => 15); } 49 | if (!cmsUser::isAllowed($this->ctype['name'], 'edit', 'all') && !cmsUser::isAllowed($this->ctype['name'], 'edit', 'premod_all')) { 50 | if ( 51 | (cmsUser::isAllowed($this->ctype['name'], 'edit', 'own') || 52 | cmsUser::isAllowed($this->ctype['name'], 'edit', 'premod_own') 53 | ) && !$this->is_owner) { 54 | return array('error_code' => 15); 55 | } 56 | } 57 | 58 | // модерация 59 | $this->is_premoderation = false; 60 | if(cmsUser::isAllowed($this->ctype['name'], 'edit', 'premod_own', true) || cmsUser::isAllowed($this->ctype['name'], 'edit', 'premod_all', true)){ 61 | $this->is_premoderation = true; 62 | } 63 | if (!$this->is_premoderation && !$this->item['date_approved']) { 64 | $this->is_premoderation = cmsUser::isAllowed($this->ctype['name'], 'add', 'premod', true); 65 | } 66 | $this->is_moderator = $this->cms_user->is_admin || cmsCore::getModel('moderation')->userIsContentModerator($this->ctype['name'], $this->cms_user->id); 67 | 68 | if (!$this->item['is_approved'] && !$this->is_moderator && !$this->item['is_draft']) { return array('error_code' => 15); } 69 | 70 | if ($this->item['is_deleted']){ 71 | 72 | $allow_restore = (cmsUser::isAllowed($this->ctype['name'], 'restore', 'all') || 73 | (cmsUser::isAllowed($this->ctype['name'], 'restore', 'own') && $this->is_owner)); 74 | 75 | if (!$this->is_moderator && !$allow_restore){ return array('error_code' => 15); } 76 | } 77 | 78 | 79 | // Определяем наличие полей-свойств 80 | $props = $this->model->getContentProps($this->ctype['name']); 81 | $this->ctype['props'] = $props; 82 | 83 | // Если включены личные папки - получаем их список 84 | $folders_list = array(); 85 | 86 | if ($this->ctype['is_folders']){ 87 | $folders_list = $this->model->getContentFolders($this->ctype['id'], $this->item['user_id']); 88 | $folders_list = array_collection_to_list($folders_list, 'id', 'title'); 89 | } 90 | 91 | // Получаем поля для данного типа контента 92 | $this->fields = $this->model->orderBy('ordering')->getContentFields($this->ctype['name'], $this->item['id']); 93 | 94 | // Если этот контент можно создавать в группах (сообществах) то получаем список групп 95 | $groups_list = array(); 96 | 97 | if ($this->ctype['is_in_groups'] || $this->ctype['is_in_groups_only']){ 98 | 99 | $groups_model = cmsCore::getModel('groups'); 100 | $groups = $groups_model->getUserGroups($this->cms_user->id); 101 | 102 | if ($groups){ 103 | $groups_list = ($this->ctype['is_in_groups_only']) ? array() : array('0'=>''); 104 | $groups_list = $groups_list + array_collection_to_list($groups, 'id', 'title'); 105 | } 106 | 107 | } 108 | 109 | // Строим форму 110 | $form = $this->getItemForm($this->ctype, $this->fields, 'edit', array( 111 | 'groups_list' => $groups_list, 112 | 'folders_list' => $folders_list 113 | ), $this->item['id'], $this->item); 114 | 115 | list($this->ctype, $this->item) = cmsEventsManager::hook('content_edit', array($this->ctype, $this->item)); 116 | list($form, $this->item) = cmsEventsManager::hook("content_{$this->ctype['name']}_form", array($form, $this->item)); 117 | 118 | if ($this->ctype['props']){ 119 | 120 | $category_id = (($this->request->has('category_id') && $this->ctype['options']['is_cats_change']) ? 121 | $this->request->get('category_id', 0) : 122 | $this->item['category_id']); 123 | 124 | $item_props = $this->model->getContentProps($this->ctype['name'], $category_id); 125 | $item_props_fields = $this->getPropsFields($item_props); 126 | $this->item['props'] = $this->model->getPropsValues($this->ctype['name'], $this->item['id']); 127 | foreach($item_props_fields as $field){ 128 | $form->addField('props', $field); 129 | } 130 | } 131 | 132 | $is_date_pub_days_allowed = $this->ctype['is_date_range'] && cmsUser::isAllowed($this->ctype['name'], 'pub_long', 'days'); 133 | $this->is_date_pub_ext_allowed = $is_date_pub_days_allowed && cmsUser::isAllowed($this->ctype['name'], 'pub_max_ext'); 134 | 135 | if ($this->is_date_pub_ext_allowed){ 136 | $this->item['pub_days'] = 0; 137 | } 138 | 139 | $add_cats = $this->model->getContentItemCategories($this->ctype['name'], $this->item['id']); 140 | 141 | if ($add_cats){ 142 | foreach($add_cats as $index => $cat_id){ 143 | if ($cat_id == $this->item['category_id']) { unset($add_cats[$index]); break; } 144 | } 145 | } 146 | 147 | // Парсим форму и получаем поля записи 148 | $this->item = array_merge($this->item, $form->parse($this->request, true, $this->item)); 149 | 150 | // Проверям правильность заполнения 151 | $errors = $form->validate($this, $this->item); 152 | 153 | if (!$errors){ 154 | list($this->item, $errors) = cmsEventsManager::hook('content_validate', array($this->item, $errors)); 155 | } 156 | 157 | if($errors){ 158 | 159 | if($errors === true){ 160 | $errors = array('csrf_token' => LANG_API_ERROR_CSRF_TOKEN); 161 | } 162 | 163 | return array( 164 | 'error_code' => 100, 165 | 'error_msg' => '', 166 | 'request_params' => $errors 167 | ); 168 | 169 | } 170 | 171 | return false; 172 | 173 | } 174 | 175 | public function run($ctype_name){ 176 | 177 | $is_pub_control = cmsUser::isAllowed($this->ctype['name'], 'pub_on'); 178 | $is_date_pub_allowed = $this->ctype['is_date_range'] && cmsUser::isAllowed($this->ctype['name'], 'pub_late'); 179 | $is_date_pub_end_allowed = $this->ctype['is_date_range'] && cmsUser::isAllowed($this->ctype['name'], 'pub_long', 'any'); 180 | 181 | $succes_text = ''; 182 | 183 | // форма отправлена к контексте черновика 184 | $is_draf_submitted = $this->request->has('to_draft'); 185 | 186 | if($is_draf_submitted){ 187 | 188 | $this->item['is_approved'] = 0; 189 | 190 | } else { 191 | 192 | if($this->item['is_draft']){ 193 | $this->item['is_approved'] = !$this->is_premoderation || $this->is_moderator; 194 | } else { 195 | $this->item['is_approved'] = $this->item['is_approved'] && (!$this->is_premoderation || $this->is_moderator); 196 | } 197 | 198 | } 199 | 200 | if($is_draf_submitted || !$this->item['is_approved']){ 201 | unset($this->item['date_approved']); 202 | } 203 | 204 | if($this->is_owner){ 205 | $this->item['approved_by'] = null; 206 | } 207 | 208 | $date_pub_time = strtotime($this->item['date_pub']); 209 | $date_pub_end_time = strtotime($this->item['date_pub_end']); 210 | $now_time = time(); 211 | $now_date = strtotime(date('Y-m-d', $now_time)); 212 | $is_pub = true; 213 | 214 | if ($is_date_pub_allowed){ 215 | $time_to_pub = $date_pub_time - $now_time; 216 | $is_pub = $is_pub && ($time_to_pub < 0); 217 | } 218 | if ($is_date_pub_end_allowed && !empty($this->item['date_pub_end'])){ 219 | $days_from_pub = floor(($now_date - $date_pub_end_time)/60/60/24); 220 | $is_pub = $is_pub && ($days_from_pub < 1); 221 | } else if ($this->is_date_pub_ext_allowed && !$this->cms_user->is_admin) { 222 | $days = $this->item['pub_days']; 223 | $date_pub_end_time = (($date_pub_end_time - $now_time) > 0 ? $date_pub_end_time : $now_time) + 60*60*24*$days; 224 | $days_from_pub = floor(($now_date - $date_pub_end_time)/60/60/24); 225 | $is_pub = $is_pub && ($days_from_pub < 1); 226 | $this->item['date_pub_end'] = date('Y-m-d', $date_pub_end_time); 227 | } 228 | 229 | unset($this->item['pub_days']); 230 | 231 | if (!$is_pub_control) { unset($this->item['is_pub']); } 232 | if (!isset($this->item['is_pub']) || !empty($this->item['is_pub'])){ 233 | $this->item['is_pub'] = $is_pub; 234 | if (!$is_pub){ 235 | $succes_text = LANG_CONTENT_IS_PUB_OFF; 236 | } 237 | } 238 | 239 | if (!empty($this->ctype['options']['is_cats_multi'])){ 240 | $add_cats = $this->request->get('add_cats', array()); 241 | if (is_array($add_cats)){ 242 | foreach($add_cats as $index=>$cat_id){ 243 | if (!is_numeric($cat_id) || !$cat_id){ 244 | unset($add_cats[$index]); 245 | } 246 | } 247 | if ($add_cats){ 248 | $this->item['add_cats'] = $add_cats; 249 | } 250 | } 251 | } 252 | 253 | $this->item = cmsEventsManager::hook('content_before_update', $this->item); 254 | $this->item = cmsEventsManager::hook("content_{$this->ctype['name']}_before_update", $this->item); 255 | 256 | // SEO параметры 257 | $item_seo = $this->prepareItemSeo($this->item, $this->fields, $this->ctype); 258 | if(empty($this->ctype['options']['is_manual_title']) && !empty($this->ctype['options']['seo_title_pattern'])){ 259 | $this->item['seo_title'] = string_replace_keys_values_extended($this->ctype['options']['seo_title_pattern'], $item_seo); 260 | } else { 261 | $this->item['seo_title'] = empty($this->ctype['options']['is_manual_title']) ? null : $this->item['seo_title']; 262 | } 263 | if ($this->ctype['is_auto_keys']){ 264 | if(!empty($this->ctype['options']['seo_keys_pattern'])){ 265 | $this->item['seo_keys'] = string_replace_keys_values_extended($this->ctype['options']['seo_keys_pattern'], $item_seo); 266 | } else { 267 | $this->item['seo_keys'] = string_get_meta_keywords($this->item['content']); 268 | } 269 | } 270 | if ($this->ctype['is_auto_desc']){ 271 | if(!empty($this->ctype['options']['seo_desc_pattern'])){ 272 | $this->item['seo_desc'] = string_get_meta_description(string_replace_keys_values_extended($this->ctype['options']['seo_desc_pattern'], $item_seo)); 273 | } else { 274 | $this->item['seo_desc'] = string_get_meta_description($this->item['content']); 275 | } 276 | } 277 | 278 | $this->item = $this->model->updateContentItem($this->ctype, $this->item['id'], $this->item, $this->fields); 279 | 280 | $this->bindItemToParents($this->ctype, $this->item); 281 | 282 | cmsEventsManager::hook('content_after_update', $this->item); 283 | cmsEventsManager::hook("content_{$this->ctype['name']}_after_update", $this->item); 284 | 285 | if(!$is_draf_submitted){ 286 | 287 | if ($this->item['is_approved'] || $this->is_moderator){ 288 | 289 | // новая запись, например из черновика 290 | if(empty($this->item['date_approved'])){ 291 | cmsEventsManager::hook('content_after_add_approve', array('ctype_name' => $this->ctype['name'], 'item' => $this->item)); 292 | cmsEventsManager::hook("content_{$this->ctype['name']}_after_add_approve", $this->item); 293 | } 294 | 295 | cmsEventsManager::hook('content_after_update_approve', array('ctype_name'=>$this->ctype['name'], 'item'=>$this->item)); 296 | cmsEventsManager::hook("content_{$this->ctype['name']}_after_update_approve", $this->item); 297 | 298 | } else { 299 | 300 | $this->item['page_url'] = href_to_abs($this->ctype['name'], $this->item['slug'] . '.html'); 301 | 302 | $succes_text = cmsCore::getController('moderation')->requestModeration($this->ctype['name'], $this->item, empty($this->item['date_approved'])); 303 | 304 | } 305 | 306 | } 307 | 308 | $this->result = array( 309 | 'success_text' => $succes_text, 310 | 'item_id' => $this->item['id'] 311 | ); 312 | 313 | } 314 | 315 | } 316 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_geo_get.php: -------------------------------------------------------------------------------- 1 | array( 11 | 'default' => '', 12 | 'rules' => array( 13 | array('required'), 14 | array('in_array', array('regions', 'cities', 'countries')) 15 | ) 16 | ), 17 | 'parent_id' => array( 18 | 'default' => '', 19 | 'rules' => array( 20 | array('number') 21 | ) 22 | ) 23 | ); 24 | 25 | public function run(){ 26 | 27 | $type = $this->request->get('type', ''); 28 | $parent_id = $this->request->get('parent_id', 0); 29 | 30 | $data = array(); 31 | 32 | switch ( $type ){ 33 | 34 | case 'regions': $items = $this->model->getRegions( $parent_id ); 35 | $select_text = LANG_GEO_SELECT_REGION; 36 | break; 37 | 38 | case 'cities': $items = $this->model->getCities( $parent_id ); 39 | $select_text = LANG_GEO_SELECT_CITY; 40 | break; 41 | 42 | case 'countries': $items = $this->model->getCountries(); 43 | $select_text = LANG_GEO_SELECT_COUNTRY; 44 | break; 45 | 46 | } 47 | 48 | if ($items){ 49 | 50 | $items = array_unique($items); 51 | 52 | $items = array('0' => $select_text) + $items; 53 | 54 | foreach ($items as $id => $name){ 55 | $data[] = array( 56 | 'id' => $id, 57 | 'name' => $name 58 | ); 59 | } 60 | 61 | } 62 | 63 | $this->result['count'] = count($items); 64 | $this->result['items'] = $items; 65 | 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_geo_get_current_country.php: -------------------------------------------------------------------------------- 1 | result = array( 12 | 'item' => $this->getGeoByIp() 13 | ); 14 | 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_images_get_presets.php: -------------------------------------------------------------------------------- 1 | model->orderByList(array( 14 | array('by' => 'is_square', 'to' => 'asc'), 15 | array('by' => 'width', 'to' => 'desc') 16 | ))->getPresets(); 17 | 18 | $this->result['items'] = $presets; 19 | $this->result['count'] = count($presets); 20 | 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_images_upload.php: -------------------------------------------------------------------------------- 1 | array( 13 | 'default' => '', 14 | 'rules' => array( 15 | array('required'), 16 | array('sysname'), 17 | array('max_length', 40) 18 | ) 19 | ), 20 | 'presets' => array( 21 | 'default' => '', 22 | 'rules' => array( 23 | array('regexp', '/^([a-z0-9\_,]+)$/i') 24 | ) 25 | ), 26 | ); 27 | 28 | public function validateApiRequest() { 29 | 30 | $name = $this->request->get('name'); 31 | 32 | // устанавливаем разрешенные типы изображений 33 | $this->cms_uploader->setAllowedMime($this->allowed_mime); 34 | 35 | cmsEventsManager::hook('images_before_upload', array($name, $this->cms_uploader), null, $this->request); 36 | 37 | // Непосредственно загружаем 38 | $result = $this->cms_uploader->upload($name); 39 | 40 | // Начинаем работу с изображением 41 | if ($result['success']){ 42 | 43 | try { 44 | $image = new cmsImages($result['path']); 45 | } catch (Exception $exc) { 46 | $result['success'] = false; 47 | $result['error'] = LANG_UPLOAD_ERR_MIME; 48 | } 49 | 50 | } 51 | 52 | // Не получилось, удаляем исходник, показываем ошибку 53 | if (!$result['success']){ 54 | if(!empty($result['path'])){ 55 | files_delete_file($result['path'], 2); 56 | } 57 | return array( 58 | 'error_msg' => $result['error'] 59 | ); 60 | } 61 | 62 | // Переданные пресеты 63 | $sizes = $this->request->get('presets'); 64 | 65 | if (!empty($sizes)){ 66 | $sizes = explode(',', $sizes); 67 | } else { 68 | $sizes = array_keys((array)$this->model->getPresetsList()); 69 | $sizes[] = 'original'; 70 | } 71 | 72 | // Результирующий массив изображений после конвертации 73 | $result['paths'] = []; 74 | 75 | // Дополняем оригиналом, если нужно 76 | if (in_array('original', $sizes, true)){ 77 | $result['paths']['original'] = array( 78 | 'path' => $result['url'], 79 | 'url' => $this->cms_config->upload_host_abs . '/' . $result['url'] 80 | ); 81 | } 82 | 83 | // Получаем пресеты 84 | $presets = $this->model->orderByList(array( 85 | ['by' => 'is_square', 'to' => 'asc'], 86 | ['by' => 'width', 'to' => 'desc'] 87 | ))->getPresets(); 88 | 89 | list($result, $presets, $sizes) = cmsEventsManager::hook('images_after_upload', array($result, $presets, $sizes), null, $this->request); 90 | 91 | // Создаём изображения по пресетам 92 | foreach($presets as $p){ 93 | 94 | if (!in_array($p['name'], $sizes, true)){ 95 | continue; 96 | } 97 | 98 | $resized_path = $image->resizeByPreset($p); 99 | 100 | if (!$resized_path) { continue; } 101 | 102 | $result['paths'][$p['name']] = [ 103 | 'path' => $resized_path, 104 | 'url' => $this->cms_config->upload_host_abs . '/' . $resized_path 105 | ]; 106 | 107 | } 108 | 109 | list($result, $presets, $sizes) = cmsEventsManager::hook('images_after_resize', array($result, $presets, $sizes), null, $this->request); 110 | 111 | if (!in_array('original', $sizes, true)){ 112 | files_delete_file($result['path'], 2); 113 | } 114 | 115 | unset($result['path']); 116 | 117 | if(!$result['paths']){ 118 | return array( 119 | 'error_msg' => LANG_UPLOAD_ERR_NO_FILE 120 | ); 121 | } 122 | 123 | $this->result['items'] = $result['paths']; 124 | $this->result['host'] = $this->cms_config->upload_host_abs . '/'; 125 | $this->result['count'] = count($result['paths']); 126 | 127 | return false; 128 | 129 | } 130 | 131 | public function run(){} 132 | 133 | } 134 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_messages_delete_contact.php: -------------------------------------------------------------------------------- 1 | array( 15 | 'default' => 0, 16 | 'rules' => array( 17 | array('required'), 18 | array('digits') 19 | ) 20 | ) 21 | ); 22 | 23 | private $contact_id; 24 | 25 | public function validateApiRequest() { 26 | 27 | $this->contact_id = $this->request->get('contact_id'); 28 | 29 | $contact = $this->model->getContact($this->cms_user->id, $this->contact_id); 30 | 31 | if (!$contact){ 32 | return array( 33 | 'error_code' => 100, 34 | 'error_msg' => '', 35 | 'request_params' => array( 36 | 'contact_id' => ERR_VALIDATE_INVALID 37 | ) 38 | ); 39 | } 40 | 41 | return false; 42 | 43 | } 44 | 45 | public function run(){ 46 | 47 | $this->model->deleteContact($this->cms_user->id, $this->contact_id); 48 | 49 | $count = $this->model->getContactsCount($this->cms_user->id); 50 | 51 | $this->result = array( 52 | 'count' => $count 53 | ); 54 | 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_messages_delete_mesages.php: -------------------------------------------------------------------------------- 1 | array( 15 | 'default' => [], 16 | 'rules' => array( 17 | array('required') 18 | ) 19 | ) 20 | ); 21 | 22 | public function run(){ 23 | 24 | $_message_ids = $this->request->get('message_ids'); 25 | 26 | $message_ids = []; 27 | 28 | foreach ($_message_ids as $message_id) { 29 | $message_ids[] = (int)$message_id; 30 | } 31 | 32 | $delete_msg_ids = $this->model->deleteMessages($this->cms_user->id, $message_ids); 33 | 34 | if($delete_msg_ids){ 35 | $message_ids = array_diff($message_ids, $delete_msg_ids); 36 | } 37 | 38 | $this->result = array( 39 | 'remove_text' => LANG_PM_IS_DELETE, 40 | 'message_ids' => $message_ids, 41 | 'delete_msg_ids' => $delete_msg_ids 42 | ); 43 | 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_messages_delete_notice.php: -------------------------------------------------------------------------------- 1 | array( 13 | 'default' => 0, 14 | 'rules' => array( 15 | array('digits') 16 | ) 17 | ) 18 | ); 19 | 20 | public function run(){ 21 | 22 | $notice_id = $this->request->get('id'); 23 | 24 | if($notice_id){ 25 | 26 | $notice = $this->model->getNotice($notice_id); 27 | 28 | if($notice && $notice['user_id'] == $this->cms_user->id && !empty($notice['options']['is_closeable'])){ 29 | $this->model->deleteNotice($notice_id); 30 | } 31 | 32 | } else { 33 | $this->model->deleteUserNotices($this->cms_user->id); 34 | } 35 | 36 | $this->result = array( 37 | 'count' => $this->model->getNoticesCount($this->cms_user->id) 38 | ); 39 | 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_messages_forgive.php: -------------------------------------------------------------------------------- 1 | array( 15 | 'default' => 0, 16 | 'rules' => array( 17 | array('required'), 18 | array('digits') 19 | ) 20 | ) 21 | ); 22 | 23 | private $contact_id; 24 | 25 | public function validateApiRequest() { 26 | 27 | $this->contact_id = $this->request->get('contact_id'); 28 | 29 | $contact = $this->model->getContact($this->cms_user->id, $this->contact_id); 30 | 31 | if (!$contact){ 32 | return array( 33 | 'error_code' => 100, 34 | 'error_msg' => '', 35 | 'request_params' => array( 36 | 'contact_id' => ERR_VALIDATE_INVALID 37 | ) 38 | ); 39 | } 40 | 41 | return false; 42 | 43 | } 44 | 45 | public function run(){ 46 | 47 | $this->model->forgiveContact($this->cms_user->id, $this->contact_id); 48 | 49 | $count = $this->model->getContactsCount($this->cms_user->id); 50 | 51 | $this->result = array( 52 | 'count' => $count 53 | ); 54 | 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_messages_get.php: -------------------------------------------------------------------------------- 1 | array( 15 | 'default' => 0, 16 | 'rules' => array( 17 | array('required'), 18 | array('digits') 19 | ) 20 | ), 21 | 'message_id' => array( 22 | 'default' => 0, 23 | 'rules' => array( 24 | array('digits') 25 | ) 26 | ) 27 | ); 28 | 29 | private $contact; 30 | 31 | public function validateApiRequest() { 32 | 33 | $this->contact = $this->model->getContact($this->cms_user->id, $this->request->get('contact_id')); 34 | 35 | if (!$this->contact){ 36 | return array( 37 | 'error_code' => 100, 38 | 'error_msg' => '', 39 | 'request_params' => array( 40 | 'contact_id' => ERR_VALIDATE_INVALID 41 | ) 42 | ); 43 | } 44 | 45 | return false; 46 | 47 | } 48 | 49 | public function run(){ 50 | 51 | $message_id = $this->request->get('message_id'); 52 | 53 | // если передан id сообщения, то показываем более ранние от него 54 | if($message_id){ 55 | $this->model->filterLt('id', $message_id); 56 | } 57 | 58 | // чтобы не считать общее кол-во, получаем на один больше 59 | $messages = $this->model->limit($this->options['limit']+1)->getMessages($this->cms_user->id, $this->contact['id']); 60 | 61 | if(count($messages) > $this->options['limit']){ 62 | $has_older = true; array_shift($messages); 63 | } else { 64 | $has_older = false; 65 | } 66 | 67 | $this->result = array( 68 | 'is_me_ignored' => $this->model->isContactIgnored($this->contact['id'], $this->cms_user->id), 69 | 'is_private' => !$this->cms_user->isPrivacyAllowed($this->contact, 'messages_pm'), 70 | 'contact' => $this->contact, 71 | 'has_older' => $has_older, 72 | 'older_message_id' => $message_id, 73 | 'items' => $messages, 74 | 'user_id' => $this->cms_user->id 75 | ); 76 | 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_messages_get_notices.php: -------------------------------------------------------------------------------- 1 | array( 13 | 'default' => 1, 14 | 'rules' => array( 15 | array('digits') 16 | ) 17 | ), 18 | 'perpage' => array( 19 | 'default' => 15, 20 | 'rules' => array( 21 | array('digits') 22 | ) 23 | ), 24 | ); 25 | 26 | public function run(){ 27 | 28 | $page = $this->request->get('page'); 29 | $perpage = $this->request->get('perpage'); 30 | 31 | $total = $this->model->getNoticesCount($this->cms_user->id); 32 | 33 | $this->model->limitPage($page, $perpage); 34 | 35 | $notices = $this->model->getNotices($this->cms_user->id); 36 | 37 | $this->result['paging'] = array( 38 | 'page' => $page, 39 | 'per_page' => $perpage 40 | ); 41 | $this->result['count'] = $total; 42 | $this->result['items'] = $notices; 43 | 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_messages_ignore.php: -------------------------------------------------------------------------------- 1 | array( 15 | 'default' => 0, 16 | 'rules' => array( 17 | array('required'), 18 | array('digits') 19 | ) 20 | ) 21 | ); 22 | 23 | private $contact_id; 24 | 25 | public function validateApiRequest() { 26 | 27 | $this->contact_id = $this->request->get('contact_id'); 28 | 29 | $contact = $this->model->getContact($this->cms_user->id, $this->contact_id); 30 | 31 | if (!$contact){ 32 | return array( 33 | 'error_code' => 100, 34 | 'error_msg' => '', 35 | 'request_params' => array( 36 | 'contact_id' => ERR_VALIDATE_INVALID 37 | ) 38 | ); 39 | } 40 | 41 | return false; 42 | 43 | } 44 | 45 | public function run(){ 46 | 47 | $this->model->ignoreContact($this->cms_user->id, $this->contact_id); 48 | $this->model->deleteContact($this->cms_user->id, $this->contact_id); 49 | 50 | $count = $this->model->getContactsCount($this->cms_user->id); 51 | 52 | $this->result = array( 53 | 'count' => $count 54 | ); 55 | 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_messages_readed.php: -------------------------------------------------------------------------------- 1 | array( 15 | 'default' => '', 16 | 'rules' => array( 17 | array('required'), 18 | array('regexp', '/^([0-9]{1}[0-9,]*)$/') 19 | ) 20 | ) 21 | ); 22 | 23 | public function run(){ 24 | 25 | $ids = explode(',', $this->request->get('ids')); 26 | 27 | $this->model->filterIn('id', $ids); 28 | $this->model->filterEqual('to_id', $this->cms_user->id); 29 | 30 | $this->model->updateFiltered('{users}_messages', array( 31 | 'is_new' => 0 32 | )); 33 | 34 | $this->result = array( 35 | 'ids' => $ids, 36 | 'user_id' => $this->cms_user->id 37 | ); 38 | 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_messages_restore_mesage.php: -------------------------------------------------------------------------------- 1 | array( 15 | 'default' => 0, 16 | 'rules' => array( 17 | array('required'), 18 | array('digits') 19 | ) 20 | ) 21 | ); 22 | 23 | public function run(){ 24 | 25 | $message_id = $this->request->get('message_id'); 26 | 27 | $this->model->restoreMessages($this->cms_user->id, $message_id); 28 | 29 | $this->result = array( 30 | 'message_id' => $message_id, 31 | 'user_id' => $this->cms_user->id 32 | ); 33 | 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_messages_send.php: -------------------------------------------------------------------------------- 1 | array( 15 | 'default' => 0, 16 | 'rules' => array( 17 | array('required'), 18 | array('digits') 19 | ) 20 | ), 21 | 'content' => array( 22 | 'default' => '', 23 | 'rules' => array( 24 | array('required'), 25 | array('max_length', 65535) 26 | ) 27 | ), 28 | 'csrf_token' => array( 29 | 'default' => '', 30 | 'rules' => array( 31 | array('required') 32 | ) 33 | ) 34 | ); 35 | 36 | private $message, $contact_id; 37 | 38 | public function validateApiRequest() { 39 | 40 | if (!cmsForm::validateCSRFToken($this->request->get('csrf_token'))){ 41 | return array( 42 | 'error_code' => 100, 43 | 'error_msg' => '', 44 | 'request_params' => array( 45 | 'csrf_token' => LANG_API_ERROR_CSRF_TOKEN 46 | ) 47 | ); 48 | } 49 | 50 | $this->contact_id = $this->request->get('contact_id'); 51 | 52 | $is_contact_exists = $this->model->isContactExists($this->cms_user->id, $this->contact_id); 53 | 54 | if ($is_contact_exists){ 55 | $this->model->updateContactsDateLastMsg($this->cms_user->id, $this->contact_id, false); 56 | } 57 | 58 | if (!$is_contact_exists){ 59 | $this->model->addContact($this->cms_user->id, $this->contact_id); 60 | } 61 | 62 | $contact = $this->model->getContact($this->cms_user->id, $this->contact_id); 63 | 64 | // Контакт не в игноре у отправителя? 65 | if ($contact['is_ignored']){ 66 | return array( 67 | 'error_msg' => LANG_PM_CONTACT_IS_IGNORED 68 | ); 69 | } 70 | 71 | // Отправитель не в игноре у контакта? 72 | if ($this->model->isContactIgnored($this->contact_id, $this->cms_user->id)){ 73 | return array( 74 | 'error_msg' => LANG_PM_YOU_ARE_IGNORED 75 | ); 76 | } 77 | 78 | // Контакт принимает сообщения от этого пользователя? 79 | if (!$this->cms_user->isPrivacyAllowed($contact, 'messages_pm')){ 80 | return array( 81 | 'error_msg' => LANG_PM_CONTACT_IS_PRIVATE 82 | ); 83 | } 84 | 85 | $this->message = cmsEventsManager::hook('html_filter', $this->request->get('content')); 86 | 87 | if (!$this->message) { 88 | return array( 89 | 'error_code' => 100, 90 | 'error_msg' => '', 91 | 'request_params' => array( 92 | 'content' => ERR_VALIDATE_REQUIRED 93 | ) 94 | ); 95 | } 96 | 97 | return false; 98 | 99 | } 100 | 101 | public function run(){ 102 | 103 | $this->setSender($this->cms_user->id)->addRecipient($this->contact_id); 104 | 105 | $message_id = $this->sendMessage($this->message); 106 | 107 | // 108 | // Отправляем уведомление на почту 109 | // 110 | $user_to = cmsCore::getModel('users')->getUser($this->contact_id); 111 | 112 | if (!$user_to['is_online']) { 113 | 114 | if($this->model->getNewMessagesCount($user_to['id']) == 1){ 115 | $this->sendNoticeEmail('messages_new', array( 116 | 'user_url' => href_to_abs('users', $this->cms_user->id), 117 | 'user_nickname' => $this->cms_user->nickname, 118 | 'message' => strip_tags($this->message) 119 | )); 120 | } 121 | 122 | } 123 | 124 | $message = $this->model->getMessage($message_id); 125 | 126 | $this->result = array( 127 | 'message' => $message, 128 | 'date' => date($this->cms_config->date_format, time()), 129 | 'user_id' => $this->cms_user->id 130 | ); 131 | 132 | } 133 | 134 | } 135 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_users_add.php: -------------------------------------------------------------------------------- 1 | is_submitted = $this->request->has('submit'); 10 | 11 | if($this->is_submitted){ 12 | $this->check_sig = true; 13 | } 14 | 15 | } 16 | 17 | /** 18 | * Блокировка прямого вызова экшена 19 | * обязательное свойство 20 | * @var boolean 21 | */ 22 | public $lock_explicit_call = true; 23 | /** 24 | * Результат запроса 25 | * обязательное свойство 26 | * @var array 27 | */ 28 | public $result; 29 | /** 30 | * Флаг, обязующий проверять параметр sig запроса 31 | * sig привязан к домену сайта и к ip адресу посетителя 32 | * @var boolean 33 | */ 34 | public $check_sig = false; 35 | 36 | public $admin_required = true; 37 | 38 | /** 39 | * Возможные параметры запроса 40 | * с правилами валидации 41 | * Если запрос имеет параметры, необходимо описать их здесь 42 | * Правила валидации параметров задаются по аналогии с полями форм 43 | * @var array 44 | */ 45 | public $request_params = array(); 46 | 47 | private $is_submitted = false; 48 | 49 | public function validateApiRequest() { 50 | 51 | if(!$this->is_submitted){ 52 | return false; 53 | } 54 | 55 | $form = $this->getUserForm(); 56 | if(!$form){ return array('error_code' => 1); } 57 | 58 | // загружаем модель пользователя 59 | $this->users_model = cmsCore::getModel('users'); 60 | 61 | $user = $form->parse($this->request, true); 62 | 63 | $errors = $form->validate($this, $user, false); 64 | 65 | if (mb_strlen($user['password1']) < 6) { 66 | $errors['password1'] = sprintf(ERR_VALIDATE_MIN_LENGTH, 6); 67 | } 68 | 69 | if($errors){ 70 | 71 | return array( 72 | 'error_code' => 100, 73 | 'error_msg' => '', 74 | 'request_params' => $errors 75 | ); 76 | 77 | } 78 | 79 | $result = $this->users_model->addUser($user); 80 | 81 | if (!$result['success']){ 82 | 83 | return array( 84 | 'error_code' => 100, 85 | 'error_msg' => '', 86 | 'request_params' => (array)$result['errors'] 87 | ); 88 | 89 | } 90 | 91 | $user['id'] = $result['id']; 92 | 93 | cmsUser::setUPS('first_auth', 1, $user['id']); 94 | 95 | $this->user = $user; 96 | 97 | return false; 98 | 99 | } 100 | 101 | public function run(){ 102 | 103 | if(!$this->is_submitted){ 104 | return $this->returnForm(); 105 | } 106 | 107 | $this->result = array( 108 | 'user_id' => $this->user['id'], 109 | 'is_verify_email' => false, 110 | 'success_text' => sprintf(LANG_CP_USER_CREATED, $this->user['nickname']) 111 | ); 112 | 113 | } 114 | 115 | private function returnForm() { 116 | 117 | $this->result = array(); 118 | 119 | $form = $this->getUserForm(); 120 | if(!$form){ return; } 121 | 122 | $this->result['item'] = form_to_params($form); 123 | $this->result['sig'] = get_sig(); 124 | 125 | } 126 | 127 | private function getUserForm() { 128 | 129 | cmsCore::loadControllerLanguage('admin'); 130 | 131 | $form = $this->getControllerForm('admin', 'user', array('add')); 132 | if(!$form){ return false; } 133 | 134 | $form->removeFieldset('permissions'); 135 | 136 | return $form; 137 | 138 | } 139 | 140 | } 141 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_users_add_to_groups.php: -------------------------------------------------------------------------------- 1 | array( 35 | 'default' => 0, 36 | 'rules' => array( 37 | array('required'), 38 | array('digits') 39 | ) 40 | ), 41 | 'group_ids' => array( 42 | 'default' => array(), 43 | 'rules' => array( 44 | array('required') 45 | ) 46 | ) 47 | ); 48 | 49 | private $users_model, $user; 50 | 51 | public function validateApiRequest() { 52 | 53 | $group_ids = $this->request->get('group_ids', array()); 54 | 55 | foreach ($group_ids as $group_id) { 56 | if(!is_numeric($group_id)){ 57 | return array('request_params' => array( 58 | 'group_ids' => ERR_VALIDATE_DIGITS 59 | )); 60 | } 61 | } 62 | 63 | $this->users_model = cmsCore::getModel('users'); 64 | 65 | $this->user = $this->users_model->getUser($this->request->get('user_id')); 66 | 67 | if (!$this->user) { 68 | return array('error_code' => 113); 69 | } 70 | 71 | if ($this->user['is_admin']) { 72 | return array('error_code' => 15); 73 | } 74 | 75 | return false; 76 | 77 | } 78 | 79 | public function run(){ 80 | 81 | $this->user['groups'] = array_merge($this->user['groups'], $this->request->get('group_ids', array())); 82 | $this->user['groups'] = array_unique($this->user['groups']); 83 | 84 | $this->model->updateUser($this->user['id'], array( 85 | 'groups' => $this->user['groups'], 86 | 'date_group' => null 87 | )); 88 | 89 | $this->result = array( 90 | 'success' => true, 91 | 'groups' => $this->user['groups'] 92 | ); 93 | 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_users_email_exists.php: -------------------------------------------------------------------------------- 1 | array( 11 | 'default' => '', 12 | 'rules' => array( 13 | array('required'), 14 | array('email') 15 | ) 16 | ) 17 | ); 18 | 19 | public function run(){ 20 | 21 | $user = $this->model_users->getUserByEmail($this->request->get('email', '')); 22 | 23 | $this->result = array( 24 | 'exists' => $user ? true : false 25 | ); 26 | 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_users_get_groups.php: -------------------------------------------------------------------------------- 1 | model->getGroups(); 40 | 41 | $this->result['count'] = count($groups); 42 | $this->result['items'] = $groups; 43 | $this->result['sig'] = get_sig(); 44 | 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_users_get_sig.php: -------------------------------------------------------------------------------- 1 | result = array( 12 | 'sig' => get_sig(), 13 | 'csrf_token' => cmsForm::getCSRFToken() 14 | ); 15 | 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_users_remove_from_groups.php: -------------------------------------------------------------------------------- 1 | array( 35 | 'default' => 0, 36 | 'rules' => array( 37 | array('required'), 38 | array('digits') 39 | ) 40 | ), 41 | 'group_ids' => array( 42 | 'default' => array(), 43 | 'rules' => array( 44 | array('required') 45 | ) 46 | ) 47 | ); 48 | 49 | private $users_model, $user; 50 | 51 | public function validateApiRequest() { 52 | 53 | $group_ids = $this->request->get('group_ids', array()); 54 | 55 | foreach ($group_ids as $group_id) { 56 | if(!is_numeric($group_id)){ 57 | return array('request_params' => array( 58 | 'group_ids' => ERR_VALIDATE_DIGITS 59 | )); 60 | } 61 | } 62 | 63 | $this->users_model = cmsCore::getModel('users'); 64 | 65 | $this->user = $this->users_model->getUser($this->request->get('user_id')); 66 | 67 | if (!$this->user) { 68 | return array('error_code' => 113); 69 | } 70 | 71 | if ($this->user['is_admin']) { 72 | return array('error_code' => 15); 73 | } 74 | 75 | return false; 76 | 77 | } 78 | 79 | public function run(){ 80 | 81 | $group_ids = $this->request->get('group_ids', array()); 82 | 83 | $removed = array(); 84 | 85 | foreach ($group_ids as $group_id) { 86 | 87 | if(($key = array_search($group_id, $this->user['groups'])) !== false) { 88 | unset($this->user['groups'][$key]); 89 | $removed[] = $group_id; 90 | } 91 | 92 | } 93 | 94 | if($removed){ 95 | 96 | $this->model->updateUser($this->user['id'], array( 97 | 'groups' => $this->user['groups'], 98 | 'date_group' => null 99 | )); 100 | 101 | } 102 | 103 | $this->result = array( 104 | 'success' => ($removed ? true : false), 105 | 'groups' => $this->user['groups'] 106 | ); 107 | 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_users_update_password.php: -------------------------------------------------------------------------------- 1 | user = $this->model->getUser($this->cms_user->id); 29 | 30 | $form = $this->getForm('password'); 31 | if(!$form){ return array('error_code' => 1); } 32 | 33 | $data = $form->parse($this->request, true); 34 | 35 | $errors = $form->validate($this, $data); 36 | 37 | if($errors === true){ 38 | $errors = array('csrf_token' => LANG_API_ERROR_CSRF_TOKEN); 39 | } 40 | 41 | if (!$errors){ 42 | 43 | // совместимость 44 | if(method_exists($this->model, 'getUserByAuth')){ 45 | 46 | $user = $this->model->getUserByAuth($this->user['email'], $data['password']); 47 | 48 | if (!$user){ 49 | $errors = array('password' => LANG_OLD_PASS_INCORRECT); 50 | } 51 | 52 | } else { 53 | 54 | $password_hash = md5(md5($data['password']) . $this->cms_user->password_salt); 55 | 56 | if ($password_hash != $this->cms_user->password){ 57 | $errors = array('password' => LANG_OLD_PASS_INCORRECT); 58 | } 59 | 60 | } 61 | 62 | } 63 | 64 | if($errors){ 65 | 66 | return array( 67 | 'error_code' => 100, 68 | 'error_msg' => '', 69 | 'request_params' => $errors 70 | ); 71 | 72 | } 73 | 74 | unset($data['password']); 75 | 76 | $result = $this->model->updateUser($this->user['id'], $data); 77 | 78 | if (!$result['success']){ 79 | 80 | return array( 81 | 'error_code' => 100, 82 | 'error_msg' => '', 83 | 'request_params' => $result['errors'] 84 | ); 85 | 86 | } 87 | 88 | return false; 89 | 90 | } 91 | 92 | public function run(){ 93 | 94 | $this->result = array( 95 | 'success_text' => LANG_PASS_CHANGED, 96 | 'user_id' => $this->user['id'] 97 | ); 98 | 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_users_update_password_fields.php: -------------------------------------------------------------------------------- 1 | result = array(); 23 | 24 | $form = $this->getForm('password'); 25 | if(!$form){ return; } 26 | 27 | $this->result['item'] = form_to_params($form); 28 | $this->result['sig'] = get_sig(); 29 | 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_widgets_get_pages.php: -------------------------------------------------------------------------------- 1 | model->getPages(); 34 | 35 | $this->result['count'] = count($pages); 36 | $this->result['items'] = $pages; 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /package/system/controllers/api/api_actions/api_widgets_get_widgets.php: -------------------------------------------------------------------------------- 1 | array( 27 | 'default' => '', 28 | 'rules' => array( 29 | array('regexp', '/^([0-9,]+)$/i') 30 | ) 31 | ) 32 | ); 33 | 34 | private $matched_pages = 0; 35 | 36 | public function validateApiRequest() { 37 | 38 | $pages_ids = $this->request->get('pages_ids'); 39 | 40 | if($pages_ids){ 41 | 42 | $pages_ids = explode(',', $pages_ids); 43 | $pages_ids = array_filter($pages_ids); 44 | 45 | if($pages_ids){ 46 | 47 | $this->matched_pages = $pages_ids; 48 | 49 | } 50 | 51 | } 52 | 53 | return false; 54 | 55 | } 56 | 57 | public function run(){ 58 | 59 | $widgets_list = $this->model->getWidgetsForPages($this->matched_pages, $this->cms_template->getName()); 60 | 61 | if (!is_array($widgets_list)){ return; } 62 | 63 | $device_type = cmsRequest::getDeviceType(); 64 | 65 | $result_widgets = array(); 66 | 67 | foreach ($widgets_list as $widget){ 68 | 69 | // не выводим виджеты контроллеров, которые отключены 70 | if(!empty($widget['controller']) && !cmsController::enabled($widget['controller'])){ 71 | continue; 72 | } 73 | 74 | // проверяем доступ для виджетов 75 | if (!$this->cms_user->isInGroups($widget['groups_view'])) { continue; } 76 | if (!empty($widget['groups_hide']) && $this->cms_user->isInGroups($widget['groups_hide']) && !$this->cms_user->is_admin) { 77 | continue; 78 | } 79 | 80 | // проверяем для каких устройств показывать 81 | if($widget['device_types'] && !in_array($device_type, $widget['device_types'])){ 82 | continue; 83 | } 84 | 85 | $result = false; 86 | 87 | $file = 'system/'.cmsCore::getWidgetPath($widget['name'], $widget['controller']).'/widget.php'; 88 | 89 | $class = 'widget' . 90 | ($widget['controller'] ? string_to_camel('_', $widget['controller']) : '') . 91 | string_to_camel('_', $widget['name']); 92 | 93 | if (!class_exists($class, false)) { 94 | cmsCore::includeFile($file); 95 | cmsCore::loadWidgetLanguage($widget['name'], $widget['controller']); 96 | } 97 | 98 | $widget_object = new $class($widget); 99 | 100 | $cache_key = 'widgets_api'.$widget['id']; 101 | $cache = cmsCache::getInstance(); 102 | 103 | if($widget_object->isCacheable()){ 104 | $result = $cache->get($cache_key); 105 | } 106 | 107 | if ($result === false){ 108 | $result = call_user_func_array(array($widget_object, 'run'), array()); 109 | if ($result !== false){ 110 | // Отдельно кешируем имя шаблона виджета, заголовок и враппер, поскольку они могли быть 111 | // изменены внутри виджета, а в кеш у нас попадает только тот массив 112 | // который возвращается кодом виджета (без самих свойств $widget_object) 113 | $result['_wd_title'] = $widget_object->title; 114 | } 115 | if($widget_object->isCacheable()){ 116 | $cache->set($cache_key, $result); 117 | } 118 | } 119 | 120 | if ($result === false) { continue; } 121 | 122 | if (isset($result['_wd_title'])) { $widget_object->title = $result['_wd_title']; } 123 | 124 | $result_widgets[] = array( 125 | 'widget_data' => $result, 126 | 'widget' => $widget 127 | ); 128 | 129 | } 130 | 131 | $this->result['count'] = count($result_widgets); 132 | $this->result['items'] = $result_widgets; 133 | 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /package/system/controllers/api/backend.php: -------------------------------------------------------------------------------- 1 | redirectToAction('options'); 16 | } 17 | 18 | public function getBackendMenu() { 19 | 20 | return [ 21 | [ 22 | 'title' => LANG_OPTIONS, 23 | 'url' => href_to($this->root_url, 'options') 24 | ], 25 | [ 26 | 'title' => LANG_API_KEYS, 27 | 'url' => href_to($this->root_url, 'keys') 28 | ] 29 | ]; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /package/system/controllers/api/backend/actions/keys.php: -------------------------------------------------------------------------------- 1 | loadDataGrid('keys'); 15 | 16 | if ($this->request->isAjax()) { 17 | 18 | $this->model->setPerPage(30); 19 | 20 | $filter = []; 21 | $filter_str = $this->request->get('filter', ''); 22 | 23 | if ($filter_str) { 24 | parse_str($filter_str, $filter); 25 | $this->model->applyGridFilter($grid, $filter); 26 | } 27 | 28 | $total = $this->model->getCount('api_keys'); 29 | $perpage = isset($filter['perpage']) ? $filter['perpage'] : 30; 30 | $pages = ceil($total / $perpage); 31 | 32 | $data = $this->model->get('api_keys'); 33 | 34 | $this->cms_template->renderGridRowsJSON($grid, $data, $total, $pages); 35 | 36 | $this->halt(); 37 | } 38 | 39 | return $this->cms_template->render('backend/keys', [ 40 | 'grid' => $grid 41 | ]); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /package/system/controllers/api/backend/actions/keys_add.php: -------------------------------------------------------------------------------- 1 | getForm('key'); 15 | 16 | if(!isset($id)){ 17 | $key = array( 18 | 'is_pub' => 1, 19 | 'api_key' => string_random() 20 | ); 21 | } else { 22 | 23 | $key = $old_key = $this->model->getKey($id); 24 | if (!$key) { cmsCore::error404(); } 25 | 26 | } 27 | 28 | if ($this->request->has('submit')){ 29 | 30 | $key = $form->parse($this->request, true); 31 | 32 | $errors = $form->validate($this, $key); 33 | 34 | if (!$errors){ 35 | 36 | if(isset($id)){ 37 | 38 | $this->model->update('api_keys', $id, $key); 39 | 40 | if($old_key['api_key'] != $key['api_key']){ 41 | cmsUser::addSessionMessage(LANG_API_KEY_UPDATE, 'info'); 42 | } 43 | 44 | } else { 45 | $this->model->insert('api_keys', $key); 46 | } 47 | 48 | cmsUser::addSessionMessage(LANG_API_KEY_SUCCESS, 'success'); 49 | 50 | $this->redirectToAction('keys'); 51 | 52 | } 53 | 54 | if ($errors){ 55 | cmsUser::addSessionMessage(LANG_FORM_ERRORS, 'error'); 56 | } 57 | 58 | } 59 | 60 | return $this->cms_template->render('backend/key', array( 61 | 'submit_title' => (!isset($id) ? LANG_ADD : LANG_SAVE), 62 | 'title' => (!isset($id) ? LANG_ADD : LANG_EDIT).' '.mb_strtolower(LANG_API_KEY), 63 | 'key' => $key, 64 | 'form' => $form, 65 | 'errors' => isset($errors) ? $errors : false 66 | )); 67 | 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /package/system/controllers/api/backend/actions/keys_delete.php: -------------------------------------------------------------------------------- 1 | model->getKey($id); 15 | if (!$key) { cmsCore::error404(); } 16 | 17 | $this->model->deleteKey($id); 18 | 19 | cmsUser::addSessionMessage(LANG_API_KEY_DELETE, 'success'); 20 | 21 | $this->redirectToAction('keys'); 22 | 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /package/system/controllers/api/backend/actions/keys_edit.php: -------------------------------------------------------------------------------- 1 | runExternalAction('keys_add', $this->params); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /package/system/controllers/api/backend/forms/form_key.php: -------------------------------------------------------------------------------- 1 | 'fieldset', 37 | 'title' => LANG_BASIC_OPTIONS, 38 | 'childs' => array( 39 | 40 | new fieldCheckbox('is_pub', array( 41 | 'title' => LANG_API_KEY_IS_PUB 42 | )), 43 | 44 | new fieldString('api_key', array( 45 | 'title' => LANG_API_KEY_CODE, 46 | 'hint' => LANG_API_KEY_CODE_HINT, 47 | 'options'=>array( 48 | 'max_length'=> 32, 49 | 'show_symbol_count'=>true 50 | ), 51 | 'rules' => array( 52 | array('required') 53 | ) 54 | )), 55 | 56 | new fieldText('description', array( 57 | 'title' => LANG_DESCRIPTION, 58 | 'options'=>array( 59 | 'max_length'=> 100, 60 | 'show_symbol_count'=>true 61 | ) 62 | )), 63 | 64 | new fieldText('ip_access', array( 65 | 'title' => LANG_API_ALLOW_IPS, 66 | 'hint' => sprintf(LANG_CP_SETTINGS_ALLOW_IPS_HINT, cmsUser::getIp()) 67 | )), 68 | 69 | new fieldListMultiple('key_methods:allow', array( 70 | 'title' => LANG_API_ALLOW_METHODS, 71 | 'default' => 0, 72 | 'show_all' => true, 73 | 'generator' => $generator 74 | )), 75 | 76 | new fieldListMultiple('key_methods:disallow', array( 77 | 'title' => LANG_API_DISALLOW_METHODS, 78 | 'default' => 0, 79 | 'generator' => $generator 80 | )) 81 | 82 | ) 83 | ) 84 | 85 | ); 86 | 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /package/system/controllers/api/backend/forms/form_options.php: -------------------------------------------------------------------------------- 1 | 'fieldset', 18 | 'title' => LANG_BASIC_OPTIONS, 19 | 'childs' => array( 20 | 21 | new fieldCheckbox('log_error', array( 22 | 'title' => LANG_API_LOG_ERROR 23 | )), 24 | 25 | new fieldCheckbox('log_success', array( 26 | 'title' => LANG_API_LOG_SUCCESS 27 | )), 28 | 29 | new fieldCheckbox('allow_admin_login', array( 30 | 'title' => LANG_API_ALLOW_ADMIN_LOGIN 31 | )) 32 | 33 | ) 34 | ) 35 | 36 | ); 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /package/system/controllers/api/backend/grids/grid_keys.php: -------------------------------------------------------------------------------- 1 | false, 14 | 'is_filter' => false, 15 | 'is_pagination' => true, 16 | 'is_draggable' => false, 17 | 'order_by' => 'id', 18 | 'order_to' => 'desc', 19 | 'show_id' => true 20 | ); 21 | 22 | $columns = array( 23 | 'id' => array( 24 | 'title' => 'id', 25 | 'width' => 30 26 | ), 27 | 'description' => array( 28 | 'title' => LANG_DESCRIPTION, 29 | 'href' => href_to($controller->root_url, 'keys_edit', array('{id}')), 30 | 'editable' => array( 31 | 'table' => 'api_keys' 32 | ) 33 | ), 34 | 'api_key' => array( 35 | 'title' => LANG_API_KEY, 36 | 'width' => 200 37 | ), 38 | 'is_pub' => array( 39 | 'title' => LANG_ON, 40 | 'flag' => true, 41 | 'flag_toggle' => href_to($controller->root_url, 'toggle_item', array('{id}', 'api_keys', 'is_pub')), 42 | 'width' => 80 43 | ), 44 | ); 45 | 46 | $actions = array( 47 | array( 48 | 'title' => LANG_EDIT, 49 | 'class' => 'edit', 50 | 'href' => href_to($controller->root_url, 'keys_edit', array('{id}')) 51 | ), 52 | array( 53 | 'title' => LANG_DELETE, 54 | 'class' => 'delete', 55 | 'href' => href_to($controller->root_url, 'keys_delete', array('{id}')), 56 | 'confirm' => LANG_API_DELETE_CONFIRM 57 | ) 58 | ); 59 | 60 | return array( 61 | 'options' => $options, 62 | 'columns' => $columns, 63 | 'actions' => $actions 64 | ); 65 | 66 | } 67 | -------------------------------------------------------------------------------- /package/system/controllers/api/frontend.php: -------------------------------------------------------------------------------- 1 | start_time = microtime(true); 25 | 26 | parent::__construct($request); 27 | 28 | // устанавливаем ошибку по-умолчанию 29 | $this->setError(1); 30 | } 31 | 32 | public function loadApiKey() { 33 | 34 | if ($this->key !== null) { 35 | return $this; 36 | } 37 | 38 | $headers = apache_request_headers(); 39 | 40 | $api_key = !empty($headers['api_key']) ? $headers['api_key'] : $this->request->get('api_key', ''); 41 | 42 | $this->key = $this->model->getKey($api_key); 43 | 44 | return $this; 45 | } 46 | 47 | /** 48 | * Проверяет запрос на ошибки 49 | * @return boolean 50 | */ 51 | public function checkRequest() { 52 | 53 | if (empty($this->key)) { 54 | return $this->error(101); 55 | } 56 | 57 | if ($this->key['ip_access'] && !string_in_mask_list(cmsUser::getIp(), $this->key['ip_access'])) { 58 | return $this->error(15); 59 | } 60 | 61 | if (!$this->key['is_pub']) { 62 | return $this->error(2); 63 | } 64 | 65 | return true; 66 | } 67 | 68 | public function actionIndex() { 69 | return cmsCore::errorForbidden(); 70 | } 71 | 72 | /** 73 | * Универсальный метод, который позволяет запускать последовательность других методов, 74 | * сохраняя и фильтруя промежуточные результаты 75 | */ 76 | public function actionExecute() { 77 | 78 | $this->loadApiKey(); 79 | 80 | // если передан ip адрес, считаем его адресом посетителя 81 | // для различных проверок компонентов 82 | // т.к. движок определяет ip адрес места запроса 83 | if ($this->request->has('ip')) { 84 | 85 | $ip = $this->request->get('ip', ''); 86 | 87 | if (!$ip || filter_var($ip, FILTER_VALIDATE_IP) !== $ip) { 88 | return $this->error(777); 89 | } 90 | 91 | // совместимость 92 | if (method_exists('cmsUser', 'setIp')) { 93 | cmsUser::setIp($ip); 94 | } 95 | } 96 | 97 | if (!$this->checkRequest()) { 98 | return false; 99 | } 100 | 101 | $code = $this->request->get('code', ''); 102 | if (!$code) { 103 | return $this->error(100); 104 | } 105 | 106 | $methods = json_decode($code, true); 107 | if (json_last_error() !== JSON_ERROR_NONE || !$methods) { 108 | return $this->error(12); 109 | } 110 | 111 | $response = []; 112 | $max_method_count = 10; 113 | 114 | if (count($methods) > $max_method_count) { 115 | return $this->error(13); 116 | } 117 | 118 | foreach ($methods as $method_param) { 119 | 120 | if (empty($method_param['method'])) { 121 | return $this->error(13); 122 | } 123 | 124 | $this->request->setData(!empty($method_param['params']) ? $method_param['params'] : []); 125 | 126 | $method_result = $this->runExternalAction('method', [$method_param['method']]); 127 | 128 | if (!$method_result) { 129 | return $this->error(13); 130 | } 131 | 132 | $response[!empty($method_param['key']) ? $method_param['key'] : $method_param['method']] = $this->output_success['response']; 133 | } 134 | 135 | $this->setSuccess($response); 136 | 137 | } 138 | 139 | /** 140 | * Дополняем метод окончания вызова экшена 141 | * @param string $action_name 142 | * @return boolean 143 | */ 144 | public function after($action_name) { 145 | 146 | parent::after($action_name); 147 | 148 | if (!$this->cms_user->is_logged && $this->output_success) { 149 | 150 | $this->output_success['session'] = [ 151 | 'session_name' => session_name(), 152 | 'session_id' => session_id() 153 | ]; 154 | } 155 | 156 | $this->renderJSON(); 157 | 158 | return true; 159 | } 160 | 161 | /** 162 | * Результат запроса 163 | * @param array $api_request_result 164 | */ 165 | public function setSuccess($api_request_result) { 166 | 167 | $success = [ 168 | 'response' => $api_request_result 169 | ]; 170 | 171 | if ($this->cms_config->debug && cmsUser::isAdmin()) { 172 | 173 | $success['debug'] = [ 174 | 'time' => cmsDebugging::getTime('cms', 4), 175 | 'mem' => round(memory_get_usage(true) / 1024 / 1024, 2), 176 | 'data' => cmsDebugging::getPointsData() 177 | ]; 178 | } 179 | 180 | $this->output_success = $success; 181 | 182 | } 183 | 184 | /** 185 | * Устанавливает ошибку запроса 186 | * @param integer $error_code 187 | * @param string $error_msg 188 | * @param array $request_params 189 | */ 190 | public function setError($error_code, $error_msg = '', $request_params = []) { 191 | 192 | if ($error_msg) { 193 | 194 | $this->output_error['error'] = [ 195 | 'error_code' => ($error_code ? $error_code : 0), 196 | 'error_msg' => $error_msg, 197 | 'request_params' => $request_params 198 | ]; 199 | 200 | } else { 201 | 202 | $this->output_error['error'] = [ 203 | 'error_code' => $error_code, 204 | 'error_msg' => constant('LANG_API_ERROR' . $error_code), 205 | 'request_params' => $request_params 206 | ]; 207 | } 208 | 209 | // если уже есть результат, очищаем его 210 | $this->output_success = []; 211 | 212 | return $this; 213 | } 214 | 215 | /** 216 | * Фиксирует ошибку запроса 217 | * @param integer $error_code 218 | * @param string $error_msg 219 | * @param array $request_params 220 | */ 221 | public function error($error_code, $error_msg = '', $request_params = []) { 222 | 223 | // записываем в лог ошибку, если включена их фиксация 224 | if (!empty($this->options['log_error'])) { 225 | 226 | $this->model->log([ 227 | 'request_time' => number_format((microtime(true) - $this->start_time), 4), 228 | 'error' => $error_code, 229 | 'method' => $this->method_name, 230 | 'key_id' => (!empty($this->key['id']) ? $this->key['id'] : null) 231 | ]); 232 | } 233 | 234 | $this->setError($error_code, $error_msg, $request_params); 235 | 236 | return false; 237 | } 238 | 239 | /** 240 | * Возвращает результирующий массив: либо массив ошибки, либо успешный результат работы 241 | * @return array 242 | */ 243 | public function getOutputdata() { 244 | return ($this->output_success ? $this->output_success : $this->output_error); 245 | } 246 | 247 | public function renderJSON() { 248 | return $this->cms_template->renderJSON($this->getOutputdata(), true); 249 | } 250 | 251 | } 252 | 253 | // apache_request_headers replicement for nginx 254 | if (!function_exists('apache_request_headers')) { 255 | 256 | function apache_request_headers() { 257 | foreach ($_SERVER as $key => $value) { 258 | if (substr($key, 0, 5) == 'HTTP_') { 259 | $key = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($key, 5))))); 260 | $out[$key] = $value; 261 | } else { 262 | $out[$key] = $value; 263 | } 264 | } 265 | return $out; 266 | 267 | } 268 | } 269 | 270 | function api_image_src($images, $size_preset = false) { 271 | 272 | $config = cmsConfig::getInstance(); 273 | 274 | if (!is_array($images)) { 275 | $images = cmsModel::yamlToArray($images); 276 | } 277 | 278 | if (!$images) { 279 | return null; 280 | } 281 | 282 | $result = array(); 283 | 284 | $keys = array_keys($images); 285 | // значит массив изображений 286 | if ($keys[0] === 0) { 287 | foreach ($images as $image) { 288 | $result[] = api_image_src($image); 289 | } 290 | } else { 291 | foreach ($images as $preset => $path) { 292 | $result[$preset] = $config->upload_host_abs . '/' . $path; 293 | } 294 | } 295 | 296 | return $result; 297 | } 298 | 299 | function form_to_params($form) { 300 | 301 | $params = array('csrf_token' => array( 302 | 'title' => 'csrf_token', 303 | 'fields' => array( 304 | array( 305 | 'title' => null, 306 | 'data' => array( 307 | 'type' => 'hidden' 308 | ), 309 | 'type' => 'string', 310 | 'name' => 'csrf_token', 311 | 'rules' => array( 312 | array('required') 313 | ), 314 | 'var_type' => 'string', 315 | 'items' => null, 316 | 'placeholder' => null, 317 | 'default' => cmsForm::getCSRFToken() 318 | ) 319 | ) 320 | )); 321 | 322 | $structure = $form->getStructure(); 323 | 324 | foreach ($structure as $key => $fieldset) { 325 | 326 | if (empty($fieldset['childs'])) { 327 | continue; 328 | } 329 | 330 | $param = array( 331 | 'title' => (!empty($fieldset['title']) ? $fieldset['title'] : null), 332 | 'hint' => (!empty($fieldset['hint']) ? $fieldset['hint'] : null), 333 | 'fields' => array() 334 | ); 335 | 336 | foreach ($fieldset['childs'] as $field) { 337 | 338 | $param['fields'][$field->getName()] = array( 339 | 'title' => $field->title, 340 | 'field_type' => isset($field->field_type) ? $field->field_type : $field->class, // совместимость 341 | 'type' => (!empty($field->type) ? $field->type : null), 342 | 'name' => $field->getName(), 343 | 'rules' => $field->getRules(), 344 | 'var_type' => $field->var_type, 345 | 'items' => (method_exists($field, 'getListItems') ? $field->getListItems() : null), 346 | 'options' => (!empty($field->options) ? $field->options : null), 347 | 'attributes' => (!empty($field->attributes) ? $field->attributes : null), 348 | 'hint' => (!empty($field->hint) ? $field->hint : null), 349 | 'units' => (!empty($field->units) ? $field->units : null), 350 | 'default' => (isset($field->default) ? $field->default : null) 351 | ); 352 | } 353 | 354 | $params[$key] = $param; 355 | } 356 | 357 | return $params; 358 | } 359 | 360 | function get_sig() { 361 | $ip = cmsUser::getIp(); 362 | return md5($ip . md5(md5(cmsConfig::get('host')) . md5(cmsConfig::get('db_base')) . sprintf('%u', ip2long($ip)))); 363 | } 364 | 365 | function check_sig($sig) { 366 | return $sig === get_sig(); 367 | } 368 | -------------------------------------------------------------------------------- /package/system/controllers/api/hooks/admin_dashboard_chart.php: -------------------------------------------------------------------------------- 1 | [ 16 | 'title' => LANG_API_STAT_OK, 17 | 'table' => 'api_logs', 18 | 'filter' => array( 19 | array( 20 | 'condition' => 'ni', 21 | 'value' => '', 22 | 'field' => 'error' 23 | ) 24 | ), 25 | 'key' => 'date_pub' 26 | ] 27 | ]; 28 | 29 | $errors_methods = $this->model-> 30 | selectOnly('method')-> 31 | filterNotNull('error')-> 32 | groupBy('method')-> 33 | get('api_logs', function($i, $model){ 34 | return $i['method']; 35 | }, false); 36 | 37 | if($errors_methods){ 38 | 39 | $sections['errors_log'] = [ 40 | 'title' => LANG_API_STAT_ERRORS, 41 | 'hint' => LANG_API_STAT_ERRORS_HINT, 42 | 'table' => 'api_logs', 43 | 'style' => [ 44 | 'bg_color' => 'rgba(248, 108, 107, 0.1)', 45 | 'border_color' => 'rgba(248, 108, 107, 1)' 46 | ], 47 | 'filter' => array( 48 | array( 49 | 'condition' => 'nn', 50 | 'value' => '', 51 | 'field' => 'error' 52 | ) 53 | ), 54 | 'key' => 'date_pub' 55 | ]; 56 | 57 | foreach ($errors_methods as $errors_method) { 58 | 59 | $hint = (!$errors_method ? LANG_API_STAT_ERRORS_HINT1 : $errors_method); 60 | 61 | $sections['errors_log:'.str_replace('.', '_', $errors_method)] = [ 62 | 'hint' => $hint, 63 | 'table' => 'api_logs', 64 | 'filter' => array( 65 | array( 66 | 'condition' => (!$errors_method ? 'ni' : 'eq'), 67 | 'value' => (!$errors_method ? '' : $errors_method), 68 | 'field' => 'method' 69 | ), 70 | array( 71 | 'condition' => 'nn', 72 | 'value' => '', 73 | 'field' => 'error' 74 | ) 75 | ), 76 | 'style' => $this->getStyles($hint), 77 | 'key' => 'date_pub' 78 | ]; 79 | } 80 | } 81 | 82 | return array( 83 | 'id' => 'api', 84 | 'title' => LANG_API_CONTROLLER, 85 | 'sections' => $sections 86 | ); 87 | } 88 | 89 | private function getStyles($title) { 90 | 91 | $bg_color = substr(dechex(crc32($title)), 0, 6); 92 | 93 | $r = hexdec( substr($bg_color, 0, 2) ); 94 | $g = hexdec( substr($bg_color, 2, 2) ); 95 | $b = hexdec( substr($bg_color, 4, 2) ); 96 | 97 | return [ 98 | 'bg_color' => "rgba({$r}, {$g}, {$b}, 0.1)", 99 | 'border_color' => "rgba({$r}, {$g}, {$b}, 1)" 100 | ]; 101 | 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /package/system/controllers/api/model.php: -------------------------------------------------------------------------------- 1 | filterEqual($field, $id)->getItem('api_keys'); 21 | 22 | if ($key) { 23 | $key['key_methods'] = cmsModel::yamlToArray($key['key_methods']); 24 | } 25 | 26 | return $key; 27 | } 28 | 29 | public function deleteKey($id) { 30 | 31 | $this->delete('api_keys', $id); 32 | $this->delete('api_logs', $id, 'key_id'); 33 | 34 | return true; 35 | } 36 | 37 | public function log($data) { 38 | 39 | $this->insert('api_logs', $data); 40 | 41 | return false; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /package/system/languages/en/controllers/api/api.php: -------------------------------------------------------------------------------- 1 | addBreadcrumb(LANG_API_KEYS, $this->href_to('keys')); 4 | 5 | $this->addBreadcrumb($title); 6 | 7 | $this->addToolButton(array( 8 | 'class' => 'save', 9 | 'title' => LANG_SAVE, 10 | 'href' => "javascript:icms.forms.submit()" 11 | )); 12 | $this->addToolButton(array( 13 | 'class' => 'cancel', 14 | 'title' => LANG_CANCEL, 15 | 'href' => $this->href_to('keys') 16 | )); 17 | 18 | $this->renderForm($form, $key, array( 19 | 'action' => '', 20 | 'submit' => array('title'=>$submit_title), 21 | 'method' => 'post' 22 | ), $errors); 23 | -------------------------------------------------------------------------------- /package/templates/default/controllers/api/backend/keys.tpl.php: -------------------------------------------------------------------------------- 1 | addBreadcrumb(LANG_API_KEYS); 3 | $this->setPageTitle(LANG_API_KEYS); 4 | 5 | $this->addToolButton(array( 6 | 'class' => 'add', 7 | 'title' => LANG_ADD, 8 | 'href' => $this->href_to('keys_add') 9 | )); 10 | 11 | $this->addToolButton(array( 12 | 'class' => 'help', 13 | 'title' => LANG_HELP, 14 | 'target' => '_blank', 15 | 'href' => LANG_HELP_URL_COM_API 16 | )); 17 | 18 | $this->renderGrid($this->href_to('keys'), $grid); ?> 19 | 20 | 33 | --------------------------------------------------------------------------------