/ */ class User_RoleController extends Zend_Controller_Action { public $contexts = array( 'index' => array('json'), 'add' => array('partial', 'json'), 'edit' => array('partial', 'json'), 'delete' => array('json'), ); /** * Use management layout for all actions. */ public function init() { $this->_helper->layout->setLayout('manage-layout'); } /** * List all roles. * * @publishes p4cms.user.role.grid.actions * Modify the passed menu (add/modify/delete items) to influence the actions shown * on entries in the Manage Users grid. * P4Cms_Navigation $actions A menu to hold grid actions. * * @publishes p4cms.user.role.grid.data.item * Return the passed item after applying any modifications (add properties, change * values, etc.) to influence the row values sent to the Manage Roles grid. * array $item The item to potentially modify. * mixed $model The original object/array that was used * to make the item. * Ui_View_Helper_DataGrid $helper The view helper that broadcast this * topic. * * @publishes p4cms.user.role.grid.data * Adjust the passed data (add properties, modify values, etc.) to influence the * row values sent to the Manage Roles grid. * Zend_Dojo_Data $data The data to be filtered. * Ui_View_Helper_DataGrid $helper The view helper that broadcast this * topic. * * @publishes p4cms.user.role.grid.populate * Adjust the passed iterator (possibly based on values in the passed form) to * filter which roles will be shown on the Manage Roles grid. * P4Cms_Model_Iterator $roles An iterator of Role_Model_Role objects. * P4Cms_Form_PubSubForm $form A form containing filter options. * * @publishes p4cms.user.role.grid.render * Make adjustments to the datagrid helper's options pre-render (e.g. change * options to add columns) for the Manage Roles grid. * Ui_View_Helper_DataGrid $helper The view helper that broadcast this * topic. * * @publishes p4cms.user.role.grid.form * Make arbitrary modifications to the Manage Roles filters form. * P4Cms_Form_PubSubForm $form The form that published this event. * * @publishes p4cms.user.role.grid.form.subForms * Return a Form (or array of Forms) to have them added to the Manage Roles filters * form. The returned form(s) should have a 'name' set on them to allow them to be * uniquely identified. * P4Cms_Form_PubSubForm $form The form that published this event. * * @publishes p4cms.user.role.grid.form.preValidate * Allows subscribers to adjust the Manage Roles filters form prior to validation * of the passed data. For example, modify element values based on related * selections to permit proper validation. * P4Cms_Form_PubSubForm $form The form that published this event. * array $values An associative array of form values. * * @publishes p4cms.user.role.grid.form.validate * Return false to indicate the Manage Roles filters form is invalid. Return true * to indicate your custom checks were satisfied, so form validity should be * unchanged. * P4Cms_Form_PubSubForm $form The form that published this event. * array $values An associative array of form values. * * @publishes p4cms.user.role.grid.form.populate * Allows subscribers to adjust the Manage Roles filters form after it has been * populated with the passed data. * P4Cms_Form_PubSubForm $form The form that published this event. * array $values The values passed to the populate * method. */ public function indexAction() { // enforce permissions $this->acl->check('users', 'manage-roles'); // setup list options form. $request = $this->getRequest(); $gridNamespace = 'p4cms.user.role.grid'; $form = new Ui_Form_GridOptions( array( 'namespace' => $gridNamespace ) ); $form->populate($request->getParams()); // setup view. $view = $this->view; $view->form = $form; $view->pageSize = $request->getParam('count', 100); $view->rowOffset = $request->getParam('start', 0); $view->pageOffset = round($view->rowOffset / $view->pageSize, 0) + 1; $view->headTitle()->set('Manage Roles'); // set DataGrid view helper namespace $helper = $view->dataGrid(); $helper->setNamespace($gridNamespace); // collect the actions from interested parties $actions = new P4Cms_Navigation; P4Cms_PubSub::publish($gridNamespace . '.actions', $actions); $view->actions = $actions; // early exit for standard requests (ie. not json) if (!$this->contextSwitch->getCurrentContext()) { $this->getHelper('helpUrl')->setUrl('roles.manage.html'); return; } // fetch roles - allow third-parties to influence list $roles = P4Cms_Acl_Role::fetchAll(); try { P4Cms_PubSub::publish($gridNamespace . '.populate', $roles, $form); } catch (Exception $e) { P4Cms_Log::logException("Error building role list.", $e); } // prepare sorting options $sortKey = $request->getParam('sort', 'id'); $sortFlags = array( P4Cms_Model_Iterator::SORT_NATURAL, P4Cms_Model_Iterator::SORT_NO_CASE ); if (substr($sortKey, 0, 1) == '-') { $sortKey = substr($sortKey, 1); $sortFlags[] = P4Cms_Model_Iterator::SORT_DESCENDING; } else { $sortFlags[] = P4Cms_Model_Iterator::SORT_ASCENDING; } // apply sorting options. $roles->sortBy($sortKey, $sortFlags); // add users to the view. $view->roles = $roles; } /** * Add new role. */ public function addAction() { // enforce permissions $this->acl->check('users', 'manage-roles'); $request = $this->getRequest(); $activeUser = P4Cms_User::fetchActive(); $form = new User_Form_AddRole; // set up view $view = $this->view; $view->form = $form; $view->headTitle()->set('Add Role'); // deny non-administrator users if (!$activeUser->isAdministrator()) { throw new P4Cms_AccessDeniedException( "You don't have permission to create roles." ); } // if posted, validate form and save role. if ($request->isPost()) { // if form is invalid, set response code and exit if (!$form->isValid($request->getParams())) { $this->getResponse()->setHttpResponseCode(400); $view->errors = $form->getMessages(); return; } // create new role entry $role = new P4Cms_Acl_Role; $role->setValues($form->getValues()); // add owner to the associated group $this->_addOwner($role); $role->save(); // clear affected cache entries. $this->_clearCaches($role->getId(), $role->getUsers(), 'add'); // set notification message $view->message = "Role '{$role->getId()}' has been successfuly added."; // for traditional requests, add notification message and redirect if (!$this->contextSwitch->getCurrentContext()) { P4Cms_Notifications::add( $view->message, P4Cms_Notifications::SEVERITY_SUCCESS ); $this->redirector->gotoSimple('index'); } } } /** * Edit existing role. */ public function editAction() { // enforce permissions $this->acl->check('users', 'manage-roles'); $request = $this->getRequest(); $activeUser = P4Cms_User::fetchActive(); $roleId = $request->getParam('id'); $role = P4Cms_Acl_Role::fetch($roleId); $form = new User_Form_EditRole; // deny if role is virtual if ($role->isVirtual()) { throw new P4Cms_AccessDeniedException( "Cannot modify '$roleId' role." ); } // deny non-administrator users if (!$activeUser->isAdministrator()) { throw new P4Cms_AccessDeniedException( "You don't have permission to edit this role." ); } // set up view $view = $this->view; $view->form = $form; $view->headTitle()->set('Edit Role'); // assemble values array to populate the form with $values = $role->getValues(); $users = $role->getRealUsers(); if ($users) { $values['users'] = array_combine($users, $users); } // populate form from post if available, otherwise from storage. $form->populate($request->isPost() ? $request->getParams() : $values); // always set the id from storage $form->getElement('id')->setValue($role->getRoleId()); // if posted, validate form and save changes. if ($request->isPost()) { // if form is invalid, set response code and exit if (!$form->isValid($request->getParams())) { $this->getResponse()->setHttpResponseCode(400); $view->errors = $form->getMessages(); return; } // collect list of associated users prior to updating role // for the purpose of clearing cache for users that are removed $originalUsers = $role->getUsers(); $role->setValues($form->getValues()) ->save(); // clear affected caches. $affectedUsers = array_unique(array_merge($role->getUsers(), $originalUsers)); $this->_clearCaches($role->getId(), $affectedUsers, 'edit'); // set notification message $view->message = "Role '{$role->getId()}' has been successfuly updated."; // for traditional requests, add notification message and redirect if (!$this->contextSwitch->getCurrentContext()) { P4Cms_Notifications::add( $view->message, P4Cms_Notifications::SEVERITY_SUCCESS ); $this->redirector->gotoSimple('index'); } } } /** * Delete role entry. * Role can be removed only via post. */ public function deleteAction() { // enforce permissions $this->acl->check('users', 'manage-roles'); // deny if not accessed via post if (!$this->getRequest()->isPost()) { throw new P4Cms_AccessDeniedException( "Deleting roles is not permitted in this context." ); } $activeUser = P4Cms_User::fetchActive(); $post = $this->getRequest()->getPost(); $roleId = $post['id']; $role = P4Cms_Acl_Role::fetch($roleId); // deny if role is a protected system role if ($role->isSystem()) { throw new P4Cms_AccessDeniedException( "System roles cannot be deleted." ); } // deny if not super access level if (!$activeUser->isAdministrator()) { throw new P4Cms_AccessDeniedException( "You don't have permission to delete this role." ); } // clear affected cache entries. $this->_clearCaches($role->getId(), $role->getUsers(), 'delete'); // do the actual delete $role->delete(); // for traditional requests, add message and redirect if (!$this->contextSwitch->getCurrentContext()) { P4Cms_Notifications::add( "Role '$roleId' has been deleted.", P4Cms_Notifications::SEVERITY_SUCCESS ); $this->redirector->gotoSimple('index'); } $this->view->roleId = $roleId; } /** * Adds the sytem user to the owners of associated group of the given role * to avoid deleting the role if no users are assigned as groups in Perforce * cannot be empty. * * Doesn't add system user to the owners of administrator's group as this * role is handled differently (it always should have users). * * @param P4Cms_Acl_Role $role role to add system user to the owners * of the associated group. */ protected function _addOwner(P4Cms_Acl_Role $role) { if ($role->getId() !== P4Cms_Acl_Role::ROLE_ADMINISTRATOR) { $user = $this->getInvokeArg('bootstrap')->getResource('perforce')->getUser(); $role->addOwner($user); } } /** * Utility method to assist with clearing caches when roles are changed. * * @param string $role the id of the role to clear. * @param array $users list of ids of affected users. * @param string $action one of: add, edit or delete */ protected function _clearCaches($role, $users, $action) { $tags = array(); // clear entries tagged as needing to be cleared when any role changes. $tags[] = 'p4cms_user_roles'; // clear entries tagged with this specific role. $tags[] = 'p4cms_user_role_' . md5($role); // clear affected user specific caches foreach ($users as $user) { $tags[] = 'p4cms_user_' . md5($user); } P4Cms_Cache::clean('all', $tags); // if a role has been added or deleted, we need to clear // the sites cache as each site's acl has a list of roles. if ($action != 'edit') { P4Cms_Cache::remove(P4Cms_Site::CACHE_KEY, 'global'); } } }