From f987b1238fc7c3dda897cab17fc5189e013389c2 Mon Sep 17 00:00:00 2001 From: oldskool Date: Mon, 25 Feb 2013 21:37:21 +0100 Subject: [PATCH] Initial commit --- CHANGELOG | 136 +++ Config/Schema/empty | 0 Config/bootstrap.php | 84 ++ Controller/AclAppController.php | 204 +++++ Controller/AclController.php | 24 + Controller/AcosController.php | 120 +++ Controller/ArosController.php | 819 ++++++++++++++++++ Controller/Component/AclManagerComponent.php | 773 +++++++++++++++++ .../Component/AclReflectorComponent.php | 280 ++++++ Controller/Component/empty | 0 Lib/AclRouter.php | 31 + Locale/acl.pot | 375 ++++++++ Locale/eng/LC_MESSAGES/empty | 0 Locale/fre/LC_MESSAGES/acl.po | 518 +++++++++++ Locale/pt_BR/LC_MESSAGES/acl.po | 208 +++++ README | 51 ++ View/Acos/admin_build_acl.ctp | 61 ++ View/Acos/admin_empty_acos.ctp | 35 + View/Acos/admin_has_updates.ctp | 42 + View/Acos/admin_index.ctp | 11 + View/Acos/admin_prune_acos.ctp | 61 ++ View/Acos/admin_synchronize.ctp | 97 +++ View/Aros/admin_ajax_role_permissions.ctp | 205 +++++ View/Aros/admin_ajax_user_permissions.ctp | 168 ++++ View/Aros/admin_check.ctp | 56 ++ View/Aros/admin_index.ctp | 11 + View/Aros/admin_not_acl_requester.ctp | 39 + View/Aros/admin_role_permissions.ctp | 232 +++++ View/Aros/admin_user_permissions.ctp | 258 ++++++ View/Aros/admin_users.ctp | 89 ++ View/Aros/ajax_role_denied.ctp | 15 + View/Aros/ajax_role_granted.ctp | 15 + View/Aros/ajax_user_denied.ctp | 27 + View/Aros/ajax_user_granted.ctp | 27 + View/Elements/Acos/links.ctp | 14 + View/Elements/Aros/links.ctp | 21 + View/Elements/design/footer.ctp | 7 + View/Elements/design/header.ctp | 24 + View/Elements/flash_error.ctp | 13 + View/Elements/flash_message.ctp | 3 + View/Errors/missing_aco_nodes.ctp | 10 + View/Helper/AclHtmlHelper.php | 27 + webroot/css/acl.css | 142 +++ webroot/empty | 0 webroot/img/ajax/waiting16.gif | Bin 0 -> 1849 bytes webroot/img/ajax/waiting24.gif | Bin 0 -> 2305 bytes webroot/img/design/add.png | Bin 0 -> 3211 bytes webroot/img/design/alert_medium.gif | Bin 0 -> 1717 bytes webroot/img/design/alert_small.gif | Bin 0 -> 121 bytes webroot/img/design/bulb16.png | Bin 0 -> 723 bytes webroot/img/design/bulb24.png | Bin 0 -> 977 bytes webroot/img/design/clean.png | Bin 0 -> 773 bytes webroot/img/design/cross.png | Bin 0 -> 655 bytes webroot/img/design/cross2.png | Bin 0 -> 544 bytes webroot/img/design/gradient_bg.gif | Bin 0 -> 1371 bytes webroot/img/design/important16.png | Bin 0 -> 717 bytes webroot/img/design/lock.png | Bin 0 -> 1583 bytes webroot/img/design/question.gif | Bin 0 -> 1210 bytes webroot/img/design/question.png | Bin 0 -> 1580 bytes webroot/img/design/success_medium.gif | Bin 0 -> 1662 bytes webroot/img/design/success_small.gif | Bin 0 -> 1024 bytes webroot/img/design/sync.png | Bin 0 -> 752 bytes webroot/img/design/tick.png | Bin 0 -> 537 bytes webroot/img/design/tick_disabled.png | Bin 0 -> 1154 bytes webroot/img/design/warning_medium.gif | Bin 0 -> 1202 bytes webroot/img/design/warning_small.png | Bin 0 -> 789 bytes webroot/js/acl_plugin.js | 216 +++++ webroot/js/jquery.js | 4 + 68 files changed, 5553 insertions(+) create mode 100644 CHANGELOG create mode 100644 Config/Schema/empty create mode 100644 Config/bootstrap.php create mode 100644 Controller/AclAppController.php create mode 100644 Controller/AclController.php create mode 100644 Controller/AcosController.php create mode 100644 Controller/ArosController.php create mode 100644 Controller/Component/AclManagerComponent.php create mode 100644 Controller/Component/AclReflectorComponent.php create mode 100644 Controller/Component/empty create mode 100644 Lib/AclRouter.php create mode 100644 Locale/acl.pot create mode 100644 Locale/eng/LC_MESSAGES/empty create mode 100644 Locale/fre/LC_MESSAGES/acl.po create mode 100644 Locale/pt_BR/LC_MESSAGES/acl.po create mode 100644 README create mode 100644 View/Acos/admin_build_acl.ctp create mode 100644 View/Acos/admin_empty_acos.ctp create mode 100644 View/Acos/admin_has_updates.ctp create mode 100644 View/Acos/admin_index.ctp create mode 100644 View/Acos/admin_prune_acos.ctp create mode 100644 View/Acos/admin_synchronize.ctp create mode 100644 View/Aros/admin_ajax_role_permissions.ctp create mode 100644 View/Aros/admin_ajax_user_permissions.ctp create mode 100644 View/Aros/admin_check.ctp create mode 100644 View/Aros/admin_index.ctp create mode 100644 View/Aros/admin_not_acl_requester.ctp create mode 100644 View/Aros/admin_role_permissions.ctp create mode 100644 View/Aros/admin_user_permissions.ctp create mode 100644 View/Aros/admin_users.ctp create mode 100644 View/Aros/ajax_role_denied.ctp create mode 100644 View/Aros/ajax_role_granted.ctp create mode 100644 View/Aros/ajax_user_denied.ctp create mode 100644 View/Aros/ajax_user_granted.ctp create mode 100644 View/Elements/Acos/links.ctp create mode 100644 View/Elements/Aros/links.ctp create mode 100644 View/Elements/design/footer.ctp create mode 100644 View/Elements/design/header.ctp create mode 100644 View/Elements/flash_error.ctp create mode 100644 View/Elements/flash_message.ctp create mode 100644 View/Errors/missing_aco_nodes.ctp create mode 100644 View/Helper/AclHtmlHelper.php create mode 100644 webroot/css/acl.css create mode 100644 webroot/empty create mode 100644 webroot/img/ajax/waiting16.gif create mode 100644 webroot/img/ajax/waiting24.gif create mode 100644 webroot/img/design/add.png create mode 100644 webroot/img/design/alert_medium.gif create mode 100644 webroot/img/design/alert_small.gif create mode 100644 webroot/img/design/bulb16.png create mode 100644 webroot/img/design/bulb24.png create mode 100644 webroot/img/design/clean.png create mode 100644 webroot/img/design/cross.png create mode 100644 webroot/img/design/cross2.png create mode 100644 webroot/img/design/gradient_bg.gif create mode 100644 webroot/img/design/important16.png create mode 100644 webroot/img/design/lock.png create mode 100644 webroot/img/design/question.gif create mode 100644 webroot/img/design/question.png create mode 100644 webroot/img/design/success_medium.gif create mode 100644 webroot/img/design/success_small.gif create mode 100644 webroot/img/design/sync.png create mode 100644 webroot/img/design/tick.png create mode 100644 webroot/img/design/tick_disabled.png create mode 100644 webroot/img/design/warning_medium.gif create mode 100644 webroot/img/design/warning_small.png create mode 100644 webroot/js/acl_plugin.js create mode 100644 webroot/js/jquery.js diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..37ffe71 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,136 @@ +ACL Plugin for CakePHP 2.x +========================== + +Website: http://www.alaxos.net/blaxos/pages/view/plugin_acl +Author: Nicolas Rod +License: http://www.opensource.org/licenses/mit-license.php The MIT License + +Version: 2.2.0 +-------------- +Date: 2012-09-24 + +- corrected some functions to be fully compatible with CakePHP 2.1 and above to allow the use of E_STRICT error reporting level +- As a side effect, E_STRICT error reporting level is not possible anymore when using CakePHP 2.0 +- better support of controller names containing an underscore +- ACO records that are not controllers or actions are not detected as ACO to prune anymore +- corrected a bug in AclRouter making the aco_path() function fail when the Cake app is at the domain root level +- added a response->render() to be sure to see the alert when some controllers have been updated +- corrected a App:uses to prevent an HtmlHelper not found error + +Version: 2.1.0 +-------------- +Date: 2012-02-04 + +- Corrected a security bug allowing any authenticated user to access the Acl plugin +- Obsolete ACO nodes are now removed from the database when the ACO datatable is synchronized with the application +- Plugins default controllers are now supported by the plugin, allowing to set permissions for their actions +- New beta AclHtmlHelper containing a link() function that returns an HTML link only if its url points to an action + that the current authenticated user can access (works only if the AclManagerComponent->set_session_permissions() was called before) +- Some minor design updates + +Version: 2.0.0 +-------------- +Date: 2011-12-15 + +- As no problems have been signaled with the 2.0.0-RC6 version, it finally becomes the 2.0.0 + +Version: 2.0.0-RC6 +------------------ +Date: 2011-12-09 + +- Corrected a bug preventing the retrieval of plugin controllers methods when a PluginAppController exists + +Version: 2.0.0-RC5 +------------------ +Date: 2011-12-07 + +- Added the RequestHandler component in AclAppController to make the plugin work even if the AppController does not use it already + +Version: 2.0.0-RC4 +------------------ +Date: 2011-11-26 + +- Removed plugin named parameter from Ajax requests when plugin is empty +- Removed doubled slashes from icons src urls + + Special thanks to Dave and Sam Sherlock for their feedbacks and ideas + +Version: 2.0.0-RC3 +------------------ +Date: 2011-11-01 + +- Removed RequestHandler from ArosController as its method isAjax() is deprecated (use $this->request->is('ajax') instead) + +Version: 2.0.0-beta +------------------- +Date: 2011-09-19 + +- Adaptation for CakePHP 2.0 + + No new functionnalities in this version, but the code has been updated for the new Cake 2.0-RC1 + Renamed classes, use App::uses() instead of old App::import(), updated forms url, etc. + + +Version: 1.0.7 +---------------- +Date: 2011-07-18 + +- the aros/users_permissions action can now be loaded through Ajax to prevent a request timeout when there are too many permissions to check +- added an indication when a user have specific permissions. New action to delete these specific permissions. +- corrected the way to get the plugins' paths in order to support custom paths added to App::path('plugins'); +- corrected the way the plugins parent ACO are generated to support camel cased plugin names +- added a parameter in bootstrap.php to support roles and users primary keys' names that do not follow CakePHP conventions +- eventual errors raised by the user model when updating the users role are now displayed for a better understanding of the problem +- new brazilian portuguese (pt_BR) translation +- performance improvements in find queries by limiting retrieved data + +Credit: + +- Elias Farah + + For the brazilian portuguese translation po file and for his help to add the possibility to customize the roles and users primary keys' names + +- Paul Marshall (http://www.paulmarshall.us) + + For pointing out a better way the get the plugins' paths and for ideas to improve performance in queries + +- Ilya (http://www.skychip.ru) and Gregorz + + For identifying a bug with camel cased plugins' names and pointing out the solution + + +Version: 1.0.6 +---------------- +Date: 2011-04-27 + +- added a parameter in bootstrap.php to support role foreign key's names that do not follow CakePHP conventions + +Version: 1.0.5 +---------------- +Date: 2011-02-19 + +- bug correction: the role foreign key is now created by using the Inflector class to be correctly generated even for camelcased role model names +- bug correcton: updated the way the roles and users display names are configured to prevent some situations where the use of an existing database field + was not possible. It also improves performance by creating new virtual fields only if necessary. + +Credit: thanks to Paul Marshall for his help on this version (http://www.paulmarshall.us) + +Version: 1.0.4 +---------------- +Date: 2011-01-22 + +- the aros/role_permissions action can now be loaded through Ajax to prevent a request timeout when there are too many permissions to check +- new search filters on users roles page and users permissions page +- updated the way new controller and/or actions detection is done to allow to see the warning even after a redirection from /admin/acl +- replaced $html and $form by $this->Html and $this->Form in views to respect CakePHP best practices + +Version: 1.0.3 +---------------- +Date: 2010-12-05 + +- Added support of plugins placed in ROOT/plugins +- Corrected a bug preventing to set a user specific permission in some cases +- Added automatic verification that the user and role models act as ACL requesters +- No writable 'tmp' folder needed anymore +- Some code refactoring (moved functions from the AclAppController to new components) +- Added this CHANGELOG file... ;-) diff --git a/Config/Schema/empty b/Config/Schema/empty new file mode 100644 index 0000000..e69de29 diff --git a/Config/bootstrap.php b/Config/bootstrap.php new file mode 100644 index 0000000..e11e5d3 --- /dev/null +++ b/Config/bootstrap.php @@ -0,0 +1,84 @@ + App :: pluginPath('Acl') . DS . 'locale')); + +/* + * Indicates whether the roles permissions page must load through Ajax + */ +Configure :: write('acl.gui.roles_permissions.ajax', false); + +/* + * Indicates whether the users permissions page must load through Ajax + */ +Configure :: write('acl.gui.users_permissions.ajax', false); +?> \ No newline at end of file diff --git a/Controller/AclAppController.php b/Controller/AclAppController.php new file mode 100644 index 0000000..342609f --- /dev/null +++ b/Controller/AclAppController.php @@ -0,0 +1,204 @@ + + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + * @link http://www.alaxos.ch + * + * @property AclManagerComponent $AclManager + */ +class AclAppController extends AppController +{ + var $components = array('RequestHandler', 'Acl.AclManager', 'Acl.AclReflector'); + + function beforeFilter() + { + parent :: beforeFilter(); + + $this->_check_config(); + $this->_check_files_updates(); + } + + private function _check_config() + { + $role_model_name = Configure :: read('acl.aro.role.model'); + + if(!empty($role_model_name)) + { + $this->set('role_model_name', $role_model_name); + $this->set('user_model_name', Configure :: read('acl.aro.user.model')); + $this->set('role_pk_name', $this->_get_role_primary_key_name()); + $this->set('user_pk_name', $this->_get_user_primary_key_name()); + $this->set('role_fk_name', $this->_get_role_foreign_key_name()); + + $this->_authorize_admins(); + +// if($this->name != 'Acl' +// && +// ($this->name != 'Acos' || $this->action != 'admin_build_acl') +// ) +// { +// $missing_aco_nodes = $this->AclManager->get_missing_acos(); +// +// if(count($missing_aco_nodes) > 0) +// { +// $this->set('missing_aco_nodes', $missing_aco_nodes); +// $this->render('/Acos/admin_acos_missing'); +// } +// } + + if(Configure :: read('acl.check_act_as_requester')) + { + $is_requester = true; + + if(!$this->AclManager->check_user_model_acts_as_acl_requester(Configure :: read('acl.aro.user.model'))) + { + $this->set('model_is_not_requester', false); + $is_requester = false; + } + + if(!$this->AclManager->check_user_model_acts_as_acl_requester(Configure :: read('acl.aro.role.model'))) + { + $this->set('role_is_not_requester', false); + $is_requester = false; + } + + if(!$is_requester) + { + $this->render('/Aros/admin_not_acl_requester'); + } + } + } + else + { + $this->Session->setFlash(__d('acl', 'The role model name is unknown. The ACL plugin bootstrap.php file has to be loaded in order to work. (see the README file)'), 'flash_error', null, 'plugin_acl'); + } + } + + function _check_files_updates() + { + if($this->request->params['controller'] != 'acos' + || ($this->request->params['action'] != 'admin_synchronize' && + $this->request->params['action'] != 'admin_prune_acos' && + $this->request->params['action'] != 'admin_build_acl')) + { + if($this->AclManager->controller_hash_file_is_out_of_sync()) + { + $missing_aco_nodes = $this->AclManager->get_missing_acos(); + $nodes_to_prune = $this->AclManager->get_acos_to_prune(); + + $has_updates = false; + + if(count($missing_aco_nodes) > 0) + { + $has_updates = true; + } + + if(count($nodes_to_prune) > 0) + { + $has_updates = true; + } + + $this->set('nodes_to_prune', $nodes_to_prune); + $this->set('missing_aco_nodes', $missing_aco_nodes); + + if($has_updates) + { + $this->render('/Acos/admin_has_updates'); + $this->response->send(); + $this->AclManager->update_controllers_hash_file(); + die(); + } + else + { + $this->AclManager->update_controllers_hash_file(); + } + } + } + } + + private function _authorize_admins() + { + $authorized_role_ids = Configure :: read('acl.role.access_plugin_role_ids'); + $authorized_user_ids = Configure :: read('acl.role.access_plugin_user_ids'); + + $model_role_fk = $this->_get_role_foreign_key_name(); + + if(in_array($this->Auth->user($model_role_fk), $authorized_role_ids) + || in_array($this->Auth->user($this->_get_user_primary_key_name()), $authorized_user_ids)) + { + // Allow all actions. CakePHP 2.0 + $this->Auth->allow('*'); + + // Allow all actions. CakePHP 2.1 + $this->Auth->allow(); + } + } + + function _get_passed_aco_path() + { + $aco_path = isset($this->params['named']['plugin']) ? $this->params['named']['plugin'] : ''; + $aco_path .= empty($aco_path) ? $this->params['named']['controller'] : '/' . $this->params['named']['controller']; + $aco_path .= '/' . $this->params['named']['action']; + + return $aco_path; + } + function _set_aco_variables() + { + $this->set('plugin', isset($this->params['named']['plugin']) ? $this->params['named']['plugin'] : ''); + $this->set('controller_name', $this->params['named']['controller']); + $this->set('action', $this->params['named']['action']); + } + + function _get_role_primary_key_name() + { + $forced_pk_name = Configure :: read('acl.aro.role.primary_key'); + if(!empty($forced_pk_name)) + { + return $forced_pk_name; + } + else + { + /* + * Return the primary key's name that follows the CakePHP conventions + */ + return 'id'; + } + } + function _get_user_primary_key_name() + { + $forced_pk_name = Configure :: read('acl.aro.user.primary_key'); + if(!empty($forced_pk_name)) + { + return $forced_pk_name; + } + else + { + /* + * Return the primary key's name that follows the CakePHP conventions + */ + return 'id'; + } + } + function _get_role_foreign_key_name() + { + $forced_fk_name = Configure :: read('acl.aro.role.foreign_key'); + if(!empty($forced_fk_name)) + { + return $forced_fk_name; + } + else + { + /* + * Return the foreign key's name that follows the CakePHP conventions + */ + return Inflector :: underscore(Configure :: read('acl.aro.role.model')) . '_id'; + } + } + + function _return_to_referer() + { + $this->redirect($this->referer(array('action' => 'admin_index'))); + } +} +?> \ No newline at end of file diff --git a/Controller/AclController.php b/Controller/AclController.php new file mode 100644 index 0000000..fd753d1 --- /dev/null +++ b/Controller/AclController.php @@ -0,0 +1,24 @@ + + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + * @link http://www.alaxos.ch + */ +class AclController extends AclAppController { + + var $name = 'Acl'; + var $uses = null; + + function index() + { + $this->redirect('/admin/acl/aros'); + } + + function admin_index() + { + $this->redirect('/admin/acl/acos'); + } + +} +?> \ No newline at end of file diff --git a/Controller/AcosController.php b/Controller/AcosController.php new file mode 100644 index 0000000..7f0c9e5 --- /dev/null +++ b/Controller/AcosController.php @@ -0,0 +1,120 @@ + + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + * @link http://www.alaxos.ch + * + * @property AclManagerComponent $AclManager + */ +class AcosController extends AclAppController { + + var $name = 'Acos'; + //var $components = array('Acl', 'Acl.AclManager'); + + function admin_index() + { + + } + + function admin_empty_acos($run = null) + { + /* + * Delete ACO with 'alias' controllers + * -> all ACOs belonging to the actions tree will be deleted, but eventual ACO that are not actions will be kept + */ + $controller_aco = $this->Aco->findByAlias('controllers'); + + if($controller_aco !== false) + { + $this->set('actions_exist', true); + + if(isset($run)) + { + if($this->Aco->delete($controller_aco['Aco']['id'])) + { + $this->set('actions_exist', false); + + $this->Session->setFlash(__d('acl', 'The actions in the ACO table have been deleted'), 'flash_message', null, 'plugin_acl'); + } + else + { + $this->Session->setFlash(__d('acl', 'The actions in the ACO table could not be deleted'), 'flash_error', null, 'plugin_acl'); + } + + $this->set('run', true); + } + else + { + $this->set('run', false); + } + } + else + { + $this->set('actions_exist', false); + } + } + + function admin_build_acl($run = null) + { + if(isset($run)) + { + $logs = $this->AclManager->create_acos(); + + $this->set('logs', $logs); + $this->set('run', true); + } + else + { + $missing_aco_nodes = $this->AclManager->get_missing_acos(); + + $this->set('missing_aco_nodes', $missing_aco_nodes); + + $this->set('run', false); + } + } + + function admin_prune_acos($run = null) + { + if(isset($run)) + { + $logs = $this->AclManager->prune_acos(); + + $this->set('logs', $logs); + $this->set('run', true); + } + else + { + $nodes_to_prune = $this->AclManager->get_acos_to_prune(); + + $this->set('nodes_to_prune', $nodes_to_prune); + + $this->set('run', false); + } + } + + function admin_synchronize($run = null) + { + if(isset($run)) + { + $prune_logs = $this->AclManager->prune_acos(); + $create_logs = $this->AclManager->create_acos(); + + $this->set('create_logs', $create_logs); + $this->set('prune_logs', $prune_logs); + + $this->set('run', true); + } + else + { + $nodes_to_prune = $this->AclManager->get_acos_to_prune(); + $missing_aco_nodes = $this->AclManager->get_missing_acos(); + + $this->set('nodes_to_prune', $nodes_to_prune); + $this->set('missing_aco_nodes', $missing_aco_nodes); + + $this->set('run', false); + } + } +} +?> \ No newline at end of file diff --git a/Controller/ArosController.php b/Controller/ArosController.php new file mode 100644 index 0000000..3a31663 --- /dev/null +++ b/Controller/ArosController.php @@ -0,0 +1,819 @@ + + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + * @link http://www.alaxos.ch + * + * @property AclReflectorComponent $AclReflector + */ +class ArosController extends AclAppController +{ + + var $name = 'Aros'; + var $uses = array('Aro'); + var $helpers = array('Js' => array('Jquery')); + + var $paginate = array( + 'limit' => 20, + //'order' => array('display_name' => 'asc') + ); + + function beforeFilter() + { + $this->loadModel(Configure :: read('acl.aro.role.model')); + $this->loadModel(Configure :: read('acl.aro.user.model')); + + parent :: beforeFilter(); + } + + function admin_index() + { + + } + + function admin_check($run = null) + { + $user_model_name = Configure :: read('acl.aro.user.model'); + $role_model_name = Configure :: read('acl.aro.role.model'); + + $user_display_field = $this->AclManager->set_display_name($user_model_name, Configure :: read('acl.user.display_name')); + $role_display_field = $this->AclManager->set_display_name($role_model_name, Configure :: read('acl.aro.role.display_field')); + + $this->set('user_display_field', $user_display_field); + $this->set('role_display_field', $role_display_field); + + $roles = $this->{$role_model_name}->find('all', array('order' => $role_display_field, 'contain' => false, 'recursive' => -1)); + + $missing_aros = array('roles' => array(), 'users' => array()); + + foreach($roles as $role) + { + /* + * Check if ARO for role exist + */ + $aro = $this->Aro->find('first', array('conditions' => array('model' => $role_model_name, 'foreign_key' => $role[$role_model_name][$this->_get_role_primary_key_name()]))); + + if($aro === false) + { + $missing_aros['roles'][] = $role; + } + } + + $users = $this->{$user_model_name}->find('all', array('order' => $user_display_field, 'contain' => false, 'recursive' => -1)); + foreach($users as $user) + { + /* + * Check if ARO for user exist + */ + $aro = $this->Aro->find('first', array('conditions' => array('model' => $user_model_name, 'foreign_key' => $user[$user_model_name][$this->_get_user_primary_key_name()]))); + + if($aro === false) + { + $missing_aros['users'][] = $user; + } + } + + + if(isset($run)) + { + $this->set('run', true); + + /* + * Complete roles AROs + */ + if(count($missing_aros['roles']) > 0) + { + foreach($missing_aros['roles'] as $k => $role) + { + $this->Aro->create(array('parent_id' => null, + 'model' => $role_model_name, + 'foreign_key' => $role[$role_model_name][$this->_get_role_primary_key_name()], + 'alias' => $role[$role_model_name][$role_display_field])); + + if($this->Aro->save()) + { + unset($missing_aros['roles'][$k]); + } + } + } + + /* + * Complete users AROs + */ + if(count($missing_aros['users']) > 0) + { + foreach($missing_aros['users'] as $k => $user) + { + /* + * Find ARO parent for user ARO + */ + $parent_id = $this->Aro->field('id', array('model' => $role_model_name, 'foreign_key' => $user[$user_model_name][$this->_get_role_foreign_key_name()])); + + if($parent_id !== false) + { + $this->Aro->create(array('parent_id' => $parent_id, + 'model' => $user_model_name, + 'foreign_key' => $user[$user_model_name][$this->_get_user_primary_key_name()], + 'alias' => $user[$user_model_name][$user_display_field])); + + if($this->Aro->save()) + { + unset($missing_aros['users'][$k]); + } + } + } + } + } + else + { + $this->set('run', false); + } + + $this->set('missing_aros', $missing_aros); + + } + + function admin_users() + { + $user_model_name = Configure :: read('acl.aro.user.model'); + $role_model_name = Configure :: read('acl.aro.role.model'); + + $user_display_field = $this->AclManager->set_display_name($user_model_name, Configure :: read('acl.user.display_name')); + $role_display_field = $this->AclManager->set_display_name($role_model_name, Configure :: read('acl.aro.role.display_field')); + + $this->paginate['order'] = array($user_display_field => 'asc'); + + $this->set('user_display_field', $user_display_field); + $this->set('role_display_field', $role_display_field); + + $this->{$role_model_name}->recursive = -1; + $roles = $this->{$role_model_name}->find('all', array('order' => $role_display_field, 'contain' => false, 'recursive' => -1)); + + $this->{$user_model_name}->recursive = -1; + + if(isset($this->request->data['User'][$user_display_field]) || $this->Session->check('acl.aros.users.filter')) + { + if(!isset($this->request->data['User'][$user_display_field])) + { + $this->request->data['User'][$user_display_field] = $this->Session->read('acl.aros.users.filter'); + } + else + { + $this->Session->write('acl.aros.users.filter', $this->request->data['User'][$user_display_field]); + } + + $filter = array($user_model_name . '.' . $user_display_field . ' LIKE' => '%' . $this->request->data['User'][$user_display_field] . '%'); + } + else + { + $filter = array(); + } + + $users = $this->paginate($user_model_name, $filter); + + $missing_aro = false; + + foreach($users as &$user) + { + $aro = $this->Acl->Aro->find('first', array('conditions' => array('model' => $user_model_name, 'foreign_key' => $user[$user_model_name][$this->_get_user_primary_key_name()]))); + + if($aro !== false) + { + $user['Aro'] = $aro['Aro']; + } + else + { + $missing_aro = true; + } + } + + $this->set('roles', $roles); + $this->set('users', $users); + $this->set('missing_aro', $missing_aro); + } + + function admin_update_user_role() + { + $user_model_name = Configure :: read('acl.aro.user.model'); + + $data = array($user_model_name => array($this->_get_user_primary_key_name() => $this->params['named']['user'], $this->_get_role_foreign_key_name() => $this->params['named']['role'])); + + if($this->{$user_model_name}->save($data, false)) + { + $this->Session->setFlash(__d('acl', 'The user role has been updated'), 'flash_message', null, 'plugin_acl'); + } + else + { + $errors = array_merge(array(__d('acl', 'The user role could not be updated')), $this->{$user_model_name}->validationErrors); + $this->Session->setFlash($errors, 'flash_error', null, 'plugin_acl'); + } + + $this->_return_to_referer(); + } + + function admin_ajax_role_permissions() + { + $role_model_name = Configure :: read('acl.aro.role.model'); + + $role_display_field = $this->AclManager->set_display_name($role_model_name, Configure :: read('acl.aro.role.display_field')); + + $this->set('role_display_field', $role_display_field); + + $this->{$role_model_name}->recursive = -1; + $roles = $this->{$role_model_name}->find('all', array('order' => $role_display_field, 'contain' => false, 'recursive' => -1)); + + $actions = $this->AclReflector->get_all_actions(); + + $methods = array(); + foreach($actions as $k => $full_action) + { + $arr = String::tokenize($full_action, '/'); + + if (count($arr) == 2) + { + $plugin_name = null; + $controller_name = $arr[0]; + $action = $arr[1]; + } + elseif(count($arr) == 3) + { + $plugin_name = $arr[0]; + $controller_name = $arr[1]; + $action = $arr[2]; + } + + if($controller_name == 'App') + { + unset($actions[$k]); + } + else + { + if(isset($plugin_name)) + { + $methods['plugin'][$plugin_name][$controller_name][] = array('name' => $action); + } + else + { + $methods['app'][$controller_name][] = array('name' => $action); + } + } + } + + $this->set('roles', $roles); + $this->set('actions', $methods); + } + + function admin_role_permissions() + { + $role_model_name = Configure :: read('acl.aro.role.model'); + + $role_display_field = $this->AclManager->set_display_name($role_model_name, Configure :: read('acl.aro.role.display_field')); + + $this->set('role_display_field', $role_display_field); + + $this->{$role_model_name}->recursive = -1; + $roles = $this->{$role_model_name}->find('all', array('order' => $role_display_field, 'contain' => false, 'recursive' => -1)); + + $actions = $this->AclReflector->get_all_actions(); + + $permissions = array(); + $methods = array(); + + foreach($actions as $full_action) + { + $arr = String::tokenize($full_action, '/'); + + if (count($arr) == 2) + { + $plugin_name = null; + $controller_name = $arr[0]; + $action = $arr[1]; + } + elseif(count($arr) == 3) + { + $plugin_name = $arr[0]; + $controller_name = $arr[1]; + $action = $arr[2]; + } + + if($controller_name != 'App') + { + foreach($roles as $role) + { + $aro_node = $this->Acl->Aro->node($role); + if(!empty($aro_node)) + { + $aco_node = $this->Acl->Aco->node('controllers/' . $full_action); + if(!empty($aco_node)) + { + $authorized = $this->Acl->check($role, 'controllers/' . $full_action); + + $permissions[$role[Configure :: read('acl.aro.role.model')][$this->_get_role_primary_key_name()]] = $authorized ? 1 : 0 ; + } + } + else + { + /* + * No check could be done as the ARO is missing + */ + $permissions[$role[Configure :: read('acl.aro.role.model')][$this->_get_role_primary_key_name()]] = -1; + } + } + + if(isset($plugin_name)) + { + $methods['plugin'][$plugin_name][$controller_name][] = array('name' => $action, 'permissions' => $permissions); + } + else + { + $methods['app'][$controller_name][] = array('name' => $action, 'permissions' => $permissions); + } + } + } + + $this->set('roles', $roles); + $this->set('actions', $methods); + } + + function admin_user_permissions($user_id = null) + { + $user_model_name = Configure :: read('acl.aro.user.model'); + $role_model_name = Configure :: read('acl.aro.role.model'); + + $user_display_field = $this->AclManager->set_display_name($user_model_name, Configure :: read('acl.user.display_name')); + + $this->paginate['order'] = array($user_display_field => 'asc'); + $this->set('user_display_field', $user_display_field); + + if(empty($user_id)) + { + if(isset($this->request->data['User'][$user_display_field]) || $this->Session->check('acl.aros.user_permissions.filter')) + { + if(!isset($this->request->data['User'][$user_display_field])) + { + $this->request->data['User'][$user_display_field] = $this->Session->read('acl.aros.user_permissions.filter'); + } + else + { + $this->Session->write('acl.aros.user_permissions.filter', $this->request->data['User'][$user_display_field]); + } + + $filter = array($user_model_name . '.' . $user_display_field . ' LIKE' => '%' . $this->request->data['User'][$user_display_field] . '%'); + } + else + { + $filter = array(); + } + + $users = $this->paginate($user_model_name, $filter); + + $this->set('users', $users); + } + else + { + $role_display_field = $this->AclManager->set_display_name($role_model_name, Configure :: read('acl.aro.role.display_field')); + + $this->set('role_display_field', $role_display_field); + + $this->{$role_model_name}->recursive = -1; + $roles = $this->{$role_model_name}->find('all', array('order' => $role_display_field, 'contain' => false, 'recursive' => -1)); + + $this->{$user_model_name}->recursive = -1; + $user = $this->{$user_model_name}->read(null, $user_id); + + $permissions = array(); + $methods = array(); + + /* + * Check if the user exists in the ARO table + */ + $user_aro = $this->Acl->Aro->node($user); + if(empty($user_aro)) + { + $display_user = $this->{$user_model_name}->find('first', array('conditions' => array($user_model_name . '.id' => $user_id, 'contain' => false, 'recursive' => -1))); + $this->Session->setFlash(sprintf(__d('acl', "The user '%s' does not exist in the ARO table"), $display_user[$user_model_name][$user_display_field]), 'flash_error', null, 'plugin_acl'); + } + else + { + $actions = $this->AclReflector->get_all_actions(); + + foreach($actions as $full_action) + { + $arr = String::tokenize($full_action, '/'); + + if (count($arr) == 2) + { + $plugin_name = null; + $controller_name = $arr[0]; + $action = $arr[1]; + } + elseif(count($arr) == 3) + { + $plugin_name = $arr[0]; + $controller_name = $arr[1]; + $action = $arr[2]; + } + + if($controller_name != 'App') + { + if(!isset($this->params['named']['ajax'])) + { + $aco_node = $this->Acl->Aco->node('controllers/' . $full_action); + if(!empty($aco_node)) + { + $authorized = $this->Acl->check($user, 'controllers/' . $full_action); + + $permissions[$user[$user_model_name][$this->_get_user_primary_key_name()]] = $authorized ? 1 : 0 ; + } + } + + if(isset($plugin_name)) + { + $methods['plugin'][$plugin_name][$controller_name][] = array('name' => $action, 'permissions' => $permissions); + } + else + { + $methods['app'][$controller_name][] = array('name' => $action, 'permissions' => $permissions); + } + } + } + + /* + * Check if the user has specific permissions + */ + $count = $this->Aro->Permission->find('count', array('conditions' => array('Aro.id' => $user_aro[0]['Aro']['id']))); + if($count != 0) + { + $this->set('user_has_specific_permissions', true); + } + else + { + $this->set('user_has_specific_permissions', false); + } + } + + $this->set('user', $user); + $this->set('roles', $roles); + $this->set('actions', $methods); + + if(isset($this->params['named']['ajax'])) + { + $this->render('admin_ajax_user_permissions'); + } + } + } + + function admin_empty_permissions() + { + if($this->Aro->Permission->deleteAll(array('Permission.id > ' => 0))) + { + $this->Session->setFlash(__d('acl', 'The permissions have been cleared'), 'flash_message', null, 'plugin_acl'); + } + else + { + $this->Session->setFlash(__d('acl', 'The permissions could not be cleared'), 'flash_error', null, 'plugin_acl'); + } + + $this->_return_to_referer(); + } + + function admin_clear_user_specific_permissions($user_id) + { + $user =& $this->{Configure :: read('acl.aro.user.model')}; + $user->id = $user_id; + + /* + * Check if the user exists in the ARO table + */ + $node = $this->Acl->Aro->node($user); + if(empty($node)) + { + $asked_user = $user->read(null, $user_id); + $this->Session->setFlash(sprintf(__d('acl', "The user '%s' does not exist in the ARO table"), $asked_user['User'][Configure :: read('acl.user.display_name')]), 'flash_error', null, 'plugin_acl'); + } + else + { + if($this->Aro->Permission->deleteAll(array('Aro.id' => $node[0]['Aro']['id']))) + { + $this->Session->setFlash(__d('acl', 'The specific permissions have been cleared'), 'flash_message', null, 'plugin_acl'); + } + else + { + $this->Session->setFlash(__d('acl', 'The specific permissions could not be cleared'), 'flash_error', null, 'plugin_acl'); + } + } + + $this->_return_to_referer(); + } + + function admin_grant_all_controllers($role_id) + { + $role =& $this->{Configure :: read('acl.aro.role.model')}; + $role->id = $role_id; + + /* + * Check if the Role exists in the ARO table + */ + $node = $this->Acl->Aro->node($role); + if(empty($node)) + { + $asked_role = $role->read(null, $role_id); + $this->Session->setFlash(sprintf(__d('acl', "The role '%s' does not exist in the ARO table"), $asked_role['Role'][Configure :: read('acl.aro.role.display_field')]), 'flash_error', null, 'plugin_acl'); + } + else + { + //Allow to everything + $this->Acl->allow($role, 'controllers'); + } + + $this->_return_to_referer(); + } + function admin_deny_all_controllers($role_id) + { + $role =& $this->{Configure :: read('acl.aro.role.model')}; + $role->id = $role_id; + + /* + * Check if the Role exists in the ARO table + */ + $node = $this->Acl->Aro->node($role); + if(empty($node)) + { + $asked_role = $role->read(null, $role_id); + $this->Session->setFlash(sprintf(__d('acl', "The role '%s' does not exist in the ARO table"), $asked_role['Role'][Configure :: read('acl.aro.role.display_field')]), 'flash_error', null, 'plugin_acl'); + } + else + { + //Deny everything + $this->Acl->deny($role, 'controllers'); + } + + $this->_return_to_referer(); + } + + function admin_get_role_controller_permission($role_id) + { + $role =& $this->{Configure :: read('acl.aro.role.model')}; + + $role_data = $role->read(null, $role_id); + + $aro_node = $this->Acl->Aro->node($role_data); + if(!empty($aro_node)) + { + $plugin_name = isset($this->params['named']['plugin']) ? $this->params['named']['plugin'] : ''; + $controller_name = $this->params['named']['controller']; + $controller_actions = $this->AclReflector->get_controller_actions($controller_name); + + $role_controller_permissions = array(); + + foreach($controller_actions as $action_name) + { + $aco_path = $plugin_name; + $aco_path .= empty($aco_path) ? $controller_name : '/' . $controller_name; + $aco_path .= '/' . $action_name; + + $aco_node = $this->Acl->Aco->node('controllers/' . $aco_path); + if(!empty($aco_node)) + { + $authorized = $this->Acl->check($role_data, 'controllers/' . $aco_path); + $role_controller_permissions[$action_name] = $authorized; + } + else + { + $role_controller_permissions[$action_name] = -1; + } + } + } + else + { + //$this->set('acl_error', true); + //$this->set('acl_error_aro', true); + } + + if($this->request->is('ajax')) + { + Configure::write('debug', 0); //-> to disable printing of generation time preventing correct JSON parsing + echo json_encode($role_controller_permissions); + $this->autoRender = false; + } + else + { + $this->_return_to_referer(); + } + } + function admin_grant_role_permission($role_id) + { + $role =& $this->{Configure :: read('acl.aro.role.model')}; + + $role->id = $role_id; + + $aco_path = $this->_get_passed_aco_path(); + + /* + * Check if the role exists in the ARO table + */ + $aro_node = $this->Acl->Aro->node($role); + if(!empty($aro_node)) + { + if(!$this->AclManager->save_permission($aro_node, $aco_path, 'grant')) + { + $this->set('acl_error', true); + } + } + else + { + $this->set('acl_error', true); + $this->set('acl_error_aro', true); + } + + $this->set('role_id', $role_id); + $this->_set_aco_variables(); + + if($this->request->is('ajax')) + { + $this->render('ajax_role_granted'); + } + else + { + $this->_return_to_referer(); + } + } + function admin_deny_role_permission($role_id) + { + $role =& $this->{Configure :: read('acl.aro.role.model')}; + + $role->id = $role_id; + + $aco_path = $this->_get_passed_aco_path(); + + $aro_node = $this->Acl->Aro->node($role); + if(!empty($aro_node)) + { + if(!$this->AclManager->save_permission($aro_node, $aco_path, 'deny')) + { + $this->set('acl_error', true); + } + } + else + { + $this->set('acl_error', true); + } + + $this->set('role_id', $role_id); + $this->_set_aco_variables(); + + if($this->request->is('ajax')) + { + $this->render('ajax_role_denied'); + } + else + { + $this->_return_to_referer(); + } + } + + function admin_get_user_controller_permission($user_id) + { + $user =& $this->{Configure :: read('acl.aro.user.model')}; + + $user_data = $user->read(null, $user_id); + + $aro_node = $this->Acl->Aro->node($user_data); + if(!empty($aro_node)) + { + $plugin_name = isset($this->params['named']['plugin']) ? $this->params['named']['plugin'] : ''; + $controller_name = $this->params['named']['controller']; + $controller_actions = $this->AclReflector->get_controller_actions($controller_name); + + $user_controller_permissions = array(); + + foreach($controller_actions as $action_name) + { + $aco_path = $plugin_name; + $aco_path .= empty($aco_path) ? $controller_name : '/' . $controller_name; + $aco_path .= '/' . $action_name; + + $aco_node = $this->Acl->Aco->node('controllers/' . $aco_path); + if(!empty($aco_node)) + { + $authorized = $this->Acl->check($user_data, 'controllers/' . $aco_path); + $user_controller_permissions[$action_name] = $authorized; + } + else + { + $user_controller_permissions[$action_name] = -1; + } + } + } + else + { + //$this->set('acl_error', true); + //$this->set('acl_error_aro', true); + } + + if($this->request->is('ajax')) + { + Configure::write('debug', 0); //-> to disable printing of generation time preventing correct JSON parsing + echo json_encode($user_controller_permissions); + $this->autoRender = false; + } + else + { + $this->_return_to_referer(); + } + } + function admin_grant_user_permission($user_id) + { + $user =& $this->{Configure :: read('acl.aro.user.model')}; + + $user->id = $user_id; + + $aco_path = $this->_get_passed_aco_path(); + + /* + * Check if the user exists in the ARO table + */ + $aro_node = $this->Acl->Aro->node($user); + if(!empty($aro_node)) + { + $aco_node = $this->Acl->Aco->node('controllers/' . $aco_path); + if(!empty($aco_node)) + { + if(!$this->AclManager->save_permission($aro_node, $aco_path, 'grant')) + { + $this->set('acl_error', true); + } + } + else + { + $this->set('acl_error', true); + $this->set('acl_error_aco', true); + } + } + else + { + $this->set('acl_error', true); + $this->set('acl_error_aro', true); + } + + $this->set('user_id', $user_id); + $this->_set_aco_variables(); + + if($this->request->is('ajax')) + { + $this->render('ajax_user_granted'); + } + else + { + $this->_return_to_referer(); + } + } + function admin_deny_user_permission($user_id) + { + $user =& $this->{Configure :: read('acl.aro.user.model')}; + + $user->id = $user_id; + + $aco_path = $this->_get_passed_aco_path(); + + /* + * Check if the user exists in the ARO table + */ + $aro_node = $this->Acl->Aro->node($user); + if(!empty($aro_node)) + { + $aco_node = $this->Acl->Aco->node('controllers/' . $aco_path); + if(!empty($aco_node)) + { + if(!$this->AclManager->save_permission($aro_node, $aco_path, 'deny')) + { + $this->set('acl_error', true); + } + } + else + { + $this->set('acl_error', true); + $this->set('acl_error_aco', true); + } + } + else + { + $this->set('acl_error', true); + $this->set('acl_error_aro', true); + } + + $this->set('user_id', $user_id); + $this->_set_aco_variables(); + + if($this->request->is('ajax')) + { + $this->render('ajax_user_denied'); + } + else + { + $this->_return_to_referer(); + } + } +} +?> \ No newline at end of file diff --git a/Controller/Component/AclManagerComponent.php b/Controller/Component/AclManagerComponent.php new file mode 100644 index 0000000..8d808eb --- /dev/null +++ b/Controller/Component/AclManagerComponent.php @@ -0,0 +1,773 @@ +controller = $controller; + $this->controllers_hash_file = CACHE . 'persistent' . DS . 'controllers_hashes.txt'; + } + + /****************************************************************************************/ + + /** + * Check if the file containing the stored controllers hashes can be created, + * and create it if it does not exist + * + * @return boolean true if the file exists or could be created + */ + private function check_controller_hash_tmp_file() + { + if(is_writable(dirname($this->controllers_hash_file))) + { + App :: uses('File', 'Utility'); + $file = new File($this->controllers_hash_file, true); + return $file->exists(); + } + else + { + $this->Session->setFlash(sprintf(__d('acl', 'the %s directory is not writable'), dirname($this->controllers_hash_file)), 'flash_error', null, 'plugin_acl'); + return false; + } + } + + /****************************************************************************************/ + + public function check_user_model_acts_as_acl_requester($model_classname) + { +// if(!isset($this->controller->{$model_classname})) +// { +// /* +// * Do not use $this->controller->loadModel, as calling it from a plugin may prevent correct loading of behaviors +// */ +// $user_model = ClassRegistry :: init($model_classname); +// } +// else +// { +// $user_model = $this->controller->{$model_classname}; +// } + + $user_model = $this->get_model_instance($model_classname); + + $behaviors = $user_model->actsAs; + if(!empty($behaviors) && array_key_exists('Acl', $behaviors)) + { + $acl_behavior = $behaviors['Acl']; + if($acl_behavior == 'requester') + { + return true; + } + elseif(is_array($acl_behavior) && isset($acl_behavior['type']) && $acl_behavior['type'] == 'requester') + { + return true; + } + } + + return false; + } + + /** + * Check if a given field_expression is an existing fieldname for the given model + * + * If it doesn't exist, a virtual field called 'alaxos_acl_display_name' is created with the given expression + * + * @param string $model_classname + * @param string $field_expression + * @return string The name of the field to use as display name + */ + public function set_display_name($model_classname, $field_expression) + { + $model_instance = $this->get_model_instance($model_classname); + + $schema = $model_instance->schema(); + + if(array_key_exists($field_expression, $schema) + || + array_key_exists(str_replace($model_classname . '.', '', $field_expression), $schema) + || + array_key_exists($field_expression, $model_instance->virtualFields)) + { + /* + * The field does not need to be created as it already exists in the model + * as a datatable field, or a virtual field configured in the model + */ + + /* + * Eventually remove the model name + */ + if(strpos($field_expression, $model_classname . '.') === 0) + { + $field_expression = str_replace($model_classname . '.', '', $field_expression); + } + + return $field_expression; + } + else + { + /* + * The field does not exist in the model + * -> create a virtual field with the given expression + */ + + $this->controller->{$model_classname}->virtualFields['alaxos_acl_display_name'] = $field_expression; + + return 'alaxos_acl_display_name'; + } + } + + /** + * Return an instance of the given model name + * + * @param string $model_classname + * @return Model + */ + private function get_model_instance($model_classname) + { + if(!isset($this->controller->{$model_classname})) + { + /* + * Do not use $this->controller->loadModel, as calling it from a plugin may prevent correct loading of behaviors + */ + $model_instance = ClassRegistry :: init($model_classname); + } + else + { + $model_instance = $this->controller->{$model_classname}; + } + + return $model_instance; + } + + /** + * return the stored array of controllers hashes + * + * @return array + */ + public function get_stored_controllers_hashes() + { + if($this->check_controller_hash_tmp_file()) + { + $file = new File($this->controllers_hash_file); + $file_content = $file->read(); + + if(!empty($file_content)) + { + $stored_controller_hashes = unserialize($file_content); + } + else + { + $stored_controller_hashes = array(); + } + + return $stored_controller_hashes; + } + } + + /** + * return an array of all controllers hashes + * + * @return array + */ + public function get_current_controllers_hashes() + { + $controllers = $this->AclReflector->get_all_controllers(); + + $current_controller_hashes = array(); + + foreach($controllers as $controller) + { + $ctler_file = new File($controller['file']); + $current_controller_hashes[$controller['name']] = $ctler_file->md5(); + } + + return $current_controller_hashes; + } + + /** + * Return ACOs paths that should exist in the ACO datatable but do not exist + */ + function get_missing_acos() + { + $actions = $this->AclReflector->get_all_actions(); + $controllers = $this->AclReflector->get_all_controllers(); + + $actions_aco_paths = array(); + foreach($actions as $action) + { + $action_infos = explode('/', $action); + $controller = $action_infos[count($action_infos) - 2]; + + if($controller != 'App') + { + $actions_aco_paths[] = 'controllers/' . $action; + } + } + foreach($controllers as $controller) + { + if($controller['name'] != 'App') + { + $actions_aco_paths[] = 'controllers/' . $controller['name']; + } + } + $actions_aco_paths[] = 'controllers'; + + $aco =& $this->Acl->Aco; + + $acos = $aco->find('all', array('recursive' => -1)); + + $existing_aco_paths = array(); + foreach($acos as $aco_node) + { + $path_nodes = $aco->getPath($aco_node['Aco']['id']); + $path = ''; + foreach($path_nodes as $path_node) + { + $path .= '/' . $path_node['Aco']['alias']; + } + + $path = substr($path, 1); + $existing_aco_paths[] = $path; + } + + $missing_acos = array_diff($actions_aco_paths, $existing_aco_paths); + + return $missing_acos; + } + + /** + * Store missing ACOs for all actions in the datasource + * If necessary, it creates actions parent nodes (plugin and controller) as well + */ + public function create_acos() + { + $aco =& $this->Acl->Aco; + + $log = array(); + + $controllers = $this->AclReflector->get_all_controllers(); + + /****************************************** + * Create 'controllers' node if it does not exist + */ + $root = $aco->node('controllers'); + if (empty($root)) + { + /* + * root node does not exist -> create it + */ + + $aco->create(array('parent_id' => null, 'model' => null, 'alias' => 'controllers')); + $root = $aco->save(); + $root['Aco']['id'] = $aco->id; + + $log[] = __d('acl', 'Created Aco node for controllers'); + } + else + { + $root = $root[0]; + } + + foreach($controllers as $controller) + { + $controller_name = $controller['name']; + + if($controller_name !== 'App') + { + $plugin_name = $this->AclReflector->getPluginName($controller_name); + $pluginNode = null; + + if(!empty($plugin_name)) + { + /* + * Case of plugin controller + */ + + $controller_name = $this->AclReflector->getPluginControllerName($controller_name); + + /****************************************** + * Check plugin node + */ + $pluginNode = $aco->node('controllers/' . $plugin_name); + if(empty($pluginNode)) + { + /* + * plugin node does not exist -> create it + */ + + $aco->create(array('parent_id' => $root['Aco']['id'], 'model' => null, 'alias' => $plugin_name)); + $pluginNode = $aco->save(); + $pluginNode['Aco']['id'] = $aco->id; + + $log[] = sprintf(__d('acl', 'Created Aco node for %s plugin'), $plugin_name); + } + } + + + /****************************************** + * Check controller node + */ + $controllerNode = $aco->node('controllers/' . (!empty($plugin_name) ? $plugin_name . '/' : '') . $controller_name); + if(empty($controllerNode)) + { + /* + * controller node does not exist -> create it + */ + + if(isset($pluginNode)) + { + /* + * The controller belongs to a plugin + */ + + $plugin_node_aco_id = isset($pluginNode[0]) ? $pluginNode[0]['Aco']['id'] : $pluginNode['Aco']['id']; + + $aco->create(array('parent_id' => $plugin_node_aco_id, 'model' => null, 'alias' => $controller_name)); + $controllerNode = $aco->save(); + $controllerNode['Aco']['id'] = $aco->id; + + $log[] = sprintf(__d('acl', 'Created Aco node for %s/%s'), $plugin_name, $controller_name); + } + else + { + /* + * The controller is an app controller + */ + + $aco->create(array('parent_id' => $root['Aco']['id'], 'model' => null, 'alias' => $controller_name)); + $controllerNode = $aco->save(); + $controllerNode['Aco']['id'] = $aco->id; + + $log[] = sprintf(__d('acl', 'Created Aco node for %s'), $controller_name); + } + } + else + { + $controllerNode = $controllerNode[0]; + } + + + /****************************************** + * Check controller actions node + */ + $actions = $this->AclReflector->get_controller_actions($controller_name); + + foreach($actions as $action) + { + $actionNode = $aco->node('controllers/' . (!empty($plugin_name) ? $plugin_name . '/' : '') . $controller_name . '/' . $action); + + if(empty($actionNode)) + { + /* + * action node does not exist -> create it + */ + + $aco->create(array('parent_id' => $controllerNode['Aco']['id'], 'model' => null, 'alias' => $action)); + $methodNode = $aco->save(); + + $log[] = sprintf(__d('acl', 'Created Aco node for %s'), (!empty($plugin_name) ? $plugin_name . '/' : '') . $controller_name . '/' . $action); + } + } + } + } + + return $log; + } + + public function update_controllers_hash_file() + { + $current_controller_hashes = $this->get_current_controllers_hashes(); + + $file = new File($this->controllers_hash_file); + $file->write(serialize($current_controller_hashes)); + } + + public function controller_hash_file_is_out_of_sync() + { + if($this->check_controller_hash_tmp_file()) + { + $stored_controller_hashes = $this->get_stored_controllers_hashes(); + $current_controller_hashes = $this->get_current_controllers_hashes(); + + /* + * Check what controllers have changed + */ + $updated_controllers = array_keys(Set :: diff($current_controller_hashes, $stored_controller_hashes)); + + return !empty($updated_controllers); + } + } + + public function get_acos_to_prune() + { + $actions = $this->AclReflector->get_all_actions(); + $controllers = $this->AclReflector->get_all_controllers(); + $plugins = $this->AclReflector->get_all_plugins_names(); + + $actions_aco_paths = array(); + foreach($actions as $action) + { + $actions_aco_paths[] = 'controllers/' . $action; + } + foreach($controllers as $controller) + { + $actions_aco_paths[] = 'controllers/' . $controller['name']; + } + foreach($plugins as $plugin) + { + $actions_aco_paths[] = 'controllers/' . $plugin; + } + $actions_aco_paths[] = 'controllers'; + + $aco =& $this->Acl->Aco; + + $acos = $aco->find('all', array('recursive' => -1)); + + $existing_aco_paths = array(); + foreach($acos as $aco_node) + { + $path_nodes = $aco->getPath($aco_node['Aco']['id']); + + if(count($path_nodes) > 1 && $path_nodes[0]['Aco']['alias'] == 'controllers') + { + $path = ''; + foreach($path_nodes as $path_node) + { + $path .= '/' . $path_node['Aco']['alias']; + } + + $path = substr($path, 1); + $existing_aco_paths[] = $path; + } + } + + $paths_to_prune = array_diff($existing_aco_paths, $actions_aco_paths); + + return $paths_to_prune; + } + + /** + * Remove all ACOs that don't have any corresponding controllers or actions. + * + * @return array log of removed ACO nodes + */ + public function prune_acos() + { + $aco =& $this->Acl->Aco; + + $log = array(); + + $paths_to_prune = $this->get_acos_to_prune(); + + foreach($paths_to_prune as $path_to_prune) + { + $node = $aco->node($path_to_prune); + if(!empty($node)) + { + /* + * First element is the last part in path + * -> we delete it + */ + if($aco->delete($node[0]['Aco']['id'])) + { + $log[] = sprintf(__d('acl', "Aco node '%s' has been deleted"), $path_to_prune); + } + else + { + $log[] = '' . sprintf(__d('acl', "Aco node '%s' could not be deleted"), $path_to_prune) . ''; + } + } + } + + return $log; + } + + /** + * + * @param AclNode $aro_nodes The Aro model hierarchy + * @param string $aco_path The Aco path to check for + * @param string $permission_type 'deny' or 'allow', 'grant', depending on what permission (grant or deny) is being set + */ + public function save_permission($aro_nodes, $aco_path, $permission_type) + { + if(isset($aro_nodes[0])) + { + $aco_path = 'controllers/' . $aco_path; + + $pk_name = 'id'; + if($aro_nodes[0]['Aro']['model'] == Configure :: read('acl.aro.role.model')) + { + $pk_name = $this->controller->_get_role_primary_key_name(); + } + elseif($aro_nodes[0]['Aro']['model'] == Configure :: read('acl.aro.user.model')) + { + $pk_name = $this->controller->_get_user_primary_key_name(); + } + + $aro_model_data = array($aro_nodes[0]['Aro']['model'] => array($pk_name => $aro_nodes[0]['Aro']['foreign_key'])); + $aro_id = $aro_nodes[0]['Aro']['id']; + + $specific_permission_right = $this->get_specific_permission_right($aro_nodes[0], $aco_path); + $inherited_permission_right = $this->get_first_parent_permission_right($aro_nodes[0], $aco_path); + + if(!isset($inherited_permission_right) && count($aro_nodes) > 1) + { + /* + * Get the permission inherited by the parent ARO + */ + $specific_parent_aro_permission_right = $this->get_specific_permission_right($aro_nodes[1], $aco_path); + + if(isset($specific_parent_aro_permission_right)) + { + /* + * If there is a specific permission for the parent ARO on the ACO, the child ARO inheritates this permission + */ + $inherited_permission_right = $specific_parent_aro_permission_right; + } + else + { + $inherited_permission_right = $this->get_first_parent_permission_right($aro_nodes[1], $aco_path); + } + } + + /* + * Check if the specific permission is necessary to get the correct permission + */ + if(!isset($inherited_permission_right)) + { + $specific_permission_needed = true; + } + else + { + if($permission_type == 'allow' || $permission_type == 'grant') + { + $specific_permission_needed = ($inherited_permission_right != 1); + } + else + { + $specific_permission_needed = ($inherited_permission_right == 1); + } + } + + if($specific_permission_needed) + { + if($permission_type == 'allow' || $permission_type == 'grant') + { + if($this->Acl->allow($aro_model_data, $aco_path)) + { + return true; + } + else + { + trigger_error(__d('acl', 'An error occured while saving the specific permission'), E_USER_NOTICE); + return false; + } + } + else + { + if($this->Acl->deny($aro_model_data, $aco_path)) + { + return true; + } + else + { + trigger_error(__d('acl', 'An error occured while saving the specific permission'), E_USER_NOTICE); + return false; + } + } + } + elseif(isset($specific_permission_right)) + { + $aco_node = $this->Acl->Aco->node($aco_path); + if(!empty($aco_node)) + { + $aco_id = $aco_node[0]['Aco']['id']; + + $specific_permission = $this->Acl->Aro->Permission->find('first', array('conditions' => array('aro_id' => $aro_id, 'aco_id' => $aco_id))); + + if($specific_permission !== false) + { + if($this->Acl->Aro->Permission->delete(array('Permission.id' => $specific_permission['Permission']['id']))) + { + return true; + } + else + { + trigger_error(__d('acl', 'An error occured while deleting the specific permission'), E_USER_NOTICE); + return false; + } + } + else + { + /* + * As $specific_permission_right has a value, we should never fall here, but who knows... ;-) + */ + + trigger_error(__d('acl', 'The specific permission id could not be retrieved'), E_USER_NOTICE); + return false; + } + } + else + { + /* + * As $specific_permission_right has a value, we should never fall here, but who knows... ;-) + */ + trigger_error(__d('acl', 'The child ACO id could not be retrieved'), E_USER_NOTICE); + return false; + } + } + else + { + /* + * Right can be inherited, and no specific permission exists => there is nothing to do... + */ + } + } + else + { + trigger_error(__d('acl', 'Invalid ARO'), E_USER_NOTICE); + return false; + } + } + + private function get_specific_permission_right($aro_node, $aco_path) + { + $pk_name = 'id'; + if($aro_node['Aro']['model'] == Configure :: read('acl.aro.role.model')) + { + $pk_name = $this->controller->_get_role_primary_key_name(); + } + elseif($aro_node['Aro']['model'] == Configure :: read('acl.aro.user.model')) + { + $pk_name = $this->controller->_get_user_primary_key_name(); + } + + $aro_model_data = array($aro_node['Aro']['model'] => array($pk_name => $aro_node['Aro']['foreign_key'])); + $aro_id = $aro_node['Aro']['id']; + + /* + * Check if a specific permission of the ARO's on the ACO already exists in the datasource + * => + * 1) the ACO node must exist in the ACO table + * 2) a record with the aro_id and aco_id must exist in the aros_acos table + */ + $aco_id = null; + $specific_permission = null; + $specific_permission_right = null; + + $aco_node = $this->Acl->Aco->node($aco_path); + if(!empty($aco_node)) + { + $aco_id = $aco_node[0]['Aco']['id']; + + $specific_permission = $this->Acl->Aro->Permission->find('first', array('conditions' => array('aro_id' => $aro_id, 'aco_id' => $aco_id))); + + if($specific_permission !== false) + { + /* + * Check the right (grant => true / deny => false) of this specific permission + */ + $specific_permission_right = $this->Acl->check($aro_model_data, $aco_path); + + if($specific_permission_right) + { + return 1; // allowed + } + else + { + return -1; // denied + } + } + } + + return null; // no specific permission found + } + + private function get_first_parent_permission_right($aro_node, $aco_path) + { + $pk_name = 'id'; + if($aro_node['Aro']['model'] == Configure :: read('acl.aro.role.model')) + { + $pk_name = $this->controller->_get_role_primary_key_name(); + } + elseif($aro_node['Aro']['model'] == Configure :: read('acl.aro.user.model')) + { + $pk_name = $this->controller->_get_user_primary_key_name(); + } + + $aro_model_data = array($aro_node['Aro']['model'] => array($pk_name => $aro_node['Aro']['foreign_key'])); + $aro_id = $aro_node['Aro']['id']; + + while(strpos($aco_path, '/') !== false && !isset($parent_permission_right)) + { + $aco_path = substr($aco_path, 0, strrpos($aco_path, '/')); + + $parent_aco_node = $this->Acl->Aco->node($aco_path); + if(!empty($parent_aco_node)) + { + $parent_aco_id = $parent_aco_node[0]['Aco']['id']; + + $parent_permission = $this->Acl->Aro->Permission->find('first', array('conditions' => array('aro_id' => $aro_id, 'aco_id' => $parent_aco_id))); + + if($parent_permission !== false) + { + /* + * Check the right (grant => true / deny => false) of this first parent permission + */ + $parent_permission_right = $this->Acl->check($aro_model_data, $aco_path); + + if($parent_permission_right) + { + return 1; // allowed + } + else + { + return -1; // denied + } + } + } + } + + return null; // no parent permission found + } + + /** + * Set the permissions of the authenticated user in Session + * The session permissions are then used for instance by the AclHtmlHelper->link() function + */ + public function set_session_permissions() + { + if(!$this->Session->check('Alaxos.Acl.permissions')) + { + $actions = $this->AclReflector->get_all_actions(); + + $user = $this->Auth->user(); + + if(!empty($user)) + { + $user = array(Configure :: read('acl.aro.user.model') => $user); + $permissions = array(); + + foreach($actions as $action) + { + $aco_path = 'controllers/' . $action; + + $permissions[$aco_path] = $this->Acl->check($user, $aco_path); + } + + $this->Session->write('Alaxos.Acl.permissions', $permissions); + } + } + } +} \ No newline at end of file diff --git a/Controller/Component/AclReflectorComponent.php b/Controller/Component/AclReflectorComponent.php new file mode 100644 index 0000000..a0f56b0 --- /dev/null +++ b/Controller/Component/AclReflectorComponent.php @@ -0,0 +1,280 @@ +controller = $controller; + } + + /****************************************************************************************/ + + public function getPluginName($ctrlName = null) + { + $arr = String::tokenize($ctrlName, '/'); + if (count($arr) == 2) { + return $arr[0]; + } else { + return false; + } + } + public function getPluginControllerName($ctrlName = null) + { + $arr = String::tokenize($ctrlName, '/'); + if (count($arr) == 2) { + return $arr[1]; + } else { + return false; + } + } + public function get_controller_classname($controller_name) + { + if(strrpos($controller_name, 'Controller') !== strlen($controller_name) - strlen('Controller')) + { + /* + * If $controller does not already end with 'Controller' + */ + + if(stripos($controller_name, '/') === false) + { + $controller_classname = $controller_name . 'Controller'; + } + else + { + /* + * Case of plugin controller + */ + $controller_classname = substr($controller_name, strripos($controller_name, '/') + 1) . 'Controller'; + } + + return $controller_classname; + } + else + { + return $controller_name; + } + } + + /****************************************************************************************/ + + public function get_all_plugins_paths() + { + $plugin_names = CakePlugin::loaded(); + + $plugin_paths = array(); + foreach($plugin_names as $plugin_name) + { + $plugin_paths[] = CakePlugin::path($plugin_name); + } + + return $plugin_paths; + } + public function get_all_plugins_names() + { + $plugin_names = array(); + + $plugin_paths = $this->get_all_plugins_paths(); + foreach($plugin_paths as $plugin_path) + { + $path_parts = explode('/', $plugin_path); + for($i = count($path_parts)-1; $i >= 0; $i--) + { + if(!empty($path_parts[$i])) + { + $plugin_names[] = $path_parts[$i]; + break; + } + } + } + + return $plugin_names; + } + public function get_all_plugins_controllers($filter_default_controller = false) + { + $plugin_paths = $this->get_all_plugins_paths(); + + $plugins_controllers = array(); + $folder = new Folder(); + + // Loop through the plugins + foreach($plugin_paths as $plugin_path) + { + $didCD = $folder->cd($plugin_path . DS . 'Controller'); + + if(!empty($didCD)) + { + $files = $folder->findRecursive('.*Controller\.php'); + + if(strrpos($plugin_path, DS) == strlen($plugin_path) - 1) + { + $plugin_path = substr($plugin_path, 0, strlen($plugin_path) - 1); + } + + $plugin_name = substr($plugin_path, strrpos($plugin_path, DS) + 1); + + foreach($files as $fileName) + { + $file = basename($fileName); + + // Get the controller name + $controller_class_name = Inflector::camelize(substr($file, 0, strlen($file) - strlen('.php'))); + + if(!$filter_default_controller || Inflector::camelize($plugin_name) . 'Controller' != $controller_class_name) + { + App::uses($controller_class_name, $plugin_name . '.Controller'); + + if (!preg_match('/^'. Inflector::camelize($plugin_name) . 'App/', $controller_class_name)) + { + $plugins_controllers[] = array('file' => $fileName, 'name' => Inflector::camelize($plugin_name) . "/" . substr($controller_class_name, 0, strlen($controller_class_name) - strlen('Controller'))); + } + } + } + } + } + + sort($plugins_controllers); + + return $plugins_controllers; + } + public function get_all_plugins_controllers_actions($filter_default_controller = false) + { + $plugin_controllers = $this->get_all_plugins_controllers(); + + $plugin_controllers_actions = array(); + + foreach($plugin_controllers as $plugin_controller) + { + $plugin_name = $this->getPluginName($plugin_controller['name']); + $controller_name = $this->getPluginControllerName($plugin_controller['name']); + + if(!$filter_default_controller || $plugin_name != $controller_name) + { + $controller_class_name = $controller_name . 'Controller'; + + $ctrl_cleaned_methods = $this->get_controller_actions($controller_class_name); + + foreach($ctrl_cleaned_methods as $action) + { + $plugin_controllers_actions[] = $plugin_name . '/' . $controller_name . '/' . $action; + } + } + } + + sort($plugin_controllers_actions); + + return $plugin_controllers_actions; + } + + public function get_all_app_controllers() + { + $controllers = array(); + + App::uses('Folder', 'Utility'); + $folder = new Folder(); + + $didCD = $folder->cd(APP . 'Controller'); + if(!empty($didCD)) + { + $files = $folder->findRecursive('.*Controller\.php'); + + foreach($files as $fileName) + { + $file = basename($fileName); + + // Get the controller name + //$controller_class_name = Inflector::camelize(substr($file, 0, strlen($file) - strlen('Controller.php'))); + + $controller_class_name = Inflector::camelize(substr($file, 0, strlen($file) - strlen('.php'))); + App::uses($controller_class_name, 'Controller'); + + $controllers[] = array('file' => $fileName, 'name' => substr($controller_class_name, 0, strlen($controller_class_name) - strlen('Controller'))); + } + } + + sort($controllers); + + return $controllers; + } + public function get_all_app_controllers_actions() + { + $controllers = $this->get_all_app_controllers(); + + $controllers_actions = array(); + + foreach($controllers as $controller) + { + $controller_class_name = $controller['name']; + + $ctrl_cleaned_methods = $this->get_controller_actions($controller_class_name); + + foreach($ctrl_cleaned_methods as $action) + { + $controllers_actions[] = $controller['name'] . '/' . $action; + } + } + + sort($controllers_actions); + + return $controllers_actions; + } + + public function get_all_controllers() + { + $app_controllers = $this->get_all_app_controllers(); + $plugin_controllers = $this->get_all_plugins_controllers(); + + return array_merge($app_controllers, $plugin_controllers); + } + public function get_all_actions() + { + $app_controllers_actions = $this->get_all_app_controllers_actions(); + $plugins_controllers_actions = $this->get_all_plugins_controllers_actions(); + + return array_merge($app_controllers_actions, $plugins_controllers_actions); + } + + /** + * Return the methods of a given class name. + * Depending on the $filter_base_methods parameter, it can return the parent methods. + * + * @param string $controller_class_name (eg: 'AcosController') + * @param boolean $filter_base_methods + */ + public function get_controller_actions($controller_classname, $filter_base_methods = true) + { + $controller_classname = $this->get_controller_classname($controller_classname); + + $methods = get_class_methods($controller_classname); + + if(isset($methods) && !empty($methods)) + { + if($filter_base_methods) + { + $baseMethods = get_class_methods('Controller'); + + $ctrl_cleaned_methods = array(); + foreach($methods as $method) + { + if(!in_array($method, $baseMethods) && strpos($method, '_') !== 0) + { + $ctrl_cleaned_methods[] = $method; + } + } + + return $ctrl_cleaned_methods; + } + else + { + return $methods; + } + } + else + { + return array(); + } + } + +} \ No newline at end of file diff --git a/Controller/Component/empty b/Controller/Component/empty new file mode 100644 index 0000000..e69de29 diff --git a/Lib/AclRouter.php b/Lib/AclRouter.php new file mode 100644 index 0000000..c8ef1ec --- /dev/null +++ b/Lib/AclRouter.php @@ -0,0 +1,31 @@ + +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"POT-Creation-Date: 2011-07-13 14:27+0200\n" +"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n" +"Last-Translator: NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#: acl_app_controller.php:73 +msgid "The role model name is unknown. The ACL plugin bootstrap.php file has to be loaded in order to work. (see the README file)" +msgstr "" + +#: controllers/acos_controller.php:24 +msgid "The ACO table has been cleared" +msgstr "" + +#: controllers/acos_controller.php:28 +msgid "The ACO table could not be cleared" +msgstr "" + +#: controllers/aros_controller.php:203 +msgid "The user role has been updated" +msgstr "" + +#: controllers/aros_controller.php:207 +msgid "The user role could not be updated" +msgstr "" + +#: controllers/aros_controller.php:384;479 +msgid "The user '%s' does not exist in the ARO table" +msgstr "" + +#: controllers/aros_controller.php:457 +msgid "The permissions have been cleared" +msgstr "" + +#: controllers/aros_controller.php:461 +msgid "The permissions could not be cleared" +msgstr "" + +#: controllers/aros_controller.php:485 +msgid "The specific permissions have been cleared" +msgstr "" + +#: controllers/aros_controller.php:489 +msgid "The specific permissions could not be cleared" +msgstr "" + +#: controllers/aros_controller.php:508;530 +msgid "The role '%s' does not exist in the ARO table" +msgstr "" + +#: controllers/components/acl_manager.php:37 +msgid "the %s directory is not writable" +msgstr "" + +#: controllers/components/acl_manager.php:264 +msgid "Created Aco node for controllers" +msgstr "" + +#: controllers/components/acl_manager.php:300 +msgid "Created Aco node for %s plugin" +msgstr "" + +#: controllers/components/acl_manager.php:327 +msgid "Created Aco node for %s/%s" +msgstr "" + +#: controllers/components/acl_manager.php:339;366 +msgid "Created Aco node for %s" +msgstr "" + +#: controllers/components/acl_manager.php:451;463 +msgid "An error occured while saving the specific permission" +msgstr "" + +#: controllers/components/acl_manager.php:485 +msgid "An error occured while deleting the specific permission" +msgstr "" + +#: controllers/components/acl_manager.php:495 +msgid "The specific permission id could not be retrieved" +msgstr "" + +#: controllers/components/acl_manager.php:504 +msgid "The child ACO id could not be retrieved" +msgstr "" + +#: controllers/components/acl_manager.php:517 +msgid "Invalid ARO" +msgstr "" + +#: views/acos/admin_acos_missing.ctp:8 +msgid "Some controllers have been modified, resulting in actions that are not referenced as ACO in the database." +msgstr "" + +#: views/acos/admin_acos_missing.ctp:15 +msgid "You can update the ACOs by clicking on the following link" +msgstr "" + +#: views/acos/admin_acos_missing.ctp:16 +msgid "Build missing ACOs" +msgstr "" + +#: views/acos/admin_acos_missing.ctp:20 +msgid "Please be aware that this message will appear only once. But you can always rebuild the ACOs by going to the ACO tab." +msgstr "" + +#: views/acos/admin_build_acl.ctp:15 +msgid "The following actions ACOs have been created" +msgstr "" + +#: views/acos/admin_build_acl.ctp:22 +msgid "There was no new actions ACOs to create" +msgstr "" + +#: views/acos/admin_build_acl.ctp:29 +msgid "This page allows you to build missing actions ACOs if any." +msgstr "" + +#: views/acos/admin_build_acl.ctp:33 +msgid "Clicking the link will not destroy existing actions ACOs." +msgstr "" + +#: views/acos/admin_build_acl.ctp:37 +#: views/aros/admin_check.ctp:43 +msgid "Build" +msgstr "" + +#: views/acos/admin_empty_acos.ctp:12 +msgid "This page allows you to clear all actions ACOs." +msgstr "" + +#: views/acos/admin_empty_acos.ctp:16 +msgid "Clicking the link will destroy all existing actions ACOs and associated permissions." +msgstr "" + +#: views/acos/admin_empty_acos.ctp:20 +msgid "Clear ACOs" +msgstr "" + +#: views/acos/admin_empty_acos.ctp:20 +msgid "Are you sure you want to destroy all existing ACOs ?" +msgstr "" + +#: views/aros/admin_ajax_role_permissions.ctp:17 +#: views/aros/admin_role_permissions.ctp:17 +msgid "Clear permissions table" +msgstr "" + +#: views/aros/admin_ajax_role_permissions.ctp:17 +#: views/aros/admin_role_permissions.ctp:17 +msgid "Are you sure you want to delete all roles and users permissions ?" +msgstr "" + +#: views/aros/admin_ajax_role_permissions.ctp:29 +#: views/aros/admin_role_permissions.ctp:29 +msgid "grant access to all actions" +msgstr "" + +#: views/aros/admin_ajax_role_permissions.ctp:30 +#: views/aros/admin_role_permissions.ctp:30 +msgid "deny access to all actions" +msgstr "" + +#: views/aros/admin_ajax_role_permissions.ctp:40 +#: views/aros/admin_role_permissions.ctp:40 +msgid "Are you sure you want to grant access to all actions of each controller to the role '%s' ?" +msgstr "" + +#: views/aros/admin_ajax_role_permissions.ctp:41 +#: views/aros/admin_role_permissions.ctp:41 +msgid "Are you sure you want to deny access to all actions of each controller to the role '%s' ?" +msgstr "" + +#: views/aros/admin_ajax_role_permissions.ctp:59 +#: views/aros/admin_ajax_user_permissions.ctp:60 +#: views/aros/admin_role_permissions.ctp:59 +#: views/aros/admin_user_permissions.ctp:119 +msgid "action" +msgstr "" + +#: views/aros/admin_ajax_role_permissions.ctp:102;168 +#: views/aros/admin_ajax_user_permissions.ctp:92;139 +msgid "loading" +msgstr "" + +#: views/aros/admin_ajax_role_permissions.ctp:107;173 +#: views/aros/admin_ajax_user_permissions.ctp:97;144 +#: views/aros/admin_role_permissions.ctp:118;200 +#: views/aros/ajax_role_denied.ctp:6 +#: views/aros/ajax_role_granted.ctp:6 +#: views/aros/ajax_user_denied.ctp:12 +#: views/aros/ajax_user_granted.ctp:12 +msgid "The ACO node is probably missing. Please try to rebuild the ACOs first." +msgstr "" + +#: views/aros/admin_ajax_role_permissions.ctp:136 +#: views/aros/admin_ajax_user_permissions.ctp:114 +#: views/aros/admin_role_permissions.ctp:147 +#: views/aros/admin_user_permissions.ctp:182 +msgid "Plugin" +msgstr "" + +#: views/aros/admin_ajax_role_permissions.ctp:195 +#: views/aros/admin_ajax_user_permissions.ctp:161 +#: views/aros/admin_role_permissions.ctp:222 +#: views/aros/admin_user_permissions.ctp:240 +msgid "authorized" +msgstr "" + +#: views/aros/admin_ajax_role_permissions.ctp:197 +#: views/aros/admin_ajax_user_permissions.ctp:163 +#: views/aros/admin_role_permissions.ctp:224 +#: views/aros/admin_user_permissions.ctp:242 +msgid "blocked" +msgstr "" + +#: views/aros/admin_ajax_user_permissions.ctp:12 +msgid "User" +msgstr "" + +#: views/aros/admin_ajax_user_permissions.ctp:14 +#: views/aros/admin_user_permissions.ctp:73 +msgid "Role" +msgstr "" + +#: views/aros/admin_ajax_user_permissions.ctp:30 +#: views/aros/admin_user_permissions.ctp:89 +#: views/aros/admin_users.ctp:52 +msgid "Update the user role" +msgstr "" + +#: views/aros/admin_ajax_user_permissions.ctp:40 +#: views/aros/admin_user_permissions.ctp:99 +#: views/elements/design/header.ctp:19 +msgid "Permissions" +msgstr "" + +#: views/aros/admin_ajax_user_permissions.ctp:46 +#: views/aros/admin_user_permissions.ctp:105 +msgid "This user has specific permissions" +msgstr "" + +#: views/aros/admin_ajax_user_permissions.ctp:48 +#: views/aros/admin_user_permissions.ctp:107 +msgid "Clear" +msgstr "" + +#: views/aros/admin_ajax_user_permissions.ctp:48 +#: views/aros/admin_user_permissions.ctp:107 +msgid "Are you sure you want to clear the permissions specific to this user ?" +msgstr "" + +#: views/aros/admin_ajax_user_permissions.ctp:60 +#: views/aros/admin_user_permissions.ctp:119 +msgid "authorization" +msgstr "" + +#: views/aros/admin_check.ctp:12 +msgid "Roles without corresponding Aro" +msgstr "" + +#: views/aros/admin_check.ctp:27 +msgid "Users without corresponding Aro" +msgstr "" + +#: views/aros/admin_check.ctp:49 +msgid "There is no missing ARO." +msgstr "" + +#: views/aros/admin_not_acl_requester.ctp:11;18 +msgid "The %s model is not configured to act as an ACL requester" +msgstr "" + +#: views/aros/admin_not_acl_requester.ctp:25 +msgid "In a classical ACL configuration, the models that represent the users and the roles must act as ACL requesters (see %s)." +msgstr "" + +#: views/aros/admin_not_acl_requester.ctp:26 +msgid "Acts As a Requester" +msgstr "" + +#: views/aros/admin_not_acl_requester.ctp:30 +msgid "If you wish, you can disable this alert by setting the ACL plugin parameter 'acl.check_act_as_requester' to false." +msgstr "" + +#: views/aros/admin_user_permissions.ctp:19 +msgid "This page allows to manage users specific rights" +msgstr "" + +#: views/aros/admin_user_permissions.ctp:25;37 +msgid "user" +msgstr "" + +#: views/aros/admin_user_permissions.ctp:29 +#: views/aros/admin_users.ctp:15 +msgid "filter" +msgstr "" + +#: views/aros/admin_user_permissions.ctp:47 +msgid "Manage user specific rights" +msgstr "" + +#: views/aros/admin_users.ctp:11;23 +msgid "name" +msgstr "" + +#: views/aros/admin_users.ctp:76 +msgid "Some users AROS are missing. Click on a role to assign one to a user." +msgstr "" + +#: views/aros/ajax_role_denied.ctp:6 +#: views/aros/ajax_role_granted.ctp:6 +msgid "The role node does not exist in the ARO table" +msgstr "" + +#: views/aros/ajax_user_denied.ctp:8 +#: views/aros/ajax_user_granted.ctp:8 +msgid "The user node does not exist in the ARO table" +msgstr "" + +#: views/aros/ajax_user_denied.ctp:16 +#: views/aros/ajax_user_granted.ctp:16 +msgid "The ARO or the ACO node is probably missing. Please try to rebuild the ACOs first." +msgstr "" + +#: views/elements/acos/links.ctp:6 +msgid "Build actions ACOs" +msgstr "" + +#: views/elements/acos/links.ctp:7 +msgid "Clear actions ACOs" +msgstr "" + +#: views/elements/acos/links.ctp:7 +msgid "are you sure ?" +msgstr "" + +#: views/elements/aros/links.ctp:6 +msgid "Build missing AROs" +msgstr "" + +#: views/elements/aros/links.ctp:7 +msgid "Users roles" +msgstr "" + +#: views/elements/aros/links.ctp:11;15 +msgid "Roles permissions" +msgstr "" + +#: views/elements/aros/links.ctp:17 +msgid "Users permissions" +msgstr "" + +#: views/elements/design/header.ctp:10 +msgid "ACL plugin" +msgstr "" + +#: views/elements/design/header.ctp:20 +msgid "Actions" +msgstr "" + +#: views/errors/missing_aco_nodes.ctp:7 +msgid "go to homepage" +msgstr "" + diff --git a/Locale/eng/LC_MESSAGES/empty b/Locale/eng/LC_MESSAGES/empty new file mode 100644 index 0000000..e69de29 diff --git a/Locale/fre/LC_MESSAGES/acl.po b/Locale/fre/LC_MESSAGES/acl.po new file mode 100644 index 0000000..37c1fba --- /dev/null +++ b/Locale/fre/LC_MESSAGES/acl.po @@ -0,0 +1,518 @@ +# LANGUAGE translation of CakePHP Application +# Copyright YEAR NAME +# +msgid "" +msgstr "" +"Project-Id-Version: ACL plugin\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-01 12:50+0100\n" +"PO-Revision-Date: 2012-02-01 12:53+0100\n" +"Last-Translator: Nicolas Rod \n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" +"X-Poedit-Language: French\n" +"X-Poedit-Basepath: /home/rodn/workspace/caketest2/plugins/Acl/\n" +"X-Poedit-KeywordsList: __;___;__n;__d:2;__c;__dc;__dn;__dcn\n" +"X-Poedit-SearchPath-0: Controller\n" +"X-Poedit-SearchPath-1: View\n" + +#: Controller/AclAppController.php:74 +msgid "The role model name is unknown. The ACL plugin bootstrap.php file has to be loaded in order to work. (see the README file)" +msgstr "Le nom du modèle servant de rôle est inconnu. Le fichier bootstrap.php du plugin ACL doit être chargé pour que le plugin fonctionne. (voir fichier README)" + +#: Controller/AcosController.php:26 +msgid "The actions in the ACO table have been deleted" +msgstr "Les actions dans la table ACO ont été effacées" + +#: Controller/AcosController.php:30 +msgid "The actions in the ACO table could not be deleted" +msgstr "Les actions dans la table ACO n'ont pas pu être effacées" + +#: Controller/ArosController.php:202 +msgid "The user role has been updated" +msgstr "Le rôle de l'utilisateur a été modifié" + +#: Controller/ArosController.php:206 +msgid "The user role could not be updated" +msgstr "Le rôle de l'utilisateur n'a pas pu être mis à jour" + +#: Controller/ArosController.php:383 +#: Controller/ArosController.php:478 +#, php-format +msgid "The user '%s' does not exist in the ARO table" +msgstr "L'utilisateur '%s' n'existe pas dans la table des AROs" + +#: Controller/ArosController.php:456 +msgid "The permissions have been cleared" +msgstr "Les permissions ont été effacées" + +#: Controller/ArosController.php:460 +msgid "The permissions could not be cleared" +msgstr "Les permissions ont été effacées" + +#: Controller/ArosController.php:484 +msgid "The specific permissions have been cleared" +msgstr "Les permissions spécifiques de l'utilisateur ont été effacées" + +#: Controller/ArosController.php:488 +msgid "The specific permissions could not be cleared" +msgstr "Les permissions spécifiques de l'utilisateur n'ont pas pu être effacées" + +#: Controller/ArosController.php:507 +#: Controller/ArosController.php:529 +#, php-format +msgid "The role '%s' does not exist in the ARO table" +msgstr "Le rôle '%s' n'existe pas dans la table des AROs" + +#: Controller/Component/AclManagerComponent.php:41 +#, php-format +msgid "the %s directory is not writable" +msgstr "le dossier %s est interdit en écriture" + +#: Controller/Component/AclManagerComponent.php:274 +msgid "Created Aco node for controllers" +msgstr "noeud ACO créé pour les contrôleurs" + +#: Controller/Component/AclManagerComponent.php:312 +#, php-format +msgid "Created Aco node for %s plugin" +msgstr "noeud ACO créé pour le plugin %s" + +#: Controller/Component/AclManagerComponent.php:339 +#, php-format +msgid "Created Aco node for %s/%s" +msgstr "noeud ACO créé pour %s/%s" + +#: Controller/Component/AclManagerComponent.php:351 +#: Controller/Component/AclManagerComponent.php:378 +#, php-format +msgid "Created Aco node for %s" +msgstr "noeud ACO créé pour %s" + +#: Controller/Component/AclManagerComponent.php:479 +#, php-format +msgid "Aco node '%s' has been deleted" +msgstr "Le noeud ACO '%s' a été effacé" + +#: Controller/Component/AclManagerComponent.php:483 +#, php-format +msgid "Aco node '%s' could not be deleted" +msgstr "Le noeud ACO '%s' n'a pas pu être effacé" + +#: Controller/Component/AclManagerComponent.php:568 +#: Controller/Component/AclManagerComponent.php:580 +msgid "An error occured while saving the specific permission" +msgstr "Une erreur est survenue en sauvant la permission spécifique" + +#: Controller/Component/AclManagerComponent.php:602 +msgid "An error occured while deleting the specific permission" +msgstr "Une erreur est survenue en effaçant la permission spécifique" + +#: Controller/Component/AclManagerComponent.php:612 +msgid "The specific permission id could not be retrieved" +msgstr "La permission spécifique n'a pas été trouvée" + +#: Controller/Component/AclManagerComponent.php:621 +msgid "The child ACO id could not be retrieved" +msgstr "L'élément ACO enfant n'a pas été trouvé" + +#: Controller/Component/AclManagerComponent.php:634 +msgid "Invalid ARO" +msgstr "ARO invalide" + +#: View/Elements/Acos/links.ctp:6 +msgid "Synchronize actions ACOs" +msgstr "Synchroniser les ACOs" + +#: View/Elements/Acos/links.ctp:6 +#: View/Elements/Acos/links.ctp:7 +#: View/Elements/Acos/links.ctp:9 +msgid "are you sure ?" +msgstr "êtes-vous sûr ?" + +#: View/Elements/Acos/links.ctp:7 +msgid "Clear actions ACOs" +msgstr "Destruction des ACOs" + +#: View/Elements/Acos/links.ctp:8 +msgid "Build actions ACOs" +msgstr "Compléter les ACOs" + +#: View/Elements/Acos/links.ctp:9 +msgid "Prune actions ACOs" +msgstr "Nettoyer les ACOs" + +#: View/Elements/Aros/links.ctp:6 +msgid "Build missing AROs" +msgstr "Compléter les AROs" + +#: View/Elements/Aros/links.ctp:7 +msgid "Users roles" +msgstr "Rôles des utilisateurs" + +#: View/Elements/Aros/links.ctp:11 +#: View/Elements/Aros/links.ctp:15 +msgid "Roles permissions" +msgstr "Permissions des rôles" + +#: View/Elements/Aros/links.ctp:17 +msgid "Users permissions" +msgstr "Permissions des utilisateurs" + +#: View/Elements/design/header.ctp:10 +msgid "ACL plugin" +msgstr "Plugin ACL" + +#: View/Elements/design/header.ctp:19 +msgid "Permissions" +msgstr "Permissions" + +#: View/Elements/design/header.ctp:20 +msgid "Actions" +msgstr "Actions" + +#: View/Errors/missing_aco_nodes.ctp:7 +msgid "go to homepage" +msgstr "aller à la page d'accueil" + +#: View/Acos/admin_has_updates.ctp:8 +msgid "Some controllers have been modified, resulting in actions that are not referenced as ACO in the database or ACO records that are obsolete" +msgstr "Certains contrôleurs ont été modifiés. En conséquence certaines actions ne sont pas référencées dans la table des ACO ou au contraire ne devraient plus l'être" + +#: View/Acos/admin_has_updates.ctp:12 +#: View/Acos/admin_synchronize.ctp:56 +msgid "Missing ACOs" +msgstr "ACOs manquants " + +#: View/Acos/admin_has_updates.ctp:21 +#: View/Acos/admin_synchronize.ctp:28 +msgid "Obsolete ACOs" +msgstr "ACOs obsolètes" + +#: View/Acos/admin_has_updates.ctp:29 +msgid "You can update the ACOs by clicking on the following link" +msgstr "Vous pouvez mettre à jour les ACOs en cliquant sur le lien suivant" + +#: View/Acos/admin_has_updates.ctp:30 +msgid "Synchronize ACOs" +msgstr "Synchroniser les ACOs" + +#: View/Acos/admin_has_updates.ctp:34 +msgid "Please be aware that this message will appear only once. But you can always rebuild the ACOs by going to the ACO tab." +msgstr "Veuillez noter que ce message n'apparaîtra qu'une seule fois. Vous pouvez cependant compléter les ACOs à tout moment en vous rendant sur l'onglet des Actions." + +#: View/Acos/admin_synchronize.ctp:12 +msgid "New ACOs" +msgstr "Nouveaux ACOs" + +#: View/Acos/admin_synchronize.ctp:17 +msgid "The following actions ACOs have been created" +msgstr "Les ACOs pour les actions suivantes ont été créés" + +#: View/Acos/admin_synchronize.ctp:24 +msgid "There was no new actions ACOs to create" +msgstr "Aucune nouvelle action à créer comme ACO n'a été trouvée" + +#: View/Acos/admin_synchronize.ctp:33 +msgid "The following actions ACOs have been deleted" +msgstr "Les ACOs pour les actions suivantes ont été effacés" + +#: View/Acos/admin_synchronize.ctp:40 +msgid "There was no action ACO to delete" +msgstr "Aucun noeud ACO à effacer n'a été trouvé" + +#: View/Acos/admin_synchronize.ctp:47 +msgid "This page allows you to synchronize the existing controllers and actions with the ACO datatable." +msgstr "Cette page permet de synchroniser les contrôleurs et les actions existantes avec la table des ACOs." + +#: View/Acos/admin_synchronize.ctp:67 +msgid "Obsolete ACO nodes" +msgstr "Noeuds ACO obsolètes" + +#: View/Acos/admin_synchronize.ctp:81 +msgid "Clicking the link will not change or remove permissions for existing actions ACOs." +msgstr "Cliquer sur le lien ne modifiera pas les permissions existantes pour les actions déjà répertoriées." + +#: View/Acos/admin_synchronize.ctp:85 +msgid "Synchronize" +msgstr "Synchroniser" + +#: View/Acos/admin_synchronize.ctp:91 +msgid "The ACO datatable is already synchronized" +msgstr "La table ACO est déjà synchronisée" + +#: View/Acos/admin_prune_acos.ctp:15 +msgid "The following actions ACOs have been pruned" +msgstr "Les noeuds ACOs pour les actions suivantes ont été effacés" + +#: View/Acos/admin_prune_acos.ctp:22 +msgid "There was no actions ACOs to prune" +msgstr "Aucun noeud ACO à effacer n'a été trouvé" + +#: View/Acos/admin_prune_acos.ctp:29 +msgid "This page allows you to prune obsolete ACOs." +msgstr "Cette page permet d'effacer les noeuds ACOs obsolètes." + +#: View/Acos/admin_prune_acos.ctp:45 +msgid "Clicking the link will not change or remove permissions for actions ACOs that are not obsolete." +msgstr "Cliquer sur le lien ne modifiera pas les permissions existantes pour les actions qui ne sont pas obsolètes." + +#: View/Acos/admin_prune_acos.ctp:49 +msgid "Prune" +msgstr "Nettoyer" + +#: View/Acos/admin_prune_acos.ctp:55 +msgid "There is no ACO node to delete" +msgstr "Il n'y a aucun noeud ACO à effacer" + +#: View/Acos/admin_empty_acos.ctp:12 +msgid "This page allows you to clear all actions ACOs." +msgstr "Cette page permet d'effacer les actions répertoriées comme ACOs." + +#: View/Acos/admin_empty_acos.ctp:18 +msgid "Clicking the link will destroy all existing actions ACOs and associated permissions." +msgstr "Cliquer sur le lien détruira toutes les actions répertoriées comme ACOs et leurs premissions associées." + +#: View/Acos/admin_empty_acos.ctp:22 +msgid "Clear ACOs" +msgstr "Détruire les ACOs existants" + +#: View/Acos/admin_empty_acos.ctp:22 +msgid "Are you sure you want to destroy all existing ACOs ?" +msgstr "Êtes-vous sûr de vouloir détruire les ACOs existants ?" + +#: View/Acos/admin_build_acl.ctp:29 +msgid "This page allows you to build missing actions ACOs if any." +msgstr "Cette page permet de compléter la table des ACOs en ajoutant les éventuelles actions non-répertoriées." + +#: View/Acos/admin_build_acl.ctp:45 +msgid "Clicking the link will not destroy existing actions ACOs." +msgstr "Cliquer sur le lien ne détruira pas les actions déjà répertoriées." + +#: View/Acos/admin_build_acl.ctp:49 +#: View/Aros/admin_check.ctp:43 +msgid "Build" +msgstr "Compléter" + +#: View/Acos/admin_build_acl.ctp:55 +msgid "There is no ACO node to create" +msgstr "Il n'y a aucun noeud ACO à créer" + +#: View/Aros/admin_check.ctp:12 +msgid "Roles without corresponding Aro" +msgstr "Rôles sans ARO correspondant" + +#: View/Aros/admin_check.ctp:27 +msgid "Users without corresponding Aro" +msgstr "Utilisateurs sans ARO correspondant" + +#: View/Aros/admin_check.ctp:49 +msgid "There is no missing ARO." +msgstr "Il n'y a aucun ARO manquant." + +#: View/Aros/ajax_user_denied.ctp:8 +#: View/Aros/ajax_user_granted.ctp:8 +msgid "The user node does not exist in the ARO table" +msgstr "L'utilisateur n'existe pas dans la table ARO" + +#: View/Aros/ajax_user_denied.ctp:12 +#: View/Aros/ajax_role_denied.ctp:6 +#: View/Aros/admin_ajax_user_permissions.ctp:99 +#: View/Aros/admin_ajax_user_permissions.ctp:149 +#: View/Aros/ajax_role_granted.ctp:6 +#: View/Aros/ajax_user_granted.ctp:12 +#: View/Aros/admin_ajax_role_permissions.ctp:107 +#: View/Aros/admin_ajax_role_permissions.ctp:173 +#: View/Aros/admin_role_permissions.ctp:118 +#: View/Aros/admin_role_permissions.ctp:200 +msgid "The ACO node is probably missing. Please try to rebuild the ACOs first." +msgstr "Le noeud ACO semble manquer. Veuillez essayer de reconstruire la table ACO." + +#: View/Aros/ajax_user_denied.ctp:16 +#: View/Aros/ajax_user_granted.ctp:16 +msgid "The ARO or the ACO node is probably missing. Please try to rebuild the ACOs first." +msgstr "Un noeud ARO ou ACO semble manquer. Veuillez essayer de reconstruire la table ACO." + +#: View/Aros/ajax_role_denied.ctp:6 +#: View/Aros/ajax_role_granted.ctp:6 +msgid "The role node does not exist in the ARO table" +msgstr "Le rôle n'existe pas dans la table ARO" + +#: View/Aros/admin_not_acl_requester.ctp:11 +#: View/Aros/admin_not_acl_requester.ctp:18 +#, php-format +msgid "The %s model is not configured to act as an ACL requester" +msgstr "Le modèle %s n'est pas configuré comme un ACL requester" + +#: View/Aros/admin_not_acl_requester.ctp:25 +#, php-format +msgid "In a classical ACL configuration, the models that represent the users and the roles must act as ACL requesters (see %s)." +msgstr "Dans une configuration ACL classique, les modèles représentant les utilisateurs et les rôles doivent agir comme des ACL requesters (voir %s)." + +#: View/Aros/admin_not_acl_requester.ctp:26 +msgid "Acts As a Requester" +msgstr "Agir comme un Requêteur" + +#: View/Aros/admin_not_acl_requester.ctp:30 +msgid "If you wish, you can disable this alert by setting the ACL plugin parameter 'acl.check_act_as_requester' to false." +msgstr "Si vous le souhaitez, vous pouvez désactiver cette alerte en mettant le paramètre du plugin 'acl.check_act_as_requester' à false." + +#: View/Aros/admin_ajax_user_permissions.ctp:12 +msgid "User" +msgstr "Utilisateur" + +#: View/Aros/admin_ajax_user_permissions.ctp:14 +#: View/Aros/admin_user_permissions.ctp:73 +msgid "Role" +msgstr "Rôle" + +#: View/Aros/admin_ajax_user_permissions.ctp:30 +#: View/Aros/admin_user_permissions.ctp:89 +#: View/Aros/admin_users.ctp:52 +msgid "Update the user role" +msgstr "Modifier le rôle de l'utilisateur" + +#: View/Aros/admin_ajax_user_permissions.ctp:46 +#: View/Aros/admin_user_permissions.ctp:105 +msgid "This user has specific permissions" +msgstr "Cet utilisateur a des permissions spécifiques" + +#: View/Aros/admin_ajax_user_permissions.ctp:48 +#: View/Aros/admin_user_permissions.ctp:107 +msgid "Clear" +msgstr "Effacer" + +#: View/Aros/admin_ajax_user_permissions.ctp:48 +#: View/Aros/admin_user_permissions.ctp:107 +msgid "Are you sure you want to clear the permissions specific to this user ?" +msgstr "Êtes-vous sûr de vouloir détruire les permissions spécifiques de cet utilisateur ?" + +#: View/Aros/admin_ajax_user_permissions.ctp:60 +#: View/Aros/admin_user_permissions.ctp:119 +#: View/Aros/admin_ajax_role_permissions.ctp:59 +#: View/Aros/admin_role_permissions.ctp:59 +msgid "action" +msgstr "action" + +#: View/Aros/admin_ajax_user_permissions.ctp:60 +#: View/Aros/admin_user_permissions.ctp:119 +msgid "authorization" +msgstr "autorisation" + +#: View/Aros/admin_ajax_user_permissions.ctp:94 +#: View/Aros/admin_ajax_user_permissions.ctp:144 +#: View/Aros/admin_ajax_role_permissions.ctp:102 +#: View/Aros/admin_ajax_role_permissions.ctp:168 +msgid "loading" +msgstr "chargement" + +#: View/Aros/admin_ajax_user_permissions.ctp:119 +#: View/Aros/admin_user_permissions.ctp:186 +#: View/Aros/admin_ajax_role_permissions.ctp:136 +#: View/Aros/admin_role_permissions.ctp:147 +msgid "Plugin" +msgstr "Plugin" + +#: View/Aros/admin_ajax_user_permissions.ctp:167 +#: View/Aros/admin_user_permissions.ctp:245 +#: View/Aros/admin_ajax_role_permissions.ctp:195 +#: View/Aros/admin_role_permissions.ctp:222 +msgid "authorized" +msgstr "autorisé" + +#: View/Aros/admin_ajax_user_permissions.ctp:169 +#: View/Aros/admin_user_permissions.ctp:247 +#: View/Aros/admin_ajax_role_permissions.ctp:197 +#: View/Aros/admin_role_permissions.ctp:224 +msgid "blocked" +msgstr "bloqué" + +#: View/Aros/admin_user_permissions.ctp:19 +msgid "This page allows to manage users specific rights" +msgstr "Cette page permet de gérer les droits particuliers de chaque utilisateur" + +#: View/Aros/admin_user_permissions.ctp:25 +#: View/Aros/admin_user_permissions.ctp:37 +msgid "user" +msgstr "utilisateur" + +#: View/Aros/admin_user_permissions.ctp:29 +#: View/Aros/admin_users.ctp:15 +msgid "filter" +msgstr "filtrer" + +#: View/Aros/admin_user_permissions.ctp:47 +msgid "Manage user specific rights" +msgstr "Gérer les droits particuliers de l'utilisateur" + +#: View/Aros/admin_users.ctp:11 +#: View/Aros/admin_users.ctp:23 +msgid "name" +msgstr "nom" + +#: View/Aros/admin_users.ctp:76 +msgid "Some users AROS are missing. Click on a role to assign one to a user." +msgstr "Certains utilisateurs n'ont pas de ARO associé. Vous pouvez les créer en cliquant sur un rôle." + +#: View/Aros/admin_ajax_role_permissions.ctp:17 +#: View/Aros/admin_role_permissions.ctp:17 +msgid "Clear permissions table" +msgstr "Vider la table des permissions" + +#: View/Aros/admin_ajax_role_permissions.ctp:17 +#: View/Aros/admin_role_permissions.ctp:17 +msgid "Are you sure you want to delete all roles and users permissions ?" +msgstr "Êtes-vous sûr de vouloir détruire l'ensembe des permissions des rôles et des utilisateurs ?" + +#: View/Aros/admin_ajax_role_permissions.ctp:29 +#: View/Aros/admin_role_permissions.ctp:29 +msgid "grant access to all actions" +msgstr "donner accès à toutes les actions" + +#: View/Aros/admin_ajax_role_permissions.ctp:30 +#: View/Aros/admin_role_permissions.ctp:30 +msgid "deny access to all actions" +msgstr "bloquer l'accès à toutes les actions" + +#: View/Aros/admin_ajax_role_permissions.ctp:40 +#: View/Aros/admin_role_permissions.ctp:40 +#, php-format +msgid "Are you sure you want to grant access to all actions of each controller to the role '%s' ?" +msgstr "Êtes-vous sûr de vouloir donner accès à toutes les actions de tous les contrôleurs au rôle '%s' ?" + +#: View/Aros/admin_ajax_role_permissions.ctp:41 +#: View/Aros/admin_role_permissions.ctp:41 +#, php-format +msgid "Are you sure you want to deny access to all actions of each controller to the role '%s' ?" +msgstr "Êtes-vous sûr de vouloir bloquer l'accès à toutes les actions de tous les contrôleurs au rôle '%s' ?" + +msgid "previous" +msgstr "précédent" + +msgid "next" +msgstr "suivant" + +#~ msgid "It will build missing actions ACOs if any and prune obsolete ones." +#~ msgstr "" +#~ "Cela complétera les noeuds ACOs manquants nettoyera les noeuds ACOs " +#~ "obsolètes." + +#~ msgid "" +#~ "It will build missing actions ACOs if any and prune any superfluous ones " +#~ "(any ACO pointing to controllers and actions that have been removed)." +#~ msgstr "" +#~ "Cela complétera les ACOs manquants s'il y en a et nettoyera d'éventuels " +#~ "ACOs obsolètes." + +#~ msgid "" +#~ "This page allows you to prune superfluous ACOs (any ACO pointing to " +#~ "controllers and actions that have been removed)." +#~ msgstr "Cette page permet de nettoyer les ACOS devenus obsolètes." + +#, fuzzy +#~ msgid "acl" +#~ msgstr "acl" diff --git a/Locale/pt_BR/LC_MESSAGES/acl.po b/Locale/pt_BR/LC_MESSAGES/acl.po new file mode 100644 index 0000000..77bffaf --- /dev/null +++ b/Locale/pt_BR/LC_MESSAGES/acl.po @@ -0,0 +1,208 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Project-Id-Version: OS-CEJAM\n" +"Last-Translator: Elias Farah \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n>1;\n" +"X-Generator: KBabel 1.11.4\n" +"X-Poedit-Language: Portuguese\n" +"X-Poedit-Country: BRAZIL\n" +"X-Poedit-SourceCharset: utf-8\n" + +msgid "ACL plugin" +msgstr "Lista de Controle de Acesso" + +msgid "Build missing AROs" +msgstr "Carregar usuários" + +msgid "Users roles" +msgstr "Grupos de usuários" + +msgid "Roles permissions" +msgstr "Permissões de Grupos" + +msgid "Users permissions" +msgstr "Permissões de Usuários" + +msgid "Permissions" +msgstr "Permissões" + +msgid "Actions" +msgstr "Ações" + +msgid "Clear permissions table" +msgstr "Limpar tabela de permissões" + +msgid "grant access to all actions" +msgstr "Dar acesso para todas as ações" + +msgid "deny access to all actions" +msgstr "Bloquear todas as ações para todas as ações" + +msgid "administrator" +msgstr "Adiminstrador" + +msgid "user" +msgstr "usuário" + +msgid "role" +msgstr "grupo" + +msgid "User" +msgstr "Usuário" + +msgid "Role" +msgstr "Grupo" + +msgid "name" +msgstr "nome" + +msgid "Name" +msgstr "Nome" + +msgid "authorization" +msgstr "autorização" + +msgid "authorized" +msgstr "autorizado" + +msgid "blocked" +msgstr "bloqueado" + +msgid "Roles without corresponding Aro" +msgstr "Grupos não correspondem ao Aro" + +msgid "Users without corresponding Aro" +msgstr "Usuãrios não correspondem ao Aro" + +msgid "Some users AROS are missing. Click on a role to assign one to a user." +msgstr "Alguns usuários não estão associados as ações. Clique no grupo para associar." + +msgid "The ARO or the ACO node is probably missing. Please try to rebuild the ACOs first." +msgstr "As ações ou os usuários estão faltando. Reconstrua a lista de ações." + +msgid "The user node does not exist in the ARO table" +msgstr "Usuário não cadastrado no sistema de ACL" + +msgid "The role node does not exist in the ARO table" +msgstr "Grupo não cadastrado no sistema de ACL" + +msgid "The ACO node is probably missing. Please try to rebuild the ACOs first." +msgstr "Uma ações está faltando. Reconstrua a lista de ações." + +msgid "Manage user specific rights" +msgstr "Controle as permissões do usuário" + +msgid "This page allows to manage users specific rights" +msgstr "Esta página permite controlar as permissões para os usuários" + +msgid "Some controllers have been modified, resulting in actions that are not referenced as ACO in the database." +msgstr "Alguns controladores foram modificados, resultando em ações que não estão referenciados no sistema ACL" + +msgid "You can update the ACOs by clicking on the following link" +msgstr "Você pode atualizar as ações clicando neste link" + +msgid "Build missing AROs" +msgstr "Carregar usuário faltando no sistema de ACL" + +msgid "There is no missing ARO." +msgstr "Não há usuário faltando." + +msgid "Build missing ACOs" +msgstr "Carregar as ações faltando" + +msgid "Please be aware that this message will appear only once. But you can always rebuild the ACOs by going to the ACO tab." +msgstr "Lembre-se que esta mensagem irá aparecer somente uma vez. Mas você sempre pode reconstruir as ações, indo até a guia ações. " + +msgid "The following actions ACOs have been created" +msgstr "As ações seguintes foram criadas" + +msgid "There was no new actions ACOs to create" +msgstr "Não houve novas ações para criar" + +msgid "This page allows you to build missing actions ACOs if any." +msgstr "Esta página permite que você construa as ações faltando se houver." + +msgid "Clicking the link will not destroy existing actions ACOs." +msgstr "Clicando no link não irá destruir ações existentes no sistema ACL." + +msgid "Build" +msgstr "Carregar" + +msgid "Build actions ACOs" +msgstr "Carregar ações" + +msgid "Clear actions ACOs" +msgstr "Limpar ações" + +msgid "This page allows you to clear all actions ACOs." +msgstr "Esta página permite que você apague todas as ações." + +msgid "Clicking the link will destroy all existing actions ACOs and associated permissions." +msgstr "Ao clicar no link irá& destruir todas as acções existentes e as permissões associadas." + +msgid "Clear ACOs" +msgstr "Limpar ACOs" + +msgid "Are you sure you want to destroy all existing ACOs ?" +msgstr "Tem certeza que quer destruir todas as acções existentes?" + +msgid "The user role has been updated" +msgstr "O grupo de usuário foi atualizado" + +msgid "The user role could not be updated" +msgstr "O grupo do usuário não pôde ser atualizado" + +msgid "The user '%s' does not exist in the ARO table" +msgstr "Usuário '%s' não cadastrado no sistema ACL" + +msgid "The permissions have been cleared" +msgstr "As permissões foram apagadas" + +msgid "The permissions could not be cleared" +msgstr "As permissões não puderam ser apagadas" + +msgid "The role '%s' does not exist in the ARO table" +msgstr "Grupo '%s' não cadastrado no sistema ACL" + +msgid "The ACO table has been cleared" +msgstr "A tabela de acções foi apagada" + +msgid "The ACO table could not be cleared" +msgstr "A tabela de acções não pôde ser apagada" + +msgid "Are you sure you want to delete all roles and users permissions ?" +msgstr "Tem certeza de que deseja excluir todos os grupos e permissões de usuários?" + +msgid "Are you sure you want to grant access to all actions of each controller to the role '%s' ?" +msgstr "Tem certeza que você deseja conceder acesso a todas as ações de cada controlador para o grupo '%s'?" + +msgid "Are you sure you want to deny access to all actions of each controller to the role '%s' ?" +msgstr "Tem certeza que quer negar o acesso a todas as ações de cada controlador para o grupo '%s'?" + +msgid "Update the user role" +msgstr "Atualize o grupo do usuário" + +msgid "The role model name is unknown. The ACL plugin bootstrap.php file has to be loaded in order to work. (see the README file)" +msgstr "O nome do modelo é desconhecido. O plugin ACL, no arquivo bootstrap.php tem que ser carregado para funcionar. (consulte o arquivo README)" + +msgid "The %s model is not configured to act as an ACL requester" +msgstr "O modelo %s não está configurado em ACL requester" + +msgid "In a classical ACL configuration, the models that represent the users and the roles must act as ACL requesters (see %s)." +msgstr "Em uma configuração de ACL clássicos, os modelos que representam os usuários e os grupos devem agir como solicitantes ACL (veja% s)." + +msgid "Acts As a Requester" +msgstr "Agir como um Requester" + +msgid "If you wish, you can disable this alert by setting the ACL plugin parameter 'acl.check_act_as_requester' to false." +msgstr "Se desejar, você pode desativar esse alerta, definindo a ACL plugin 'acl.check_act_as_requester' parâmetro para false ." + +msgid "filter" +msgstr "filtro" + diff --git a/README b/README new file mode 100644 index 0000000..865a478 --- /dev/null +++ b/README @@ -0,0 +1,51 @@ +ACL Plugin for CakePHP 2.0 +=========================== + +Version: 2.2.0 +Date: 2012-09-24 +Author: Nicolas Rod +Website: http://www.alaxos.net/blaxos/pages/view/plugin_acl +License: http://www.opensource.org/licenses/mit-license.php The MIT License + +This CakePHP plugin is an interface to manage an ACL protected web application. + +It is made to work with an application already configured with ACL. The documentation to configure the ACL +can be found on the following links : + +- http://book.cakephp.org/2.0/en/core-libraries/components/access-control-lists.html +- http://book.cakephp.org/2.0/en/tutorials-and-examples/simple-acl-controlled-application/simple-acl-controlled-application.html + + +Installation +------------- + + +- Download the plugin and put it in your 'app/Plugin' or 'plugins' folder +- Configure the 'admin' route (see http://book.cakephp.org/2.0/en/development/routing.html) +- Configure the plugin according to your web application: + + Some settings have to be read by CakePHP when the plugin is loaded. They can be found + in the 'Acl/Config/bootstrap.php' file. + + You have two options to use these settings, as CakePHP doesn't automatically load + the bootstrap.php files in plugins: + + 1. Copy all the settings in your app/config/bootstrap.php file + + or + + 2. Load the plugin bootstrap with the plugin + + CakePlugin::load('Acl', array('bootstrap' => true)); + +- Make sure the AclComponent is declared in your AppController and that your User and Group/Role models are configured to act as requester (see the CakePHP ACL tutorial) +- Access the ACL plugin by navigating to /admin/acl + + +About CakePHP 2.0 +----------------- + +If you use CakePHP version 2.0, the plugin will work only if you do not use the E_STRICT error reporting level. + +You can use E_STRICT error reporting level with CakePHP 2.1 or above. + diff --git a/View/Acos/admin_build_acl.ctp b/View/Acos/admin_build_acl.ctp new file mode 100644 index 0000000..51bbddf --- /dev/null +++ b/View/Acos/admin_build_acl.ctp @@ -0,0 +1,61 @@ +element('design/header'); +?> + +element('Acos/links'); +?> + + 0) + { + echo '

