/** * Check by triggering error if process * * Validation callback. * * @param Validation $validation Object for validation * @param string $field Field name * @return void * * @uses Module::event */ public function process_alias(Validation $validation, $field) { // always set unique alias if its set $alias = $this->_unique_slug(trim($this->alias)); // make sure only one alias exists for home page <front> if ($this->alias === Path::FRONT_ALIAS) { $alias = Path::FRONT_ALIAS; } $this->type = empty($this->type) ? NULL : $this->type; // allow other modules to interact with alias Module::event('path_aliases', $this); $source = trim($this->source, '/'); $this->lang = empty($this->lang) ? $this->_language_none : $this->lang; if ($params = $this->_process_uri($source)) { if (isset($params['directory'])) { $this->route_directory = $params['directory']; } if (isset($params['controller'])) { $this->route_controller = $params['controller']; } if (isset($params['action'])) { $this->route_action = $params['action']; } if (isset($params['id'])) { $this->route_id = $params['id']; } if (isset($params['route'])) { $this->route_name = $params['route']; } $this->alias = $alias; } elseif (!isset($params['controller']) or !isset($params) or empty($params['controller']) or empty($params)) { $validation->error($field, 'invalid_source', array($validation[$field])); } }
/** * Delete all objects in the associated table * * This does NOT destroy relationships that have been created with other objects. * * @return ORM * @uses Module::event * @throws Gleez_Exception */ public function delete_all() { if ($this->_loaded) { throw new Gleez_Exception('Cannot delete all :model model because it is loaded.', array(':model' => $this->_object_name)); } Module::event($this->_object_name . '_pre_delete_all', $this); $this->_build(ORM::DELETE); $this->_db_builder->execute($this->_db); Module::event($this->_object_name . '_delete_all', $this); return $this->clear(); }
/** * Make sure the user has permission to do the action on this object * * Similar to [Comment::access] but this return TRUE/FALSE instead of exception * * @param string $action The action `view|edit|delete` default `view` * @param ORM $comment The comment object * @param Model_User $user The user object to check permission, defaults to loaded in user * @param string $misc The misc element usually `id|slug` for logging purpose * * @return boolean * * @throws HTTP_Exception_404 * * @uses User::active_user * @uses Module::event */ public static function comment($action = 'view', ORM $comment, Model_User $user = NULL, $misc = NULL) { if (!in_array($action, array('view', 'edit', 'delete', 'add', 'list'), TRUE)) { // If the $action was not one of the supported ones, we return access denied. Log::notice('Unauthorized attempt to access non-existent action :act.', array(':act' => $action)); return FALSE; } if (!$comment->loaded()) { // If the $action was not one of the supported ones, we return access denied. throw HTTP_Exception::factory(404, 'Attempt to access non-existent comment.'); } // If no user object is supplied, the access check is for the current user. if (is_null($user)) { $user = User::active_user(); } if (self::check('bypass comment access', $user)) { return TRUE; } // Allow other modules to interact with access Module::event('comment_access', $action, $comment); if ($action === 'view') { if ($comment->status === 'publish' and self::check('access comment', $user)) { return TRUE; } elseif ($comment->status != 'publish' and $comment->author == (int) $user->id and $user->id != 1) { return TRUE; } elseif (self::check('administer comment', $user)) { return TRUE; } else { return FALSE; } } if ($action === 'edit') { if (self::check('edit own comment') and $comment->author == (int) $user->id and $user->id != 1) { return TRUE; } elseif (self::check('administer comment', $user)) { return TRUE; } else { return FALSE; } } if ($action === 'delete') { if ((self::check('delete own comment') or self::check('delete any comment')) and $comment->author == (int) $user->id and $user->id != 1) { return TRUE; } elseif (self::check('administer comment', $user)) { return TRUE; } else { return FALSE; } } return TRUE; }
/** * Static method to return menu object based on its unique name * * @param string $name The name of the menu * @return object Menu */ public static function items($name) { $cache = Cache::instance('menus'); if (!($items = $cache->get($name))) { $_menu = ORM::factory('menu')->where('name', '=', (string) $name)->find()->as_array(); if (!$_menu) { return; } $ritems = ORM::factory('menu')->where('lft', '>', $_menu['lft'])->where('rgt', '<', $_menu['rgt'])->where('scp', '=', $_menu['scp'])->where('active', '=', 1)->order_by('lft', 'ASC')->find_all(); $items = array(); foreach ($ritems as $item) { $items[] = $item->as_array(); } if (empty($items)) { return; } // set the cache for performance in production if (Kohana::$environment === Kohana::PRODUCTION) { $cache->set($name, $items, DATE::DAY); } } //Initiate Menu Object $menu = static::factory(); // start with an empty $right stack $stack = array(); foreach ($items as &$item) { // check if we should remove a node from the stack while (count($stack) > 0 and $stack[count($stack) - 1]['rgt'] < $item['rgt']) { array_pop($stack); } if (count($stack) > 0) { $menu->add($item['name'], $item['title'], $item['url'], $item['descp'], $item['params'], $item['image'], $stack[count($stack) - 1]['name']); } else { $menu->add($item['name'], $item['title'], $item['url'], $item['descp'], $item['params'], $item['image']); } $stack[] =& $item; } // unset the stack array to freeup memory unset($stack); // Enable developers to override menu Module::event('menus_items', $menu); Module::event("menus_items_{$name}", $menu); return $menu; }
/** * Run all the enabled filters on a piece of text. * * Note: Because filters can inject JavaScript or execute PHP code, security is * vital here. When a user supplies a text format, you should validate it using * filter_access() before accepting/using it. This is normally done in the * validation stage of the Form API. You should for example never make a preview * of content in a disallowed format. * * @param string $text The text to be filtered * @param integer $format_id The format id of the text to be filtered. If no format is assigned, the fallback format will be used [Optional] * @param string $langcode The language code of the text to be filtered, e.g. 'en' for English. This allows filters to be language aware so language specific text replacement can be implemented [Optional] * @param boolean $cache Boolean whether to cache the filtered output in the {cache_filter} table. The caller may set this to FALSE when the output is already cached elsewhere to avoid duplicate cache lookups and storage [Optional] * * @return mixed * * @uses Config::load * @uses Config_Group::get * @uses Cache::get * @uses Cache::set * @uses Module::event * @uses Filter::process * * @todo Make @params description shorter */ public static function markup($text, $format_id = NULL, $langcode = NULL, $cache = FALSE) { // Save some cpu cycles if text is empty or null if (empty($text)) { return $text; } $format_id = is_null($format_id) ? Config::get('inputfilter.default_format', 1) : $format_id; $langcode = is_null($langcode) ? I18n::$lang : $langcode; // Check for a cached version of this piece of text. $cache_id = $format_id . ':' . $langcode . ':' . hash('sha256', $text); if ($cache and $cached = Cache::instance('cache_filter')->get($cache_id)) { return $cached; } // Convert all Windows and Mac newlines to a single newline, so filters // only need to deal with one possibility. $text = str_replace(array("\r\n", "\r"), "\n", $text); $textObj = new ArrayObject(array('text' => (string) $text, 'format' => (int) $format_id, 'langcode' => (string) $langcode, 'cache' => (bool) $cache, 'cache_id' => (string) $cache_id), ArrayObject::ARRAY_AS_PROPS); Module::event('inputfilter', $textObj); $text = is_string($textObj->text) ? $textObj->text : $text; $text = Filter::process($textObj); // run all filters // Store in cache with a minimum expiration time of 1 day. if ($cache) { Cache::instance('cache_filter')->set($cache_id, $text, null, time() + Date::DAY); } return $text; }
/** * If debugging is enabled, append profiler stats for non-production environments. * * @return void */ public function after() { if ($this->auto_render && $this->bare == FALSE) { // Controller name as the default page id if none set empty($this->_page_id) and $this->_page_id = $this->request->controller(); // Load left and right sidebars if available $this->_set_sidebars(); // Set appropriate column css class $this->_set_column_class(); // Do some CSS magic to page class $classes = array(I18n::$lang, $this->request->controller(), $this->request->action(), $this->request->controller() . '-' . $this->request->action(), $this->template->column_class, $this->_page_class, $this->_auth->logged_in() ? 'logged-in' : 'not-logged-in'); // Special check for frontpage and frontpage title if ($this->is_frontpage()) { // Set front variable true for themers $this->template->front = TRUE; // Don't show title on homepage $this->template->title = FALSE; // Don't show title on homepage $this->title = FALSE; $this->template->mission = __($this->_config->get('site_mission', '')); } View::set_global(array('is_front' => $this->template->front, 'is_admin' => $this->template->_admin)); $classes[] = $this->template->_admin ? 'backend' : 'frontend'; $classes[] = $this->template->front ? 'front' : 'not-front'; $page_class = implode(' ', array_unique(array_map('trim', $classes))); // Construct Head Section Page title $this->_set_head_title(); // Allow module and theme developers to override Module::event('template', $this); // Set primary menu $primary_menu = Menu::links('main-menu', array('class' => 'menus nav navbar-nav')); // Bind the generic page variables $this->template->set('lang', I18n::$lang)->set('page_id', $this->_page_id)->set('page_class', $page_class)->set('primary_menu', $primary_menu)->set('title', $this->title)->set('subtitle', $this->subtitle)->set('icon', $this->icon)->set('schemaType', $this->schemaType)->set('mission', $this->template->mission)->set('content', $this->response->body())->set('messages', Message::display())->set('profiler', FALSE); if (count($this->_tabs) > 0) { $this->template->tabs = View::factory('tabs')->set('tabs', $this->_tabs); } if (count($this->_subtabs) > 0) { $this->template->subtabs = View::factory('tabs')->set('tabs', $this->_subtabs); } if (count($this->_actions) > 0) { $this->template->actions = View::factory('actions')->set('actions', $this->_actions); } // And profiler if debug is true if (Kohana::$environment !== Kohana::PRODUCTION and $this->debug) { $this->template->profiler = View::factory('profiler/stats'); } // And finally the profiler stats $this->_set_profiler_stats(); // Assign the template as the request response and render it $this->response->body($this->template); } elseif ($this->_ajax && $this->bare == FALSE) { $output = $this->response->body(); $this->process_ajax(); if ($this->_response_format === 'application/json') { // Check for dataTables request if ($this->request->query('draw') !== NULL) { return; } $output = $this->_json['Data']; } $this->response->body($output); } elseif ($this->_internal && $this->bare == FALSE) { $output = $this->response->body(); $this->response->body($output); } if ($this->bare == FALSE) { if (isset($this->_benchmark)) { // Stop the benchmark Profiler::stop($this->_benchmark); } // Set header content-type to response format with utf-8 $this->response->headers('Content-Type', $this->_response_format . '; charset=' . Kohana::$charset); } parent::after(); }
/** * Validates login information from an array, and optionally redirects * after a successful login. * * @param array $array Values to check * @param boolean|string $redirect URI or URL to redirect to * * @throws Validation_Exception * * @return Model_User * * @uses Log::error * @uses Module::event * @uses Request::initial * @uses Request::redirect */ public function login(array $array, $redirect = FALSE) { $labels = $this->labels(); $rules = $this->rules(); $array = Validation::factory($array); // important to check isset to avoid unnecessary routing if (isset($array['name'])) { $login_name = $this->unique_key($array['name']); // be sure remove the name/email_available rule during login if (isset($rules[$login_name][4])) { unset($rules[$login_name][4]); } $array->rules('name', $rules[$login_name]); $array->label('name', $labels[$login_name]); $array->label('password', $labels['pass']); $array->rules('password', $rules['pass']); } // Get the remember login option $remember = isset($array['remember']); Module::event('user_login_validate', $array); if ($array->check()) { // Attempt to load the user $this->where($login_name, '=', $array['name'])->find(); if ($this->loaded() and $this->status != 1) { $array->error('name', 'blocked'); Module::event('user_blocked', $array); Log::error('User: :name account blocked.', array(':name' => $array['name'])); throw new Validation_Exception($array, 'Account Blocked'); } elseif ($this->loaded() and Auth::instance()->login($this, $array['password'], $remember)) { // Redirect after a successful login if (is_string($redirect)) { Request::initial()->redirect($redirect); } return $this; } else { $array->error('name', 'invalid'); Module::event('user_auth_failed', $array); Log::error('User: :name failed login.', array(':name' => $array['name'])); throw new Validation_Exception($array, 'Validation has failed for login'); } } else { Log::error('User Login error.'); throw new Validation_Exception($array, 'Validation has failed for login'); } }
/** * Make sure the user has permission to do the action on this object * * Similar to Comment::access but this return True/False instead of exception * * @param bool|string $action The action view|edit|delete default view * @param Model_User $user The user object to check permission, defaults to logged in user * @param string $misc The misc element usually id|slug for logging purpose * * @throws HTTP_Exception_404 * * @return boolean|Model_Comment * * @uses Log::add * @uses User::active_user * @uses ACL::check * @uses Module::event */ public function user_can($action = FALSE, Model_User $user = NULL, $misc = NULL) { if (!$action) { $action = 'view'; } if (!in_array($action, array('view', 'edit', 'delete', 'add', 'list'), TRUE)) { // If the $action was not one of the supported ones, we return access denied. Log::notice('Unauthorised attempt to access non-existent action :act.', array(':act' => $action)); return FALSE; } if (!$this->loaded()) { // If the $action was not one of the supported ones, we return access denied. throw HTTP_Exception::factory(404, 'Attempt to access non-existent comment.'); } // If no user object is supplied, the access check is for the current user. if (empty($user)) { $user = User::active_user(); } if (ACL::check('bypass comment access', $user)) { return TRUE; } //allow other modules to interact with access Module::event('comment_access', $action, $this); // can view? if ($action === 'view') { if ($this->status === 'publish' and ACL::check('access comment', $user)) { return $this; } elseif ($this->status != 'publish' and $this->author == (int) $user->id and $user->id != 1) { return $this; } elseif (ACL::check('administer comment', $user)) { return $this; } else { Log::notice('Unauthorised attempt to view comment :post.', array(':post' => $this->id)); return FALSE; } } // can edit? if ($action === 'edit') { if (ACL::check('edit own comment') and $this->author == (int) $user->id and $user->id != 1) { return $this; } elseif (ACL::check('administer comment', $user)) { return $this; } else { Log::notice('Unauthorised attempt to edit comment :post.', array(':post' => $this->id)); return FALSE; } } // can delete? if ($action === 'delete') { if ((ACL::check('delete own comment') or ACL::check('delete any comment')) and $this->author == (int) $user->id and $user->id != 1) { return $this; } elseif (ACL::check('administer comment', $user)) { return $this; } else { Log::notice('Unauthorised attempt to delete comment :post.', array(':post' => $this->id)); return FALSE; } } return TRUE; }
/** * Returns the named widget * * @param string $name Name of the widget * @param boolean $visible Visibility permission from widget or FALSE to skip * @param boolean $region The name of the region ex:left, right or FALSE for all regions * @param boolean $format The format of the output ex:xhtml, html or FALSE for object * * @return object Widget widget * @return string HTML widget */ public function get_widget($name, $visible = FALSE, $region = FALSE, $format = FALSE) { $response = FALSE; if (!($widget = $this->get($name))) { return $response; } $visible == TRUE ? $this->is_visible($widget) : $widget->visible == TRUE; // Enable developers to override widget Module::event('Widget', $widget); Module::event('Widget_' . ucfirst($name), $widget); if ($widget->status and $widget->visible) { try { $widget->content = Widget::factory($name, $widget, $widget->config)->render(); $response = $format === FALSE ? $widget : trim($this->_html($widget, $this->_region, $this->_format)); } catch (Exception $e) { Log::error('Error processing widget ":name": :msg', array(':name' => $name, ':msg' => $e->getMessage())); } } return $response; }
/** * Do save * * @uses Arr::get * @uses Module::available * @uses Module::is_active * @uses Module::deactivate * @uses Module::is_installed * @uses Module::upgrade * @uses Module::install * @uses Module::activate * @uses Module::event * @uses Cache::delete_all * @uses Log::add * @uses Gleez_Exception::text */ private function _do_save() { $changes = new stdClass(); $changes->activate = array(); $changes->deactivate = array(); $activated_names = array(); $deactivated_names = array(); foreach (Module::available() as $module_name => $info) { if ($info->locked) { continue; } try { $desired = Arr::get($_POST, $module_name) == 1; if ($info->active and !$desired and Module::is_active($module_name)) { Module::deactivate($module_name); $changes->deactivate[] = $module_name; $deactivated_names[] = __($info->name); } elseif (!$info->active and $desired and !Module::is_active($module_name)) { if (Module::is_installed($module_name)) { Module::upgrade($module_name); } else { Module::install($module_name); } Module::activate($module_name); $changes->activate[] = $module_name; $activated_names[] = __($info->name); } } catch (Exception $e) { Log::error(Gleez_Exception::text($e)); } } Module::event('module_change', $changes); // @todo This type of collation is questionable from an i18n perspective if ($activated_names) { Message::success(__('Activated: %names', array('%names' => join(", ", $activated_names)))); } if ($deactivated_names) { Message::success(__('Deactivated: %names', array('%names' => join(", ", $deactivated_names)))); } // Clear any cache for sure Cache::instance()->delete_all(); }
/** * Delete all objects in the associated table * * This does NOT destroy relationships that have been created with other objects. * * @param boolean $soft Make delete as soft or hard. Default hard * @return ORM * @uses Module::event * @throws Gleez_Exception */ public function delete_all($soft = FALSE) { if ($this->_loaded) { throw new Gleez_Exception('Cannot delete all :model model because it is loaded.', array(':model' => $this->_object_name)); } Module::event($this->_object_name . '_pre_delete_all', $this, $soft); if (is_array($this->_deleted_column) && $soft == TRUE) { } else { $this->_build(ORM::DELETE); $this->_db_builder->execute($this->_db); } Module::event($this->_object_name . '_delete_all', $this, $soft); return $this->clear(); }
/** * Process actions */ public function action_process() { $route = Route::get('admin/comment')->uri(array('action' => 'list')); $redirect = empty($this->redirect) ? $route : $this->redirect; $post = $this->request->post(); // If deletion is not desired, redirect to list if (isset($post['no']) and $this->valid_post()) { $this->request->redirect($redirect); } // If deletion is confirmed if (isset($post['yes']) and $this->valid_post()) { $comments = array_filter($post['items']); ORM::factory('comment')->where('id', 'IN', $comments)->delete_all(); Module::event('comment_bulk_delete', $comments); Message::success(__('The delete has been performed!')); $this->request->redirect($redirect); } if ($this->valid_post('comment-bulk-actions')) { if (!isset($post['comments']) or (!is_array($post['comments']) or !count(array_filter($post['comments'])))) { $this->_errors = array(__('No items selected.')); $this->request->redirect($redirect); } try { if ($post['operation'] == 'delete') { // Filter out unchecked comments $comments = array_filter($post['comments']); $this->title = __('Delete Comments'); $items = DB::select('id', 'title')->from('comments')->where('id', 'IN', $comments)->execute()->as_array('id', 'title'); $view = View::factory('form/confirm_multi')->set('action', '')->set('items', $items); $this->response->body($view); return; } $this->_bulk_update($post); Message::success(__('The update has been performed!')); $this->request->redirect($redirect); } catch (Exception $e) { Message::error(__('The update has not been performed!')); } } }