'; + echo __d('acl', 'The following actions ACOs have been created'); + echo '

'; + echo $this->Html->nestedList($logs); + } + else + { + echo '

'; + echo __d('acl', 'There was no new actions ACOs to create'); + echo '

'; + } +} +else +{ + echo '

'; + echo __d('acl', 'This page allows you to build missing actions ACOs if any.'); + echo '

'; + + echo '

 

'; + + if(count($missing_aco_nodes) > 0) + { + echo '

' . __d('acl', 'Missing ACOs') . '

'; + + echo '

'; + echo $this->Html->nestedList($missing_aco_nodes); + echo '

'; + + echo '

 

'; + + echo '

'; + echo __d('acl', 'Clicking the link will not destroy existing actions ACOs.'); + echo '

'; + + echo '

'; + echo $this->Html->link($this->Html->image('/acl/img/design/add.png') . ' ' . __d('acl', 'Build'), '/admin/acl/acos/build_acl/run', array('escape' => false)); + echo '

'; + } + else + { + echo '

'; + echo $this->Html->image('/acl/img/design/tick.png') . ' ' . __d('acl', 'There is no ACO node to create'); + echo '

'; + } +} + +echo $this->element('design/footer'); +?> \ No newline at end of file diff --git a/View/Acos/admin_empty_acos.ctp b/View/Acos/admin_empty_acos.ctp new file mode 100644 index 0000000..9fe9a67 --- /dev/null +++ b/View/Acos/admin_empty_acos.ctp @@ -0,0 +1,35 @@ +element('design/header'); +?> + +element('Acos/links'); +?> + +'; + echo __d('acl', 'This page allows you to clear all actions ACOs.'); + echo '

'; + + echo '

 

'; + + if($actions_exist) + { + echo '

'; + echo __d('acl', 'Clicking the link will destroy all existing actions ACOs and associated permissions.'); + echo '

'; + + echo '

'; + echo $this->Html->link($this->Html->image('/acl/img/design/cross.png') . ' ' . __d('acl', 'Clear ACOs'), '/admin/acl/acos/empty_acos/run', array('confirm' => __d('acl', 'Are you sure you want to destroy all existing ACOs ?'), 'escape' => false)); + echo '

'; + } + else + { + echo '

'; + echo __d('acl', 'There is no ACO node to delete'); + echo '

'; + } + +echo $this->element('design/footer'); +?> \ No newline at end of file diff --git a/View/Acos/admin_has_updates.ctp b/View/Acos/admin_has_updates.ctp new file mode 100644 index 0000000..285bd05 --- /dev/null +++ b/View/Acos/admin_has_updates.ctp @@ -0,0 +1,42 @@ +element('design/header', array('no_acl_links' => true)); +?> + +
+ + ' . __d('acl', 'Some controllers have been modified, resulting in actions that are not referenced as ACO in the database or ACO records that are obsolete') . ' :

'; + + if(count($missing_aco_nodes) > 0) + { + echo '

' . __d('acl', 'Missing ACOs') . '

'; + + echo '

'; + echo $this->Html->nestedList($missing_aco_nodes); + echo '

'; + } + + if(count($nodes_to_prune) > 0) + { + echo '

' . __d('acl', 'Obsolete ACOs') . '

'; + + echo '

'; + echo $this->Html->nestedList($nodes_to_prune); + echo '

'; + } + + echo '

'; + echo __d('acl', 'You can update the ACOs by clicking on the following link') . ' : '; + echo $this->Html->link(__d('acl', 'Synchronize ACOs'), '/admin/acl/acos/synchronize/run'); + echo '

'; + + echo '

'; + echo __d('acl', 'Please be aware that this message will appear only once. But you can always rebuild the ACOs by going to the ACO tab.'); + echo '

'; + ?> + +
+ +element('design/footer'); +?> \ No newline at end of file diff --git a/View/Acos/admin_index.ctp b/View/Acos/admin_index.ctp new file mode 100644 index 0000000..8c2d0c0 --- /dev/null +++ b/View/Acos/admin_index.ctp @@ -0,0 +1,11 @@ +element('design/header'); +?> + +element('Acos/links'); +?> + +element('design/footer'); +?> \ No newline at end of file diff --git a/View/Acos/admin_prune_acos.ctp b/View/Acos/admin_prune_acos.ctp new file mode 100644 index 0000000..87c1b42 --- /dev/null +++ b/View/Acos/admin_prune_acos.ctp @@ -0,0 +1,61 @@ +element('design/header'); +?> + +element('Acos/links'); +?> + + 0) + { + echo '

'; + echo __d('acl', 'The following actions ACOs have been pruned'); + echo '

'; + echo $this->Html->nestedList($logs); + } + else + { + echo '

'; + echo __d('acl', 'There was no actions ACOs to prune'); + echo '

'; + } +} +else +{ + echo '

'; + echo __d('acl', 'This page allows you to prune obsolete ACOs.'); + echo '

'; + + echo '

 

'; + + if(count($nodes_to_prune) > 0) + { + echo '

' . __d('acl', 'Obsolete ACO nodes') . '

'; + + echo '

'; + echo $this->Html->nestedList($nodes_to_prune); + echo '

'; + + echo '

 

'; + + echo '

'; + echo __d('acl', 'Clicking the link will not change or remove permissions for actions ACOs that are not obsolete.'); + echo '

'; + + echo '

'; + echo $this->Html->link($this->Html->image('/acl/img/design/clean.png') . ' ' . __d('acl', 'Prune'), '/admin/acl/acos/prune_acos/run', array('escape' => false)); + echo '

'; + } + else + { + echo '

'; + echo $this->Html->image('/acl/img/design/tick.png') . ' ' . __d('acl', 'There is no ACO node to delete'); + echo '

'; + } +} + +echo $this->element('design/footer'); +?> \ No newline at end of file diff --git a/View/Acos/admin_synchronize.ctp b/View/Acos/admin_synchronize.ctp new file mode 100644 index 0000000..b875f2f --- /dev/null +++ b/View/Acos/admin_synchronize.ctp @@ -0,0 +1,97 @@ +element('design/header'); +?> + +element('Acos/links'); +?> + +' . __d('acl', 'New ACOs') . ''; + + if(count($create_logs) > 0) + { +// echo '

'; +// echo __d('acl', 'The following actions ACOs have been created'); +// echo '

'; + echo $this->Html->nestedList($create_logs); + } + else + { + echo '

'; + echo __d('acl', 'There was no new actions ACOs to create'); + echo '

'; + } + + echo '

' . __d('acl', 'Obsolete ACOs') . '

'; + + if(count($prune_logs) > 0) + { +// echo '

'; +// echo __d('acl', 'The following actions ACOs have been deleted'); +// echo '

'; + echo $this->Html->nestedList($prune_logs); + } + else + { + echo '

'; + echo __d('acl', 'There was no action ACO to delete'); + echo '

'; + } +} +else +{ + echo '

'; + echo __d('acl', 'This page allows you to synchronize the existing controllers and actions with the ACO datatable.'); + echo '

'; + + echo '

 

'; + + $has_aco_to_sync = false; + + if(count($missing_aco_nodes) > 0) + { + echo '

' . __d('acl', 'Missing ACOs') . '

'; + + echo '

'; + echo $this->Html->nestedList($missing_aco_nodes); + echo '

'; + + $has_aco_to_sync = true; + } + + if(count($nodes_to_prune) > 0) + { + echo '

' . __d('acl', 'Obsolete ACO nodes') . '

'; + + echo '

'; + echo $this->Html->nestedList($nodes_to_prune); + echo '

'; + + $has_aco_to_sync = true; + } + + if($has_aco_to_sync) + { + echo '

 

'; + + echo '

'; + echo __d('acl', 'Clicking the link will not change or remove permissions for existing actions ACOs.'); + echo '

'; + + echo '

'; + echo $this->Html->link($this->Html->image('/acl/img/design/sync.png') . ' ' . __d('acl', 'Synchronize'), '/admin/acl/acos/synchronize/run', array('escape' => false)); + echo '

'; + } + else + { + echo '

'; + echo $this->Html->image('/acl/img/design/tick.png') . ' ' . __d('acl', 'The ACO datatable is already synchronized'); + echo '

'; + } +} + +echo $this->element('design/footer'); +?> \ No newline at end of file diff --git a/View/Aros/admin_ajax_role_permissions.ctp b/View/Aros/admin_ajax_role_permissions.ctp new file mode 100644 index 0000000..cf57c55 --- /dev/null +++ b/View/Aros/admin_ajax_role_permissions.ctp @@ -0,0 +1,205 @@ +Html->script('/acl/js/jquery'); +echo $this->Html->script('/acl/js/acl_plugin'); + +echo $this->element('design/header'); +?> + +element('Aros/links'); +?> + +
+ +
+ + Html->link($this->Html->image('/acl/img/design/cross.png') . ' ' . __d('acl', 'Clear permissions table'), '/admin/acl/aros/empty_permissions', array('confirm' => __d('acl', 'Are you sure you want to delete all roles and users permissions ?'), 'escape' => false)); + ?> + + +
+ +
+ + + + + + + + + +'; + echo ' '; + echo ' '; + echo ' '; + echo ''; + + $i++; +} +?> +
all actions'); ?>all actions'); ?>
' . $role[$role_model_name][$role_display_field] . '' . $this->Html->link($this->Html->image('/acl/img/design/tick.png'), '/admin/acl/aros/grant_all_controllers/' . $role[$role_model_name][$role_pk_name], array('escape' => false, 'confirm' => sprintf(__d('acl', "Are you sure you want to grant access to all actions of each controller to the role '%s' ?"), $role[$role_model_name][$role_display_field]))) . '' . $this->Html->link($this->Html->image('/acl/img/design/cross.png'), '/admin/acl/aros/deny_all_controllers/' . $role[$role_model_name][$role_pk_name], array('escape' => false, 'confirm' => sprintf(__d('acl', "Are you sure you want to deny access to all actions of each controller to the role '%s' ?"), $role[$role_model_name][$role_display_field]))) . '
+ +
+ +
+ + + + Html->tableHeaders($headers); + ?> + + + $ctrl_infos) + { + if($previous_ctrl_name != $controller_name) + { + $previous_ctrl_name = $controller_name; + + $color = ($i % 2 == 0) ? 'color1' : 'color2'; + } + + foreach($ctrl_infos as $ctrl_info) + { + echo ' + '; + + echo ''; + + foreach($roles as $role) + { + echo ''; + } + + echo ' + '; + } + + $i++; + } + } + ?> + $plugin_ctrler_infos) + { +// debug($plugin_name); +// debug($plugin_ctrler_infos); + + $color = null; + + echo ''; + + $i = 0; + foreach($plugin_ctrler_infos as $plugin_ctrler_name => $plugin_methods) + { + //debug($plugin_ctrler_name); + //echo ''; + + if($previous_ctrl_name != $plugin_ctrler_name) + { + $previous_ctrl_name = $plugin_ctrler_name; + + $color = ($i % 2 == 0) ? 'color1' : 'color2'; + } + + + foreach($plugin_methods as $method) + { + echo ' + '; + + echo ''; + //debug($method['name']); + + foreach($roles as $role) + { + echo ''; + } + + echo ' + '; + } + + $i++; + } + } + } + ?> +
' . $controller_name . '->' . $ctrl_info['name'] . ''; + echo ''; + + /* + * The right of the action for the role must still be loaded + */ + echo $this->Html->image('/acl/img/ajax/waiting16.gif', array('title' => __d('acl', 'loading'))); + + if(!in_array($controller_name . '_' . $role[$role_model_name][$role_pk_name], $js_init_done)) + { + $js_init_done[] = $controller_name . '_' . $role[$role_model_name][$role_pk_name]; + $this->Js->buffer('init_register_role_controller_toggle_right("' . $this->Html->url('/', true) . '", "' . $role[$role_model_name][$role_pk_name] . '", "", "' . $controller_name . '", "' . __d('acl', 'The ACO node is probably missing. Please try to rebuild the ACOs first.') . '");'); + } + + echo ''; + + echo ' '; + echo $this->Html->image('/acl/img/ajax/waiting16.gif', array('id' => 'right__' . $role[$role_model_name][$role_pk_name] . '_' . $controller_name . '_' . $ctrl_info['name'] . '_spinner', 'style' => 'display:none;')); + + echo '
' . __d('acl', 'Plugin') . ' ' . $plugin_name . '
' . $plugin_ctrler_name . '
' . $plugin_ctrler_name . '->' . $method['name'] . ''; + echo ''; + + /* + * The right of the action for the role must still be loaded + */ + echo $this->Html->image('/acl/img/ajax/waiting16.gif', array('title' => __d('acl', 'loading'))); + + if(!in_array($plugin_name . "_" . $plugin_ctrler_name . '_' . $role[$role_model_name][$role_pk_name], $js_init_done)) + { + $js_init_done[] = $plugin_name . "_" . $plugin_ctrler_name . '_' . $role[$role_model_name][$role_pk_name]; + $this->Js->buffer('init_register_role_controller_toggle_right("' . $this->Html->url('/', true) . '", "' . $role[$role_model_name][$role_pk_name] . '", "' . $plugin_name . '", "' . $plugin_ctrler_name . '", "' . __d('acl', 'The ACO node is probably missing. Please try to rebuild the ACOs first.') . '");'); + } + + echo ''; + + echo ' '; + echo $this->Html->image('/acl/img/ajax/waiting16.gif', array('id' => 'right_' . $plugin_name . '_' . $role[$role_model_name][$role_pk_name] . '_' . $plugin_ctrler_name . '_' . $method['name'] . '_spinner', 'style' => 'display:none;')); + + echo '
+ Html->image('/acl/img/design/tick.png') . ' ' . __d('acl', 'authorized'); + echo '   '; + echo $this->Html->image('/acl/img/design/cross.png') . ' ' . __d('acl', 'blocked'); + ?> + +
+ + +element('design/footer'); +?> \ No newline at end of file diff --git a/View/Aros/admin_ajax_user_permissions.ctp b/View/Aros/admin_ajax_user_permissions.ctp new file mode 100644 index 0000000..bdfe07d --- /dev/null +++ b/View/Aros/admin_ajax_user_permissions.ctp @@ -0,0 +1,168 @@ +Html->script('/acl/js/jquery'); +echo $this->Html->script('/acl/js/acl_plugin'); + +echo $this->element('design/header'); +?> + +element('Aros/links'); +?> + +

+ +

+ + + + '; + + echo $role[$role_model_name][$role_display_field]; + if($role[$role_model_name][$role_pk_name] == $user[$user_model_name][$role_fk_name]) + { + echo $this->Html->image('/acl/img/design/tick.png'); + } + else + { + $title = __d('acl', 'Update the user role'); + echo $this->Html->link($this->Html->image('/acl/img/design/tick_disabled.png'), array('plugin' => 'acl', 'controller' => 'aros', 'action' => 'update_user_role', 'user' => $user[$user_model_name][$user_pk_name], 'role' => $role[$role_model_name][$role_pk_name]), array('title' => $title, 'alt' => $title, 'escape' => false)); + } + + echo ''; + } + ?> + +
+ +

+ + '; + echo $this->Html->image('/acl/img/design/bulb24.png') . __d('acl', 'This user has specific permissions'); + echo ' ('; + echo $this->Html->link($this->Html->image('/acl/img/design/cross2.png', array('style' => 'vertical-align:middle;')) . ' ' . __d('acl', 'Clear'), '/admin/acl/aros/clear_user_specific_permissions/' . $user[$user_model_name][$user_pk_name], array('confirm' => __d('acl', 'Are you sure you want to clear the permissions specific to this user ?'), 'escape' => false)); + echo ')'; + echo '
'; + } + ?> + + + + Html->tableHeaders($headers); + ?> + + + $ctrl_infos) + { + if($previous_ctrl_name != $controller_name) + { + $previous_ctrl_name = $controller_name; + + $color = (isset($color) && $color == 'color1') ? 'color2' : 'color1'; + } + + foreach($ctrl_infos as $ctrl_info) + { + echo ''; + + echo ''; + + echo ''; + echo ''; + } + } + } + ?> + $plugin_ctrler_infos) + { + echo ''; + + foreach($plugin_ctrler_infos as $plugin_ctrler_name => $plugin_methods) + { + if($previous_ctrl_name != $plugin_ctrler_name) + { + $previous_ctrl_name = $plugin_ctrler_name; + + $color = (isset($color) && $color == 'color1') ? 'color2' : 'color1'; + } + + foreach($plugin_methods as $method) + { + echo ''; + + echo ''; + + echo ''; + echo ''; + } + } + } + } + ?> +
' . $controller_name . '->' . $ctrl_info['name'] . ''; + echo ''; + + /* + * The right of the action for the role must still be loaded + */ + echo $this->Html->image('/acl/img/ajax/waiting16.gif', array('title' => __d('acl', 'loading'))); + + if(!in_array($controller_name . '_' . $user[$user_model_name][$user_pk_name], $js_init_done)) + { + $js_init_done[] = $controller_name . '_' . $user[$user_model_name][$user_pk_name]; + $this->Js->buffer('init_register_user_controller_toggle_right("' . $this->Html->url('/', true) . '", "' . $user[$user_model_name][$user_pk_name] . '", "", "' . $controller_name . '", "' . __d('acl', 'The ACO node is probably missing. Please try to rebuild the ACOs first.') . '");'); + } + + echo ''; + + echo ' '; + echo $this->Html->image('/acl/img/ajax/waiting16.gif', array('id' => 'right__' . $user[$user_model_name][$user_pk_name] . '_' . $controller_name . '_' . $ctrl_info['name'] . '_spinner', 'style' => 'display:none;')); + + echo '
' . __d('acl', 'Plugin') . ' ' . $plugin_name . '
' . $plugin_ctrler_name . '->' . $method['name'] . ''; + echo ''; + + /* + * The right of the action for the role must still be loaded + */ + echo $this->Html->image('/acl/img/ajax/waiting16.gif', array('title' => __d('acl', 'loading'))); + + if(!in_array($plugin_name . "_" . $plugin_ctrler_name . '_' . $user[$user_model_name][$user_pk_name], $js_init_done)) + { + $js_init_done[] = $plugin_name . "_" . $plugin_ctrler_name . '_' . $user[$user_model_name][$user_pk_name]; + $this->Js->buffer('init_register_user_controller_toggle_right("' . $this->Html->url('/', true) . '", "' . $user[$user_model_name][$user_pk_name] . '", "' . $plugin_name . '", "' . $plugin_ctrler_name . '", "' . __d('acl', 'The ACO node is probably missing. Please try to rebuild the ACOs first.') . '");'); + } + + echo ''; + + echo ' '; + echo $this->Html->image('/acl/img/ajax/waiting16.gif', array('id' => 'right_' . $plugin_name . '_' . $user[$user_model_name][$user_pk_name] . '_' . $plugin_ctrler_name . '_' . $method['name'] . '_spinner', 'style' => 'display:none;')); + + echo '
+ Html->image('/acl/img/design/tick.png') . ' ' . __d('acl', 'authorized'); + echo '   '; + echo $this->Html->image('/acl/img/design/cross.png') . ' ' . __d('acl', 'blocked'); + ?> +element('design/footer'); +?> \ No newline at end of file diff --git a/View/Aros/admin_check.ctp b/View/Aros/admin_check.ctp new file mode 100644 index 0000000..56ea754 --- /dev/null +++ b/View/Aros/admin_check.ctp @@ -0,0 +1,56 @@ +element('design/header'); +?> + +element('Aros/links'); +?> + + 0) +{ + echo '

' . __d('acl', 'Roles without corresponding Aro') . '

'; + + $list = array(); + foreach($missing_aros['roles'] as $missing_aro) + { + $list[] = $missing_aro[$role_model_name][$role_display_field]; + } + + echo $this->Html->nestedList($list); +} +?> + + 0) +{ + echo '

' . __d('acl', 'Users without corresponding Aro') . '

'; + + $list = array(); + foreach($missing_aros['users'] as $missing_aro) + { + $list[] = $missing_aro[$user_model_name][$user_display_field]; + } + + echo $this->Html->nestedList($list); +} +?> + + 0 || count($missing_aros['users']) > 0) +{ + echo '

'; + echo $this->Html->link(__d('acl', 'Build'), '/admin/acl/aros/check/run'); + echo '

'; +} +else +{ + echo '

'; + echo __d('acl', 'There is no missing ARO.'); + echo '

'; +} +?> + +element('design/footer'); +?> \ No newline at end of file diff --git a/View/Aros/admin_index.ctp b/View/Aros/admin_index.ctp new file mode 100644 index 0000000..8b8a941 --- /dev/null +++ b/View/Aros/admin_index.ctp @@ -0,0 +1,11 @@ +element('design/header'); +?> + +element('Aros/links'); +?> + +element('design/footer'); +?> \ No newline at end of file diff --git a/View/Aros/admin_not_acl_requester.ctp b/View/Aros/admin_not_acl_requester.ctp new file mode 100644 index 0000000..4f2ee29 --- /dev/null +++ b/View/Aros/admin_not_acl_requester.ctp @@ -0,0 +1,39 @@ +element('design/header', array('no_acl_links' => true)); +?> + +
+ + '; + echo sprintf(__d('acl', 'The %s model is not configured to act as an ACL requester'), Configure :: read('acl.aro.user.model')) . '

'; + echo '

'; + } + + if(isset($role_is_not_requester)) + { + echo '

'; + echo sprintf(__d('acl', 'The %s model is not configured to act as an ACL requester'), Configure :: read('acl.aro.role.model')) . '

'; + echo '

'; + } + + echo '

 

'; + + echo '

'; + echo sprintf(__d('acl', 'In a classical ACL configuration, the models that represent the users and the roles must act as ACL requesters (see %s).'), + $this->Html->link(__d('acl', 'Acts As a Requester'), 'http://book.cakephp.org/view/1547/Acts-As-a-Requester')); + echo '

'; + + echo '

'; + echo __d('acl', "If you wish, you can disable this alert by setting the ACL plugin parameter 'acl.check_act_as_requester' to false."); + echo '

'; + + ?> + +
+ +element('design/footer'); +?> \ No newline at end of file diff --git a/View/Aros/admin_role_permissions.ctp b/View/Aros/admin_role_permissions.ctp new file mode 100644 index 0000000..da51d16 --- /dev/null +++ b/View/Aros/admin_role_permissions.ctp @@ -0,0 +1,232 @@ +Html->script('/acl/js/jquery'); +echo $this->Html->script('/acl/js/acl_plugin'); + +echo $this->element('design/header'); +?> + +element('Aros/links'); +?> + +
+ +
+ + Html->link($this->Html->image('/acl/img/design/cross.png') . ' ' . __d('acl', 'Clear permissions table'), '/admin/acl/aros/empty_permissions', array('confirm' => __d('acl', 'Are you sure you want to delete all roles and users permissions ?'), 'escape' => false)); + ?> + + +
+ +
+ + + + + + + + + +'; + echo ' '; + echo ' '; + echo ' '; + echo ''; + + $i++; +} +?> +
all actions'); ?>all actions'); ?>
' . $role[$role_model_name][$role_display_field] . '' . $this->Html->link($this->Html->image('/acl/img/design/tick.png'), '/admin/acl/aros/grant_all_controllers/' . $role[$role_model_name][$role_pk_name], array('escape' => false, 'confirm' => sprintf(__d('acl', "Are you sure you want to grant access to all actions of each controller to the role '%s' ?"), $role[$role_model_name][$role_display_field]))) . '' . $this->Html->link($this->Html->image('/acl/img/design/cross.png'), '/admin/acl/aros/deny_all_controllers/' . $role[$role_model_name][$role_pk_name], array('escape' => false, 'confirm' => sprintf(__d('acl', "Are you sure you want to deny access to all actions of each controller to the role '%s' ?"), $role[$role_model_name][$role_display_field]))) . '
+ +
+ +
+ + + + Html->tableHeaders($headers); + ?> + + + $ctrl_infos) + { + if($previous_ctrl_name != $controller_name) + { + $previous_ctrl_name = $controller_name; + + $color = ($i % 2 == 0) ? 'color1' : 'color2'; + } + + foreach($ctrl_infos as $ctrl_info) + { + echo ' + '; + + echo ''; + + foreach($roles as $role) + { + echo ''; + } + + echo ' + '; + } + + $i++; + } + } + ?> + $plugin_ctrler_infos) + { +// debug($plugin_name); +// debug($plugin_ctrler_infos); + + $color = null; + + echo ''; + + $i = 0; + foreach($plugin_ctrler_infos as $plugin_ctrler_name => $plugin_methods) + { + //debug($plugin_ctrler_name); + //echo ''; + + if($previous_ctrl_name != $plugin_ctrler_name) + { + $previous_ctrl_name = $plugin_ctrler_name; + + $color = ($i % 2 == 0) ? 'color1' : 'color2'; + } + + + foreach($plugin_methods as $method) + { + echo ' + '; + + echo ''; + //debug($method['name']); + + foreach($roles as $role) + { + echo ''; + + $this->Js->buffer('register_role_toggle_right(true, "' . $this->Html->url('/') . '", "right_' . $plugin_name . '_' . $role[$role_model_name][$role_pk_name] . '_' . $plugin_ctrler_name . '_' . $method['name'] . '", "' . $role[$role_model_name][$role_pk_name] . '", "' . $plugin_name . '", "' . $plugin_ctrler_name . '", "' . $method['name'] . '")'); + + echo $this->Html->image('/acl/img/design/tick.png', array('class' => 'pointer')); + } + else + { + //echo ''; + + $this->Js->buffer('register_role_toggle_right(false, "' . $this->Html->url('/') . '", "right_' . $plugin_name . '_' . $role[$role_model_name][$role_pk_name] . '_' . $plugin_ctrler_name . '_' . $method['name'] . '", "' . $role[$role_model_name][$role_pk_name] . '", "' . $plugin_name . '", "' . $plugin_ctrler_name . '", "' . $method['name'] . '")'); + + echo $this->Html->image('/acl/img/design/cross.png', array('class' => 'pointer')); + } + } + else + { + /* + * The right of the action for the role is unknown + */ + echo $this->Html->image('/acl/img/design/important16.png', array('title' => __d('acl', 'The ACO node is probably missing. Please try to rebuild the ACOs first.'))); + } + + echo ''; + + echo ' '; + echo $this->Html->image('/acl/img/ajax/waiting16.gif', array('id' => 'right_' . $plugin_name . '_' . $role[$role_model_name][$role_pk_name] . '_' . $plugin_ctrler_name . '_' . $method['name'] . '_spinner', 'style' => 'display:none;')); + + echo ''; + } + + echo ' + '; + } + + $i++; + } + } + } + ?> +
' . $controller_name . '->' . $ctrl_info['name'] . ''; + echo ''; + + if(isset($ctrl_info['permissions'][$role[$role_model_name][$role_pk_name]])) + { + if($ctrl_info['permissions'][$role[$role_model_name][$role_pk_name]] == 1) + { + $this->Js->buffer('register_role_toggle_right(true, "' . $this->Html->url('/') . '", "right__' . $role[$role_model_name][$role_pk_name] . '_' . $controller_name . '_' . $ctrl_info['name'] . '", "' . $role[$role_model_name][$role_pk_name] . '", "", "' . $controller_name . '", "' . $ctrl_info['name'] . '")'); + + echo $this->Html->image('/acl/img/design/tick.png', array('class' => 'pointer')); + } + else + { + $this->Js->buffer('register_role_toggle_right(false, "' . $this->Html->url('/') . '", "right__' . $role[$role_model_name][$role_pk_name] . '_' . $controller_name . '_' . $ctrl_info['name'] . '", "' . $role[$role_model_name][$role_pk_name] . '", "", "' . $controller_name . '", "' . $ctrl_info['name'] . '")'); + + echo $this->Html->image('/acl/img/design/cross.png', array('class' => 'pointer')); + } + } + else + { + /* + * The right of the action for the role is unknown + */ + echo $this->Html->image('/acl/img/design/important16.png', array('title' => __d('acl', 'The ACO node is probably missing. Please try to rebuild the ACOs first.'))); + } + + echo ''; + + echo ' '; + echo $this->Html->image('/acl/img/ajax/waiting16.gif', array('id' => 'right__' . $role[$role_model_name][$role_pk_name] . '_' . $controller_name . '_' . $ctrl_info['name'] . '_spinner', 'style' => 'display:none;')); + + echo '
' . __d('acl', 'Plugin') . ' ' . $plugin_name . '
' . $plugin_ctrler_name . '
' . $plugin_ctrler_name . '->' . $method['name'] . ''; + echo ''; + + if(isset($ctrl_info['permissions'][$role[$role_model_name][$role_pk_name]])) + { + if($method['permissions'][$role[$role_model_name][$role_pk_name]] == 1) + { + //echo '' . $this->Html->link($this->Html->image('/acl/img/design/tick.png'), '/admin/acl/aros/deny_role_permission/' . $role[$role_model_name][$role_pk_name] . '/plugin:' . $plugin_name . '/controller:' . $plugin_ctrler_name . '/action:' . $method['name'], array('escape' => false)) . '' . $this->Html->link($this->Html->image('/acl/img/design/cross.png'), '/admin/acl/aros/grant_role_permission/' . $role[$role_model_name][$role_pk_name] . '/plugin:' . $plugin_name .'/controller:' . $plugin_ctrler_name . '/action:' . $method['name'], array('escape' => false)) . '
+ Html->image('/acl/img/design/tick.png') . ' ' . __d('acl', 'authorized'); + echo '   '; + echo $this->Html->image('/acl/img/design/cross.png') . ' ' . __d('acl', 'blocked'); + ?> + +
+ + +element('design/footer'); +?> \ No newline at end of file diff --git a/View/Aros/admin_user_permissions.ctp b/View/Aros/admin_user_permissions.ctp new file mode 100644 index 0000000..e44cb33 --- /dev/null +++ b/View/Aros/admin_user_permissions.ctp @@ -0,0 +1,258 @@ +Html->script('/acl/js/jquery'); +echo $this->Html->script('/acl/js/acl_plugin'); + +echo $this->element('design/header'); +?> + +element('Aros/links'); +?> + + +  

'; + echo '

'; + echo __d('acl', 'This page allows to manage users specific rights'); + echo '

'; + echo '

 

'; + ?> + Form->create('User'); + echo __d('acl', 'user'); + echo '
'; + echo $this->Form->input($user_display_field, array('label' => false, 'div' => false)); + echo ' '; + echo $this->Form->end(array('label' =>__d('acl', 'filter'), 'div' => false)); + echo '
'; + ?> + + + Paginator->sort(__d('acl', 'user'), $user_display_field)); + + echo $this->Html->tableHeaders($headers); + ?> + + '; + echo ' '; + $title = __d('acl', 'Manage user specific rights'); + + $link = '/admin/acl/aros/user_permissions/' . $user[$user_model_name][$user_pk_name]; + if(Configure :: read('acl.gui.users_permissions.ajax') === true) + { + $link .= '/ajax:true'; + } + + echo ' '; + + echo ''; + } + ?> + + + +
' . $user[$user_model_name][$user_display_field] . '' . $this->Html->link($this->Html->image('/acl/img/design/lock.png'), $link, array('alt' => $title, 'title' => $title, 'escape' => false)) . '
+ Paginator->prev('<< ' . __d('acl', 'previous'), array(), null, array('class'=>'disabled'));?> + | + Paginator->numbers(array('modulus' => 5, 'first' => 2, 'last' => 2, 'after' => ' ', 'before' => ' '));?> + | + Paginator->next(__d('acl', 'next') . ' >>', array(), null, array('class' => 'disabled'));?> +
+ +

+ +

+ + + + '; + + echo $role[$role_model_name][$role_display_field]; + if($role[$role_model_name][$role_pk_name] == $user[$user_model_name][$role_fk_name]) + { + echo $this->Html->image('/acl/img/design/tick.png'); + } + else + { + $title = __d('acl', 'Update the user role'); + echo $this->Html->link($this->Html->image('/acl/img/design/tick_disabled.png'), array('plugin' => 'acl', 'controller' => 'aros', 'action' => 'update_user_role', 'user' => $user[$user_model_name][$user_pk_name], 'role' => $role[$role_model_name][$role_pk_name]), array('title' => $title, 'alt' => $title, 'escape' => false)); + } + + echo ''; + } + ?> + +
+ +

+ + '; + echo $this->Html->image('/acl/img/design/bulb24.png') . __d('acl', 'This user has specific permissions'); + echo ' ('; + echo $this->Html->link($this->Html->image('/acl/img/design/cross2.png', array('style' => 'vertical-align:middle;')) . ' ' . __d('acl', 'Clear'), '/admin/acl/aros/clear_user_specific_permissions/' . $user[$user_model_name][$user_pk_name], array('confirm' => __d('acl', 'Are you sure you want to clear the permissions specific to this user ?'), 'escape' => false)); + echo ')'; + echo '
'; + } + ?> + + + + Html->tableHeaders($headers); + ?> + + + $ctrl_infos) + { + if($previous_ctrl_name != $controller_name) + { + $previous_ctrl_name = $controller_name; + + $color = (isset($color) && $color == 'color1') ? 'color2' : 'color1'; + } + + foreach($ctrl_infos as $ctrl_info) + { + //debug($ctrl_info); + + echo ' + '; + + echo ''; + + echo ''; + echo ' + '; + } + } + } + ?> + $plugin_ctrler_infos) + { + echo ' + '; + + foreach($plugin_ctrler_infos as $plugin_ctrler_name => $plugin_methods) + { + if($previous_ctrl_name != $plugin_ctrler_name) + { + $previous_ctrl_name = $plugin_ctrler_name; + + $color = (isset($color) && $color == 'color1') ? 'color2' : 'color1'; + } + + foreach($plugin_methods as $method) + { + echo ' + '; + + echo ''; + //debug($method['name']); + + echo ''; + echo ' + '; + } + } + } + } + ?> +
' . $controller_name . '->' . $ctrl_info['name'] . ''; + echo ''; + + if($ctrl_info['permissions'][$user[$user_model_name][$user_pk_name]] == 1) + { + $this->Js->buffer('register_user_toggle_right(true, "' . $this->Html->url('/') . '", "right__' . $user[$user_model_name][$user_pk_name] . '_' . $controller_name . '_' . $ctrl_info['name'] . '", "' . $user[$user_model_name][$user_pk_name] . '", "", "' . $controller_name . '", "' . $ctrl_info['name'] . '")'); + + echo $this->Html->image('/acl/img/design/tick.png', array('class' => 'pointer')); + } + elseif($ctrl_info['permissions'][$user[$user_model_name][$user_pk_name]] == 0) + { + $this->Js->buffer('register_user_toggle_right(false, "' . $this->Html->url('/') . '", "right__' . $user[$user_model_name][$user_pk_name] . '_' . $controller_name . '_' . $ctrl_info['name'] . '", "' . $user[$user_model_name][$user_pk_name] . '", "", "' . $controller_name . '", "' . $ctrl_info['name'] . '")'); + + echo $this->Html->image('/acl/img/design/cross.png', array('class' => 'pointer')); + } + elseif($ctrl_info['permissions'][$user[$user_model_name][$user_pk_name]] == -1) + { + echo $this->Html->image('/acl/img/design/important16.png'); + } + + echo ''; + + echo ' '; + echo $this->Html->image('/acl/img/ajax/waiting16.gif', array('id' => 'right__' . $user[$user_model_name][$user_pk_name] . '_' . $controller_name . '_' . $ctrl_info['name'] . '_spinner', 'style' => 'display:none;')); + + echo '
' . __d('acl', 'Plugin') . ' ' . $plugin_name . '
' . $plugin_ctrler_name . '->' . $method['name'] . ''; + echo ''; + + if($method['permissions'][$user[$user_model_name][$user_pk_name]] == 1) + { + $this->Js->buffer('register_user_toggle_right(true, "' . $this->Html->url('/') . '", "right_' . $plugin_name . '_' . $user[$user_model_name][$user_pk_name] . '_' . $plugin_ctrler_name . '_' . $method['name'] . '", "' . $user[$user_model_name][$user_pk_name] . '", "' . $plugin_name . '", "' . $plugin_ctrler_name . '", "' . $method['name'] . '")'); + + echo $this->Html->image('/acl/img/design/tick.png', array('class' => 'pointer')); + } + elseif($method['permissions'][$user[$user_model_name][$user_pk_name]] == 0) + { + $this->Js->buffer('register_user_toggle_right(false, "' . $this->Html->url('/') . '", "right_' . $plugin_name . '_' . $user[$user_model_name][$user_pk_name] . '_' . $plugin_ctrler_name . '_' . $method['name'] . '", "' . $user[$user_model_name][$user_pk_name] . '", "' . $plugin_name . '", "' . $plugin_ctrler_name . '", "' . $method['name'] . '")'); + + echo $this->Html->image('/acl/img/design/cross.png', array('class' => 'pointer')); + } + elseif($method['permissions'][$user[$user_model_name][$user_pk_name]] == -1) + { + echo $this->Html->image('/acl/img/design/important16.png'); + } + else + { + echo '?'; + } + + echo ''; + + echo ' '; + echo $this->Html->image('/acl/img/ajax/waiting16.gif', array('id' => 'right_' . $plugin_name . '_' . $user[$user_model_name][$user_pk_name] . '_' . $plugin_ctrler_name . '_' . $method['name'] . '_spinner', 'style' => 'display:none;')); + + echo '
+ Html->image('/acl/img/design/tick.png') . ' ' . __d('acl', 'authorized'); + echo '   '; + echo $this->Html->image('/acl/img/design/cross.png') . ' ' . __d('acl', 'blocked'); + ?> + +element('design/footer'); +?> \ No newline at end of file diff --git a/View/Aros/admin_users.ctp b/View/Aros/admin_users.ctp new file mode 100644 index 0000000..c5bcb61 --- /dev/null +++ b/View/Aros/admin_users.ctp @@ -0,0 +1,89 @@ +element('design/header'); +?> + +element('Aros/links'); +?> + +Form->create('User', array('url' => array('plugin' => 'acl', 'controller' => 'aros', 'action' => 'admin_users'))); +echo __d('acl', 'name'); +echo '
'; +echo $this->Form->input($user_display_field, array('label' => false, 'div' => false)); +echo ' '; +echo $this->Form->end(array('label' =>__d('acl', 'filter'), 'div' => false)); +echo '
'; +?> + + + Paginator->sort($user_display_field, __d('acl', 'name'))); + + foreach($roles as $role) + { + $headers[] = $role[$role_model_name][$role_display_field]; + $column_count++; + } + + echo $this->Html->tableHeaders($headers); + + ?> + + +'; + echo ' '; + + foreach($roles as $role) + { + if(isset($user['Aro']) && $role[$role_model_name][$role_pk_name] == $user[$user_model_name][$role_fk_name]) + { + echo ' '; + } + else + { + $title = __d('acl', 'Update the user role'); + echo ' '; + } + } + + //echo ' '; + + echo ''; +} +?> + + + +
' . $user[$user_model_name][$user_display_field] . '' . $this->Html->image('/acl/img/design/tick.png') . '' . $this->Html->link($this->Html->image('/acl/img/design/tick_disabled.png'), '/admin/acl/aros/update_user_role/user:' . $user[$user_model_name][$user_pk_name] . '/role:' . $role[$role_model_name][$role_pk_name], array('title' => $title, 'alt' => $title, 'escape' => false)) . '' . (isset($user['Aro']) ? $this->Html->image('/acl/img/design/tick.png') : $this->Html->image('/acl/img/design/cross.png')) . '
+ Paginator->prev('<< ' . __d('acl', 'previous'), array(), null, array('class'=>'disabled'));?> + | + Paginator->numbers(array('modulus' => 5, 'first' => 2, 'last' => 2, 'after' => ' ', 'before' => ' '));?> + | + Paginator->next(__d('acl', 'next') . ' >>', array(), null, array('class' => 'disabled'));?> +
+ + + +
+ +

+ +
+ + +element('design/footer'); +?> \ No newline at end of file diff --git a/View/Aros/ajax_role_denied.ctp b/View/Aros/ajax_role_denied.ctp new file mode 100644 index 0000000..ad1f98e --- /dev/null +++ b/View/Aros/ajax_role_denied.ctp @@ -0,0 +1,15 @@ +'; + + if(isset($acl_error)) + { + $title = isset($acl_error_aro) ? __d('acl', 'The role node does not exist in the ARO table') : __d('acl', 'The ACO node is probably missing. Please try to rebuild the ACOs first.') ; + echo $this->Html->image('/acl/img/design/important16.png', array('class' => 'pointer', 'alt' => $title, 'title' => $title)); + } + else + { + echo $this->Html->image('/acl/img/design/cross.png', array('class' => 'pointer', 'alt' => 'denied')); + } + +echo ''; +?> \ No newline at end of file diff --git a/View/Aros/ajax_role_granted.ctp b/View/Aros/ajax_role_granted.ctp new file mode 100644 index 0000000..cdc8874 --- /dev/null +++ b/View/Aros/ajax_role_granted.ctp @@ -0,0 +1,15 @@ +'; + + if(isset($acl_error)) + { + $title = isset($acl_error_aro) ? __d('acl', 'The role node does not exist in the ARO table') : __d('acl', 'The ACO node is probably missing. Please try to rebuild the ACOs first.') ; + echo $this->Html->image('/acl/img/design/important16.png', array('class' => 'pointer', 'alt' => $title, 'title' => $title)); + } + else + { + echo $this->Html->image('/acl/img/design/tick.png', array('class' => 'pointer', 'alt' => 'granted')); + } + +echo ''; +?> \ No newline at end of file diff --git a/View/Aros/ajax_user_denied.ctp b/View/Aros/ajax_user_denied.ctp new file mode 100644 index 0000000..76fd3b9 --- /dev/null +++ b/View/Aros/ajax_user_denied.ctp @@ -0,0 +1,27 @@ +'; + + if(isset($acl_error)) + { + if(isset($acl_error_aro)) + { + $title = __d('acl', 'The user node does not exist in the ARO table'); + } + elseif(isset($acl_error_aco)) + { + $title = __d('acl', 'The ACO node is probably missing. Please try to rebuild the ACOs first.'); + } + else + { + $title = __d('acl', 'The ARO or the ACO node is probably missing. Please try to rebuild the ACOs first.'); + } + + echo $this->Html->image('/acl/img/design/important16.png', array('class' => 'pointer', 'alt' => $title, 'title' => $title)); + } + else + { + echo $this->Html->image('/acl/img/design/cross.png', array('class' => 'pointer')); + } + +echo ''; +?> \ No newline at end of file diff --git a/View/Aros/ajax_user_granted.ctp b/View/Aros/ajax_user_granted.ctp new file mode 100644 index 0000000..d674529 --- /dev/null +++ b/View/Aros/ajax_user_granted.ctp @@ -0,0 +1,27 @@ +'; + + if(isset($acl_error)) + { + if(isset($acl_error_aro)) + { + $title = __d('acl', 'The user node does not exist in the ARO table'); + } + elseif(isset($acl_error_aco)) + { + $title = __d('acl', 'The ACO node is probably missing. Please try to rebuild the ACOs first.'); + } + else + { + $title = __d('acl', 'The ARO or the ACO node is probably missing. Please try to rebuild the ACOs first.'); + } + + echo $this->Html->image('/acl/img/design/important16.png', array('class' => 'pointer', 'alt' => $title, 'title' => $title)); + } + else + { + echo $this->Html->image('/acl/img/design/tick.png', array('class' => 'pointer')); + } + +echo ''; +?> \ No newline at end of file diff --git a/View/Elements/Acos/links.ctp b/View/Elements/Acos/links.ctp new file mode 100644 index 0000000..228cb53 --- /dev/null +++ b/View/Elements/Acos/links.ctp @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/View/Elements/Aros/links.ctp b/View/Elements/Aros/links.ctp new file mode 100644 index 0000000..057cac9 --- /dev/null +++ b/View/Elements/Aros/links.ctp @@ -0,0 +1,21 @@ + \ No newline at end of file diff --git a/View/Elements/design/footer.ctp b/View/Elements/design/footer.ctp new file mode 100644 index 0000000..7f3effd --- /dev/null +++ b/View/Elements/design/footer.ctp @@ -0,0 +1,7 @@ +Js)) +{ + echo $this->Js->writeBuffer(); +} +?> + \ No newline at end of file diff --git a/View/Elements/design/header.ctp b/View/Elements/design/header.ctp new file mode 100644 index 0000000..f7faafe --- /dev/null +++ b/View/Elements/design/header.ctp @@ -0,0 +1,24 @@ +Html->css('/acl/css/acl.css'); +?> +
+ + Session->flash('plugin_acl'); + ?> + +

+ + params['controller']; + + $links = array(); + $links[] = $this->Html->link(__d('acl', 'Permissions'), '/admin/acl/aros/index', array('class' => ($selected == 'aros' )? 'selected' : null)); + $links[] = $this->Html->link(__d('acl', 'Actions'), '/admin/acl/acos/index', array('class' => ($selected == 'acos' )? 'selected' : null)); + + echo $this->Html->nestedList($links, array('class' => 'acl_links')); + } + ?> \ No newline at end of file diff --git a/View/Elements/flash_error.ctp b/View/Elements/flash_error.ctp new file mode 100644 index 0000000..0d348cf --- /dev/null +++ b/View/Elements/flash_error.ctp @@ -0,0 +1,13 @@ +
+ACL: +Html->nestedList($message); +} +else +{ + echo $message; +} +?> +
\ No newline at end of file diff --git a/View/Elements/flash_message.ctp b/View/Elements/flash_message.ctp new file mode 100644 index 0000000..1726d31 --- /dev/null +++ b/View/Elements/flash_message.ctp @@ -0,0 +1,3 @@ +
+ ACL: +
\ No newline at end of file diff --git a/View/Errors/missing_aco_nodes.ctp b/View/Errors/missing_aco_nodes.ctp new file mode 100644 index 0000000..0f500be --- /dev/null +++ b/View/Errors/missing_aco_nodes.ctp @@ -0,0 +1,10 @@ +'; + +echo ' ' . $message . ''; +echo '

 

'; +echo '

 

'; +echo '

' . $this->Html->link(__d('acl', 'go to homepage'), '/') . '

'; + +echo '
'; +?> \ No newline at end of file diff --git a/View/Helper/AclHtmlHelper.php b/View/Helper/AclHtmlHelper.php new file mode 100644 index 0000000..438a4c7 --- /dev/null +++ b/View/Helper/AclHtmlHelper.php @@ -0,0 +1,27 @@ +Session->read('Alaxos.Acl.permissions'); + if(!isset($permissions)) + { + $permissions = array(); + } + + $aco_path = AclRouter :: aco_path($url); + + if(isset($permissions[$aco_path]) && $permissions[$aco_path] == 1) + { + return parent::link($title, $url, $options, $confirmMessage); + } + else + { + return null; + } + } +} \ No newline at end of file diff --git a/webroot/css/acl.css b/webroot/css/acl.css new file mode 100644 index 0000000..1764926 --- /dev/null +++ b/webroot/css/acl.css @@ -0,0 +1,142 @@ +/** + * @author Nicolas Rod + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + * @link http://www.alaxos.ch + */ + +#plugin_acl +{ + background-color:#ffffff; + padding:5px; + margin:5px auto 5px auto; + /*max-width:600px;*/ +} +#plugin_acl tr +{ + margin:0px; +} +#plugin_acl th, #plugin_acl td +{ + padding:0px 5px; + margin:10px; + line-height:25px; + min-width:38px; + text-align:left; +} +#plugin_acl td img +{ + vertical-align: middle; +} +#plugin_acl p +{ + margin:5px 0px; +} +.acl_links +{ + margin:15px 0px; +} +ul.acl_links +{ + list-style: none ; + margin: 0 ; + padding: 0 ; + overflow: hidden ; +} +ul.acl_links li +{ + float: left ; + /*width: 150px ;*/ + /*border: 1px solid #600 ;*/ + margin-right: 1px ; + color: #fff ; + /*background: #c00 ;*/ +} +ul.acl_links li a +{ + display: block ; + background:#3F3834; + color: #fff ; + font: 1em "Trebuchet MS", Arial, sans-serif; + line-height: 1em ; + padding: 4px 10px ; + text-align: center ; + text-decoration: none ; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +ul.acl_links a:hover, ul.acl_links li a:focus, ul.acl_links li a:active +{ + background: #900 ; + text-decoration: underline ; +} +ul.acl_links li a.selected +{ + background: #900; +} + +.separator +{ + height:20px; +} +.pointer +{ + cursor: pointer; +} +.color1 +{ + background-color:#ffffff; +} +tr.color1:hover +{ + background-color:#cccccc; +} +.color2 +{ + background-color:#cccccc; +} +tr.color2:hover +{ + background-color:#ffffff; +} +tr.title +{ + background-color:#444444; + color:#ffffff; +} +.line_warning +{ + background-image: url('../img/design/warning_small.png'); + background-repeat: no-repeat; + background-position: right; + overflow:visible; + color:red; +} +.warning +{ + background-image: url('../img/design/warning_medium.gif'); + background-repeat: no-repeat; + padding-left:40px; + color:red; + line-height:32px; +} +#pluginAclflashMessage.message +{ + width:300px; + margin-top:10px; + margin-bottom:10px; + margin-left:auto; + margin-right:auto; + color:#04AF0D; + text-align:center; +} +#pluginAclflashMessage.error +{ + width:300px; + margin-top:10px; + margin-bottom:10px; + margin-left:auto; + margin-right:auto; + color:#ff0000; + text-align:center; +} \ No newline at end of file diff --git a/webroot/empty b/webroot/empty new file mode 100644 index 0000000..e69de29 diff --git a/webroot/img/ajax/waiting16.gif b/webroot/img/ajax/waiting16.gif new file mode 100644 index 0000000000000000000000000000000000000000..2cf7e31d59986f4dea815b91497b148cf393a496 GIT binary patch literal 1849 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 literal 0 HcmV?d00001 diff --git a/webroot/img/design/alert_medium.gif b/webroot/img/design/alert_medium.gif new file mode 100644 index 0000000000000000000000000000000000000000..0d249d61ffb0cf3a515fd84eda4bc0b9545f949a GIT binary patch literal 1717 zcmV;m21@xyNk%w1VITk?0Qdg@$kNiZ007Am0Qvd(xx>W&d3nf+ivR!r>AJeB0RZfC zbM5Z#rHzf~C;`S76y@64(Ha8(Sy|Z$1mYb5(p6Q{&CIQvo4UHX|2jMWDl4{DKmVMZ z$XZ&*DJbVFD8)!fdjJ5ni;LL7!JKw>|AvOb1p@z8SJ)^5|8{l%eSMk$0NmW%k2^c& zItcXi^yD-&v#hL<0s`V39K^l6|CN>hiHY6R)ZC<`!4)b91&SD3n%K@$vEhW@i6tYW||4se5?;s;d7$K!gAQw{vs< zO-=m#{Pa>%>^?sKj*g~TS&}O&|B;cp008YyPXA$H{0j=hd}F=}3cdgU*L8LOBqjeH z9sgotW4Gg0Tq#rT_rel$85gTBQaC|7U2v1qQbU2md!Wy9EH}>FMU@=llQv|4>iv zKtTUbQ2$9rs+XA8fPlqbLESVo-K3wiv$Mg*#`+i)_4oJv0Rf-`0HOp0@t~jjUtgdQ z5Vv4R*0QqwZ)*E+aN%KL|7d90N*>uxJ>*Oo?d*C_9 zQbxB&L%61)!Xp;=X=u|w7WsyT|Ad3^KRNG;ip8_D|8#KtX=&Nb&8nZE#{dBEdwb3a z0l2ZT`)q9gU0vgyou-nKFNJ*arVv4=rSwZDJj6Os?4aM%dM{efPcz#S@ca! z{}UAdOibICm*1S5+2rK-s;ceC$oybn`!O-bl!NwWW~DAJ*kEAu0s^0ii1G~q^mcdt z{r&y_|NsC0A^8LW00930EC2ui03ZM$06+-;0RIUbNbnylB=yt<(G#WifO!vi7>000nMY%rNkM7&^!3R3)20W**|QVJ_L5tT&|L@43H0shcofdVNM zP(>6)_`nJg!ZZcP0>`|OKrbYSa~L6E-0{R8nfMb)Cpv^dhzWYEv0?$~WVVM00x^(4 z4hf7=1R+m6l7SpD{M23`eBj|lI}tEaz#uVvVTMG$j4(a|A6g!#7v-VQ3#$Fpvi*fP&Y?E4nn$zyy?5>Ix^hG&&Fxtu!D&8UZxo zzzdaBLPj}8G{V;#5-0$SbLOo773vE@9e|885EdFhUkD z%mauD3CJT57vgrX24b}tf`&9&9^ir}2FP1O3RP&qh$3mkU`04}@B&BxV`OL~5e1}> z$Rr^}0)rAYP*z0|tZeAPgFD0oNh8%nf#DD|uOY-L$Q&TX6d^Pt4vIw}r4dsq1hRq^ zpxTo{6hd@k0wI)8Ldy*Xd%^*c-4NwN6jh`^4k9Wf($5HQj9Wt$q*-DW26#{a4*=KT z@WdUKm@ot@;-r&G2{GJ~bHqP&B=O)TDP&>79c&kaB|dQI&?N>>SfU3bC{W|ZaMlbI zxC&pmVS)))#lZ#~B2AKq6B%G|M+8JHp#liM*ig^_`mC7)AjDu53I*US0Lv7Z$Pfnx zm#i$DEzY^Xz%QIbsSOoWbfAm?`%GYjD9Yu)#jBc1@(l}9eWBd=Uwm-}5PxfmmJ4*W LFUg;c1_S^*X$lya literal 0 HcmV?d00001 diff --git a/webroot/img/design/alert_small.gif b/webroot/img/design/alert_small.gif new file mode 100644 index 0000000000000000000000000000000000000000..f9bec77d980b05e257699413030f88c795b9793a GIT binary patch literal 121 zcmZ?wbhEHb6krfwIK;rvz`*byi2ef!Fat&^{$ycfU|?a;0g3}v3NSD*+j*?Iuy;bE z!^`f;U9s$Eq^|2GY~T!iAh=Ys@9oT0Z*-Q&{R!H+_wv@8IifrZ-MSs0vbFF`u}Et9 Nu*PqFgcB2kH2@0!D{KG& literal 0 HcmV?d00001 diff --git a/webroot/img/design/bulb16.png b/webroot/img/design/bulb16.png new file mode 100644 index 0000000000000000000000000000000000000000..385154b228759c58d9f2d833639deef33861f021 GIT binary patch literal 723 zcmV;^0xbQBP)<7Wkh@#y~vrWbW$S zaKIZ<6pgO7BuEz5!|Ss*PO+W~z&owqV!!|jq1&^UW<*I;M zn=_M_fiphT0B-_ZLDqAUm(;eZA*~}RVzVO&imGX%tchbR6HpYz-EUy%H^4n;@d{t6 z@eO>bW=9sbYl2`PNy0``z|}ynko`^j-=OkgqmX6YM@D~E+I#q9EOw3wLYC#FM0TsNl*@0zEo>GO zMaMFmx%fKw4Ni_rl7uh@4DtqvX=os}VL|>xgQ&Xq|>u@-PMA3wX35QJqugw5gEEeh)c{&H~&3Yrl@r z9|b&n3euq-$qwHmkRJg2z`27T8K4QM;+DaljCFqm7ywFkZ!Qnfr~?21002ovPDHLk FV1k_FLP-Ds literal 0 HcmV?d00001 diff --git a/webroot/img/design/bulb24.png b/webroot/img/design/bulb24.png new file mode 100644 index 0000000000000000000000000000000000000000..ca9561fb6eace196aa5cf94a4025ae48dc4e70ef GIT binary patch literal 977 zcmV;?11|iDP)xBQYczeIxNk@ESD|K!_z?XrTy#E#cNe zq3yQpc5j}k)evo=Yjl$@XJ&HteDj?-bA~nygZiHzF0|NorJJH@nhXU%GhjDt#10l2 zKX#M`v!v^KP}4M#ECp|NmQIlWb|IQ>zj)N`IpaC#skRFZnn9H*s+Nc*((}(hO$F}1 z8*c)?*MLP+3SdVzK>MxB7cRBbyS$R3C0CQ#rD#%Kh$bZ&(G+*y+j{y~Q$u5C&m#;f zdWot+u}~3$<_=$TtGmJF<5}cDAcf};;}lq{z%wW=Dq>(h`K`)PQQvXI?FRqWVhRcp zKyLS5@VR|iRZpcPbwN?}P2$L7ge@$C8AQ>#ZWzlOa;(F5=rAZaU@ArML&YAaeQ#=0 zjlu5JU+V^CXu1KRDFbSNhSN5x9rkMQuQa6qe!#jx@uI9|NKg_ms~K8aQYBENszAZO zL9h&szz=~xYf1s6NK0hom32{-c$SeM7LpWQjf+_+kx>*1PbnXI;! zlC!Cds#1{jXCIf}R@hk9VZ~g9fbBichXbHs+$=#TG`}3~8~HTaQeR#tSXgAYvAD8~ z!&PNG1m-xq726&Tk4*-{i*wr%6gvY0(0}9Mt6EQE-TuZ}rz5 zl1pfmXB38?@0*$EOcI;hNJ5iHyw#`_D<+Ey(t?XhOLl^ng^SURf+GA21zi{y1{{!5 z5QL7#g;8=>?7hOBWP~@Qv%4i?;^z?o7$2sh!G| zts6JQ<4rGsx`hNvL;&d8r%uFIa{QCF&sB3vJ3Xhnz3G3(a_m%-#>gcR&Ll0E*wJ36qI~C2ft2!

!GOpKDtrJ2lSaNQ|Hgjn@93PsJ(gZ`2+IBy96 z0wag|dVeYUtj2Xcip4zE2Iz1NmGK?q-I(0Ec_nX5@MXf0%df=eg{JcD1;K)00000NkvXXu0mjf Dmc(vD literal 0 HcmV?d00001 diff --git a/webroot/img/design/cross.png b/webroot/img/design/cross.png new file mode 100644 index 0000000000000000000000000000000000000000..1514d51a3cf1b67e1c5b9ada36f1fd474e2d214a GIT binary patch literal 655 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 literal 0 HcmV?d00001 diff --git a/webroot/img/design/lock.png b/webroot/img/design/lock.png new file mode 100644 index 0000000000000000000000000000000000000000..f6db9146028e62429d16490680d600995be2a866 GIT binary patch literal 1583 zcmV+~2GIG5P)F`}@-E+gBIPnbY|O zDEF6;#W0Tp1P~*72;g%-clWYJpnSfPk`%v;j3|SM2tUK$zkeA%efr99=gw1xCr{om zeEarg*5%8m8dt5F^%9>$VDA>{7zzx}pTB0< zz55KqfCxIEzJ3naasvZZeLp`Nu>7Ate;9uJ_`&e& z*DtWeATcg3E(T6cPKMvVe>1FKe~{tQr8_tG>{;V`^5otJ*c<_~7a)LG2*uU!-+vku z6(zxzgTUv{pBaAs{K@d*#XF!+UjrTTlR-vCn1P?4lYxhahe2FioFO>ak>UOOkLo5S zPW3sH5ub+qdgap1jTQ=+Psveoakz1|}v}4Iq;jh*`1O0T4iV9q{MR zUpruyWBC64J2-KH9Pser%?;2v1^NCpC}u!O1Bl-~d2+Ae{{2_r1p5B{dja{QC6=n6lZymV@xGU%weXe0ci=$x`Hm^>63SMc2N5{Q*|{=FJ-h zUS4jn89=~>E4l#!h)@)OvljMZNjH38Vm-Yl!W`=xT zIXMPiSvjgyxt||DV)zWqnr}bo&^ z4k#s1>;O?yb%tlBB^W;LJe30Eb^`G;XvxR`5I`6X`1tid1G}II(2XmpVmTOm`N_b3 z_a)G5P;tN@2r4sR4gd%s3CtD{{4p)d58iTg zu@pf=*;oKT0I}dqxv(f;VS-d6APZrJ{rd+s6p4*Z48;N1i)4TR!r=g*Z+-$pfQKDo z`QQHtAE8)Eq!^wM00)X9)X{IX2E=Bt&@Km7o;rXK_C{Q?pP2q0`-Gf=4TL2E5;Laine04NcFYJ>Nn h5+7(UIG+Oq7yv4^lt4U>BKZIS002ovPDHLkV1g3O%dh|d literal 0 HcmV?d00001 diff --git a/webroot/img/design/question.gif b/webroot/img/design/question.gif new file mode 100644 index 0000000000000000000000000000000000000000..88f037998c269cfd86f78048e7096eb54c02030f GIT binary patch literal 1210 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 Iod*N}J9ZiLD*ylh literal 0 HcmV?d00001 diff --git a/webroot/img/design/success_small.gif b/webroot/img/design/success_small.gif new file mode 100644 index 0000000000000000000000000000000000000000..b1cdeb763332852fec845afa4b80a49c8aea458f GIT binary patch literal 1024 zcmZ?wbhEHb6krfw_|Cxa|NsBL|Nj2@`}@nUPal7Nc>DeJ%O6i)et+`(>%(VX9zXf? z@bSlo58gd^_~yZb*AK3}yL9u-mD6tzoO-kW;NxxkpX}K8c>CVRTem%2zwP0=z4y0n zdAN4V{nZ;D&D(r`^{(4nH{V^k;qJ1Hx0i3bxpm9!Yp*ZZc45n^%d_U(n7HWr)CJe4thzL7!L=!~u1}bEX~N7aJ@YU1&$!S% z<6_sGb6qpec1}IpKK)GFv@`R4&i=fk$+ZVEiVr0h98PN5o0EGaDdV_j-l2rt!-=_v6DkfQ7axqsJD5_hJXL8x@_@bTBHQQ1PcSJ=WvMJscUA!%- z0Lb2NmA^eAbBBM!rg`hmaz;TzsmQ%)KLxLl-%$g61U))%kn&&C?I5Iyz z(kWRd;H#m**e}4N-y>1Ekn!YV9%lX>f{PkYPSFls;qmfA%SEO}l}8B)MXB90j1qKQ zZcbRyalq6t!{TL9n~xM1gV2);f}Rf)1>Cp9R2*2w#K35=XTt%NfWS^wFAfHc4^xlJ znQEJG>VzCVHeH38fraDK^S*w?$t?E_zC7fS(GV!(5t?$mMOlYQ)Z~;ME2E(CrX(vcfMuzxeas03CQae&W}aCdw~m|?5@#1^7U$t$um%97 Cf_I|; literal 0 HcmV?d00001 diff --git a/webroot/img/design/sync.png b/webroot/img/design/sync.png new file mode 100644 index 0000000000000000000000000000000000000000..01dc22961038e079c457b5b55748eeb4b9d9ff85 GIT binary patch literal 752 zcmV$qBb28k~k(!=6@#h^Bot{8B+|N#pPb!`@HAg^C}Lgm4$18 zh)jV@1Bl2HirlGp?iT;Olg>_Fxt&o@gXsWd&hhFqeyoP$?SX<$%cW6`vDftHLCtDy z=aiP2lb7!(wGW=MPIK|lNFnfIEtCSS0Yz^Sq1o_w{MRVMVVOqtFvl-^uj~^zWu4|? zm|PF669Jk^$){1X0K^k*4uyNf6D?wsn?#Y&s15<3d;KLl92NrWM0DDgwTC15?ag?m zT6V%p$%KUsKa+njgor|G&_)3f0Cr^|o$}(PY1eOoXf{`aT(`ry)9IfE1N$R;{`K)^ z+E_;r0Ud#e^bCNDo?k<2*xgRh?W)<+=^qDh?%UV0O1EcrwiLVD9!go1GPGO0$E%fv zYo7&2*RRJD4GQZ)@x-NH!h@pi*H_>DAp6f2$X82;m+F-mjhd7DKbYRn^RJwFG1YE& z`R(`R`|2Rq{q^zt7Y0#(e)C=`c_euB{K@Aim1`{jxpqVM#nB+a_*lr~#28^P#N*xa z{C*ffYn`1KPZC8!u~NqvbKmww&vWrT7i$gqwL(!FeXFm1ar54k>pF8Mj*U$_j-}I$ zC{^mYPcm=k1_r+8;`=VX=W+hkGr`0B#^Tqve@1J=@KB6rlcP9}B@$TO*g}L%e~19= z6f120y~Ej;Un1_hym0C`A`nS0`zR7R-H5e~ZJNz?=A)}`=AJTGey}=kt+}!IYc4x+ zEIFM#GJ>@RP;|Nx}+W02Os;LA@x$UNDeyZ+7HRAH-h(O45$V=&ef it+7k9@4fY(nEwH5Hs{AQG2a)rMyf zFQK~pm1x3+7!nu%-M`k}``c>^00{o_1pjWJUTfl8mg=3qGEl8H@}^@w`VUx0_$uy4 z2FhRqKX}xI*?Tv1DJd8z#F#0c%*~rM30HE1@2o5m~}ZyoWhqv>ql{V z1ZGE0lgcoK^lx+eqc*rAX1Ky;Xx3U%u#zG!m-;eD1Qsn@kf3|F9qz~|95=&g3(7!X zB}JAT>RU;a%vaNOGnJ%e1=K6eAh43c(QN8RQ6~GP%O}Jju$~Ld*%`mO1pU8P*7-ZbZ>KLZ*U+lnSp_Ufq@}0xwybFAi#%#fq@|}KQEO56)-X|e7nZL z$iTqBa9P*U#mSX{G{Bl%P*lRez;J+pfx##xwK$o9f#C}S14DXwNkIt%17i#W1A|CX zc0maP17iUL1A|C*NRTrF17iyV0~1e4YDEbH0|SF|enDkXW_m`6f}y3QrGjHhep0GJ zaAk2xYHqQDXI^rCQ9*uDVo7QW0|Nup4h9AW240u^5(W3f%sd4n162kpgNVo|1qcff zJ_s=cNG>fZg9jx8g8+j9g8_pBLjXe}Lp{R+hNBE`7{wV~7)u#fFy3PlV+vxLz;uCG zm^qSpA@ds+OO_6nTdaDlt*rOhEZL^9ePa)2-_4=K(Z%tFGm-NGmm}8}ZcXk5JW@PU zd4+f<@d@)yL(o<5icqT158+-B6_LH7;i6x}CW#w~Uy-Pgl#@Irl`kzV zeL|*8R$ca%T%Wv){2zs_iiJvgN^h0dsuZZ2sQy$tsNSU!s;Q*;LF<6_B%M@UD?LHI zSNcZ`78uqV#TeU~$eS{ozBIdFzSClfs*^S+dw;4dus<{M;#|MXC)T}S9v!D zcV!QCPhBq)ZyO(X-(bH4|NMaZz==UigLj2o41F2S6d@OB6%`R(5i>J(Puzn9wnW{e zu;hl6HK{k#IWjCVGqdJqU(99Cv(K+6*i`tgSi2;vbXD1#3jNBGs$DgVwO(~o>mN4i zHPtkqZIx>)Y(Ls5-Br|mx>vQYvH$Kwn@O`L|D75??eGkZnfg$5<;Xeg_o%+-I&+-3%01W^SH2RkDT>t<8AY({UO#lFTB>(_`g8%^e z{{R4h=>PzAFaQARU;qF*m;eA5Z<1fdMgRZ+Eemp{fKy-VV*#8n=x@M8uHexS|k2UJtzA5AIrj zc+7+eHjTKf5JX;b?mS@1AnvxVoiQOHHuboq{@--74)6RB@PvoY7kz5WHAV!v)ixdx zApt%;s!368gu2mJ+!OGLMI|{>TS{K)bNX16lY-ij`cyY5Eee^GEs8py*<;Ps0EPh; Um%50t@&Et;07*qoM6N<$f&vTjoB#j- literal 0 HcmV?d00001 diff --git a/webroot/img/design/warning_medium.gif b/webroot/img/design/warning_medium.gif new file mode 100644 index 0000000000000000000000000000000000000000..ab6b850c0fec1bfea48e2a86c2473ede8b5e109f GIT binary patch literal 1202 zcmchW{Y%tY6vj`~MgtMcR+Ocpv@u&2+jMKTu@^QJOA31%s;z`t+iRs;OxgD05=d=7 z^k&2CLZ=r>DFw|;N_T_8ByvR$#pY-k1Ws?1KNLeyM6qX|``!MA?k~gP-20r*^PKN2 z$j_S<+K@pR^p5^NhR6~zkq{}NGKP#L!(@bvx~4T`Emc4 zm_$evN~DI=k}|1~qJTD}p@qk|t!|Dx))+QMj8Qihm9@sQv0|(`3N+aoX2W7w9Te`0 zHNr;3h=LJMjas8@RE%OOs38VuPy!1*42CwOp@qll47nPItrct4`NLRL%$CKnI=i4i zQ`m}FQMd;b?pkH5Viop~2Qcv(alk(y;1JXh12iac6&x50ZAe2)U2?9C8b_Gb1qpu` zi%Nt=kt^(i0!>z7MUF@s0e}nF5j5N)O5_1dyha>gf?+rWHN*gom%suC216Ut>Q>}# zqm3Fzu`vV*e;A8ORNVr-^*ai0qi&zxk{pzmyIZdprDOEcaohF`J7mv;TfT?o9C(u; zjn4sFLU{1xjr#O0e&(Od_d^B|J)kLWuKQ1XKkQ#>@}(}ke6DT(Fkg1ETT*5gpATo2 zzmSylIX>Uxl%Fp41uE0e6pnwHe9{#AJ2w%jjy?$#eOuIi;AQD^SwF2JZScXsgy5Vz zb#v?U;?;NehjY_*^j=PMlq}|8NwBVVzJK?zKu%xsY45W7>)X%#(CqI$T%8?R)78@O zu%)yzGEnwU-IB@UlS@MbBkOM+il@(ucdeR`Q`~)eZuy#~Nwqf?d{^-EK-u|tWykV| zQ%~$HxpFDv?8*4vuWFk97@X`p@IF+tuq(K2T=~aXZ1brU|ho*NP9C@^ziiQ^!^#4{> gFs*9i(`eq%E8V5)TXjFSG|zV-@+dIoOQPBT0a>UIX#fBK literal 0 HcmV?d00001 diff --git a/webroot/img/design/warning_small.png b/webroot/img/design/warning_small.png new file mode 100644 index 0000000000000000000000000000000000000000..6cca94d1a3b73fafb4bd3fb88aab42083516c4c0 GIT binary patch literal 789 zcmV+w1M2*VP)WdL?%ZZ04)F(7JTZgwspGB7YTATcsJF)=zaH6SZ6F)%Q_U7nx-000Mc zNliru)d3X?Cma?LsOkU!010qNS#tmY3lRVS3lRZ-WM7d0000DMK}|sb0I`n?{9y$E z00Ed#OjJex0RQN_6YjMFfgh5*!q0M&&8 z^3NCh%LDhr0PnW}>9GOfr~urd0Iqxhs(1j0Mv>A*NgzwhydA#0MeHkG$sJ- z%OU&A0s6-P^}hh^w*bA405T*1w15EHmH^$80NRWI*pv&-z*G9v5&h5w`^y6P#sJ@} z0BKMFZBhWvmjd6P0^XVd+?W8{mjcF}Hty3Z{?-rv(+T{}1Np}Q=BxtasR84o1L2_p z-J%T6#9;j19{<`E{?!fr&jmy`0QI{7@U#HvtN`h#0?Ma9@Y^!~-W&PY75UQ-R6_vy z!~pib0Q0v1>9h{a!(;j2Dg59Z;l>w0IS)!c2>Hwe`o;kEzyj8{HR;wPj7stYC`{yRmz8g0)6gDsq(XI#l&xS3xf zI82fN0004WQchCm3h|I63tg5c5 zMG`0~E-5W5NAR< z!gq0XbNBG{^z!!c^#co7S=-p!8QR-BI666l_&U0J`UZwZ#wMm_<`$Mf0R=@RWffI< zHFXUQO)YH(27UoSAz=|wd3gy*DQOv5IhcT$I81 + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + * @link http://www.alaxos.ch + */ +function init_register_user_controller_toggle_right(app_root_url, user_id, plugin, controller, missing_aco_text) +{ + app_root_url = ensure_ends_with(app_root_url, "/"); + var plugin_param = (plugin == null || plugin == "" || typeof(plugin) == "undefined") ? '' : "/plugin:" + plugin; + + var url = app_root_url + "admin/acl/aros/get_user_controller_permission/" + user_id + plugin_param + "/controller:" + controller; + + $.ajax({ url: url, + dataType: "html", + cache: false, + success: function (data, textStatus) + { + //alert(data); + permissions = jQuery.parseJSON(data); + //alert(permissions); + + for(var action in permissions) + { + var start_granted = false; + var span_id = "right_" + plugin + "_" + user_id + "_" + controller + "_" + action; + + if(permissions[action] == true || permissions[action] == false) + { + if(permissions[action] == true) + { + icon_html = "\"granted\""; + start_granted = true; + } + else + { + icon_html = "\"denied\""; + start_granted = false; + } + + $("#" + span_id).html(icon_html); + + register_user_toggle_right(start_granted, app_root_url, span_id, user_id, plugin, controller, action); + } + else + { + icon_html = "\"""; + + $("#" + span_id).html(icon_html); + } + } + } + }); +} +function register_user_toggle_right(start_granted, app_root_url, span_id, user_id, plugin, controller, action) +{ + app_root_url = ensure_ends_with(app_root_url, "/"); + var plugin_param = (plugin == null || plugin == "" || typeof(plugin) == "undefined") ? '' : "/plugin:" + plugin; + + if(start_granted) + { + var url1 = app_root_url + "admin/acl/aros/deny_user_permission/" + user_id + plugin_param + "/controller:" + controller + "/action:" + action; + var url2 = app_root_url + "admin/acl/aros/grant_user_permission/" + user_id + plugin_param + "/controller:" + controller + "/action:" + action; + } + else + { + var url1 = app_root_url + "admin/acl/aros/grant_user_permission/" + user_id + plugin_param + "/controller:" + controller + "/action:" + action; + var url2 = app_root_url + "admin/acl/aros/deny_user_permission/" + user_id + plugin_param + "/controller:" + controller + "/action:" + action; + } + + $("#" + span_id).toggle(function() + { + $("#right_" + plugin + "_" + user_id + "_" + controller + "_" + action + "_spinner").show(); + + $.ajax({ url: url1, + dataType: "html", + cache: false, + success: function (data, textStatus) + { + $("#right_" + plugin + "_" + user_id + "_" + controller + "_" + action).html(data); + }, + complete: function() + { + $("#right_" + plugin + "_" + user_id + "_" + controller + "_" + action + "_spinner").hide(); + } + }); + }, + function() + { + $("#right_" + plugin + "_" + user_id + "_" + controller + "_" + action + "_spinner").show(); + + $.ajax({ url: url2, + dataType: "html", + cache: false, + success: function (data, textStatus) + { + $("#right_" + plugin + "_" + user_id + "_" + controller + "_" + action).html(data); + }, + complete: function() + { + $("#right_" + plugin + "_" + user_id + "_" + controller + "_" + action + "_spinner").hide(); + } + }); + }); +} + + +function init_register_role_controller_toggle_right(app_root_url, role_id, plugin, controller, missing_aco_text) +{ + app_root_url = ensure_ends_with(app_root_url, "/"); + var plugin_param = (plugin == null || plugin == "" || typeof(plugin) == "undefined") ? '' : "/plugin:" + plugin; + + var url = app_root_url + "admin/acl/aros/get_role_controller_permission/" + role_id + plugin_param + "/controller:" + controller; + + $.ajax({ url: url, + dataType: "html", + cache: false, + success: function (data, textStatus) + { + //alert(data); + permissions = jQuery.parseJSON(data); + //alert(permissions); + + for(var action in permissions) + { + var start_granted = false; + var span_id = "right_" + plugin + "_" + role_id + "_" + controller + "_" + action; + + if(permissions[action] == true || permissions[action] == false) + { + if(permissions[action] == true) + { + icon_html = "\"granted\""; + start_granted = true; + } + else + { + icon_html = "\"denied\""; + start_granted = false; + } + + $("#" + span_id).html(icon_html); + + register_role_toggle_right(start_granted, app_root_url, span_id, role_id, plugin, controller, action); + } + else + { + icon_html = "\"""; + + $("#" + span_id).html(icon_html); + } + } + } + }); +} + +function register_role_toggle_right(start_granted, app_root_url, span_id, role_id, plugin, controller, action) +{ + app_root_url = ensure_ends_with(app_root_url, "/"); + var plugin_param = (plugin == null || plugin == "" || typeof(plugin) == "undefined") ? '' : "/plugin:" + plugin; + + if(start_granted) + { + var url1 = app_root_url + "admin/acl/aros/deny_role_permission/" + role_id + plugin_param + "/controller:" + controller + "/action:" + action; + var url2 = app_root_url + "admin/acl/aros/grant_role_permission/" + role_id + plugin_param + "/controller:" + controller + "/action:" + action; + } + else + { + var url1 = app_root_url + "admin/acl/aros/grant_role_permission/" + role_id + plugin_param + "/controller:" + controller + "/action:" + action; + var url2 = app_root_url + "admin/acl/aros/deny_role_permission/" + role_id + plugin_param + "/controller:" + controller + "/action:" + action; + } + + $("#" + span_id).toggle(function() + { + $("#right_" + plugin + "_" + role_id + "_" + controller + "_" + action + "_spinner").show(); + + $.ajax({ url: url1, + dataType: "html", + cache: false, + success: function (data, textStatus) + { + $("#right_" + plugin + "_" + role_id + "_" + controller + "_" + action).html(data); + }, + complete: function() + { + $("#right_" + plugin + "_" + role_id + "_" + controller + "_" + action + "_spinner").hide(); + } + }); + }, + function() + { + $("#right_" + plugin + "_" + role_id + "_" + controller + "_" + action + "_spinner").show(); + + $.ajax({ url: url2, + dataType: "html", + cache: false, + success: function (data, textStatus) + { + $("#right_" + plugin + "_" + role_id + "_" + controller + "_" + action).html(data); + }, + complete: function() + { + $("#right_" + plugin + "_" + role_id + "_" + controller + "_" + action + "_spinner").hide(); + } + }); + }); +} + +function ensure_ends_with(text, trailing_text) +{ + if(text.length < trailing_text.length || text.substring(text.length - trailing_text.length) != trailing_text) + { + text = text + trailing_text; + } + + return text; +} \ No newline at end of file diff --git a/webroot/js/jquery.js b/webroot/js/jquery.js new file mode 100644 index 0000000..628ed9b --- /dev/null +++ b/webroot/js/jquery.js @@ -0,0 +1,4 @@ +/*! jQuery v1.6.4 http://jquery.com/ | http://jquery.org/license */ +(function(a,b){function cu(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cr(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"":"")+""),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cq(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cp(){cn=b}function co(){setTimeout(cp,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bv(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bl(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bd,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bk(a){f.nodeName(a,"input")?bj(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bj)}function bj(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bi(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bh(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bg(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i=0===c})}function U(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function M(a,b){return(a&&a!=="*"?a+".":"")+b.replace(y,"`").replace(z,"&")}function L(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;ic)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function J(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function D(){return!0}function C(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function K(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(K,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z]|[0-9])/ig,x=/^-ms-/,y=function(a,b){return(b+"").toUpperCase()},z=d.userAgent,A,B,C,D=Object.prototype.toString,E=Object.prototype.hasOwnProperty,F=Array.prototype.push,G=Array.prototype.slice,H=String.prototype.trim,I=Array.prototype.indexOf,J={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.4",length:0,size:function(){return this.length},toArray:function(){return G.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?F.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),B.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(G.apply(this,arguments),"slice",G.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:F,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;B.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!B){B=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",C,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",C),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&K()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):J[D.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!E.call(a,"constructor")&&!E.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||E.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(x,"ms-").replace(w,y)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c
a",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},m&&f.extend(p,{position:"absolute",left:"-1000px",top:"-1000px"});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="

",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
t
",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML="",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i=f.expando,j=typeof c=="string",k=a.nodeType,l=k?f.cache:a,m=k?a[f.expando]:a[f.expando]&&f.expando;if((!m||e&&m&&l[m]&&!l[m][i])&&j&&d===b)return;m||(k?a[f.expando]=m=++f.uuid:m=f.expando),l[m]||(l[m]={},k||(l[m].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?l[m][i]=f.extend(l[m][i],c):l[m]=f.extend(l[m],c);g=l[m],e&&(g[i]||(g[i]={}),g=g[i]),d!==b&&(g[f.camelCase(c)]=d);if(c==="events"&&!g[c])return g[i]&&g[i].events;j?(h=g[c],h==null&&(h=g[f.camelCase(c)])):h=g;return h}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e=f.expando,g=a.nodeType,h=g?f.cache:a,i=g?a[f.expando]:f.expando;if(!h[i])return;if(b){d=c?h[i][e]:h[i];if(d){d[b]||(b=f.camelCase(b)),delete d[b];if(!l(d))return}}if(c){delete h[i][e];if(!l(h[i]))return}var j=h[i][e];f.support.deleteExpando||!h.setInterval?delete h[i]:h[i]=null,j?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=j):g&&(f.support.deleteExpando?delete a[f.expando]:a.removeAttribute?a.removeAttribute(f.expando):a[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;d=e.value;return typeof d=="string"?d.replace(p,""):d==null?"":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=v:u&&(i=u)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.attr(a,b,""),a.removeAttribute(b),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(u&&f.nodeName(a,"button"))return u.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(u&&f.nodeName(a,"button"))return u.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==null?g:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabIndex=f.propHooks.tabIndex,v={get:function(a,c){var d;return f.prop(a,c)===!0||(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(u=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var w=/\.(.*)$/,x=/^(?:textarea|input|select)$/i,y=/\./g,z=/ /g,A=/[^\w\s.|`]/g,B=function(a){return a.replace(A,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=C;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=C);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),B).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},I=function(c){var d=c.target,e,g;if(!!x.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=H(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:I,beforedeactivate:I,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&I.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&I.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",H(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in G)f.event.add(this,c+".specialChange",G[c]);return x.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return x.test(this.nodeName)}},G=f.event.special.change.filters,G.focus=G.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(h=g;h0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=S.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(U(c[0])||U(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=R.call(arguments);N.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!T[a]?f.unique(e):e,(this.length>1||P.test(d))&&O.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};be.optgroup=be.option,be.tbody=be.tfoot=be.colgroup=be.caption=be.thead,be.th=be.td,f.support.htmlSerialize||(be._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!be[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bh(a,d),e=bi(a),g=bi(d);for(h=0;e[h];++h)g[h]&&bh(e[h],g[h])}if(b){bg(a,d);if(c){e=bi(a),g=bi(d);for(h=0;e[h];++h)bg(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=be[l]||be._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bn.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bm,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bm.test(g)?g.replace(bm,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bv(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bw=function(a,c){var d,e,g;c=c.replace(bo,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bx=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bp.test(d)&&bq.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bv=bw||bx,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bz=/%20/g,bA=/\[\]$/,bB=/\r?\n/g,bC=/#.*$/,bD=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bE=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bF=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bG=/^(?:GET|HEAD)$/,bH=/^\/\//,bI=/\?/,bJ=/)<[^<]*)*<\/script>/gi,bK=/^(?:select|textarea)/i,bL=/\s+/,bM=/([?&])_=[^&]*/,bN=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bO=f.fn.load,bP={},bQ={},bR,bS,bT=["*/"]+["*"];try{bR=e.href}catch(bU){bR=c.createElement("a"),bR.href="",bR=bR.href}bS=bN.exec(bR.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bO)return bO.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bJ,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bK.test(this.nodeName)||bE.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bB,"\r\n")}}):{name:b.name,value:c.replace(bB,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?bX(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),bX(a,b);return a},ajaxSettings:{url:bR,isLocal:bF.test(bS[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bT},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bV(bP),ajaxTransport:bV(bQ),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?bZ(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=b$(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bD.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bC,"").replace(bH,bS[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bL),d.crossDomain==null&&(r=bN.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bS[1]&&r[2]==bS[2]&&(r[3]||(r[1]==="http:"?80:443))==(bS[3]||(bS[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bW(bP,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bG.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bI.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bM,"$1_="+x);d.url=y+(y===d.url?(bI.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bT+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bW(bQ,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){s<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)bY(g,a[g],c,e);return d.join("&").replace(bz,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var b_=f.now(),ca=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+b_++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ca.test(b.url)||e&&ca.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ca,l),b.url===j&&(e&&(k=k.replace(ca,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cb=a.ActiveXObject?function(){for(var a in cd)cd[a](0,1)}:!1,cc=0,cd;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ce()||cf()}:ce,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cb&&delete cd[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cc,cb&&(cd||(cd={},f(a).unload(cb)),cd[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cg={},ch,ci,cj=/^(?:toggle|show|hide)$/,ck=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cl,cm=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cn;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cq("show",3),a,b,c);for(var g=0,h=this.length;g=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b
";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=ct.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!ct.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cu(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cu(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a&&a.style?parseFloat(f.css(a,d,"padding")):null},f.fn["outer"+c]=function(a){var b=this[0];return b&&b.style?parseFloat(f.css(b,d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNaN(j)?i:j}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); \ No newline at end of file