Skip to content
Browse files

[ReUp] Add wizard for User Group creation to speed up ACL workflow

- Also add Context policy for proper managing of access to non-mgr Contexts
  • Loading branch information...
1 parent e5369e4 commit 5ddbd03eff05455825d72910927986ce395a466c Shaun McCormick committed Apr 13, 2012
View
45 _build/data/permissions/transport.policy.tpl.context.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ * The default Context Policy Template Permission scheme.
+ *
+ * @var modX|xPDO $xpdo
+ * @package modx
+ */
+$permissions = array();
+$permissions[] = $xpdo->newObject('modAccessPermission',array(
+ 'name' => 'load',
+ 'description' => 'perm.load_desc',
+ 'value' => true,
+));
+$permissions[] = $xpdo->newObject('modAccessPermission',array(
+ 'name' => 'list',
+ 'description' => 'perm.list_desc',
+ 'value' => true,
+));
+$permissions[] = $xpdo->newObject('modAccessPermission',array(
+ 'name' => 'view',
+ 'description' => 'perm.view_desc',
+ 'value' => true,
+));
+$permissions[] = $xpdo->newObject('modAccessPermission',array(
+ 'name' => 'save',
+ 'description' => 'perm.save_desc',
+ 'value' => true,
+));
+$permissions[] = $xpdo->newObject('modAccessPermission',array(
+ 'name' => 'remove',
+ 'description' => 'perm.remove_desc',
+ 'value' => true,
+));
+$permissions[] = $xpdo->newObject('modAccessPermission',array(
+ 'name' => 'view_unpublished',
+ 'description' => 'perm.view_unpublished_desc',
+ 'value' => true,
+));
+$permissions[] = $xpdo->newObject('modAccessPermission',array(
+ 'name' => 'copy',
+ 'description' => 'perm.copy_desc',
+ 'value' => true,
+));
+
+return $permissions;
View
11 _build/data/transport.core.accesspolicies.php
@@ -117,4 +117,15 @@
'lexicon' => 'permissions',
), '', true, true);
+$policies['11']= $xpdo->newObject('modAccessPolicy');
+$policies['11']->fromArray(array (
+ 'id' => 11,
+ 'name' => 'Context',
+ 'description' => 'A standard Context policy that you can apply when creating Context ACLs for basic read/write and view_unpublished access within a Context.',
+ 'parent' => 0,
+ 'class' => '',
+ 'data' => '{"load":true,"list":true,"view":true,"save":true,"remove":true,"copy":true,"view_unpublished":true}',
+ 'lexicon' => 'permissions',
+), '', true, true);
+
return $policies;
View
13 _build/data/transport.core.accesspolicytemplates.php
@@ -70,4 +70,17 @@
$templates['5']->addMany($permissions);
} else { $xpdo->log(xPDO::LOG_LEVEL_ERROR,'Could not load Media Source Template Permissions.'); }
+/* context template policies */
+$templates['6']= $xpdo->newObject('modAccessPolicyTemplate');
+$templates['6']->fromArray(array(
+ 'id' => 6,
+ 'name' => 'ContextTemplate',
+ 'description' => 'Context Policy Template with all attributes.',
+ 'lexicon' => 'permissions',
+));
+$permissions = include dirname(__FILE__).'/permissions/transport.policy.tpl.context.php';
+if (is_array($permissions)) {
+ $templates['6']->addMany($permissions);
+} else { $xpdo->log(xPDO::LOG_LEVEL_ERROR,'Could not load Context Template Permissions.'); }
+
return $templates;
View
1 _build/resolvers/resolve.policies.php
@@ -12,6 +12,7 @@
'Load Only' => 'ObjectTemplate',
'Load, List and View' => 'ObjectTemplate',
'Object' => 'ObjectTemplate',
+ 'Context' => 'ContextTemplate',
'Element' => 'ElementTemplate',
'Media Source Admin' => 'MediaSourceTemplate',
'Media Source User' => 'MediaSourceTemplate',
View
1 _build/resolvers/resolve.policytemplates.php
@@ -12,6 +12,7 @@
'ResourceTemplate' => 'Resource',
'AdministratorTemplate' => 'Admin',
'ObjectTemplate' => 'Object',
+ 'ContextTemplate' => 'Object',
'ElementTemplate' => 'Element',
'MediaSourceTemplate' => 'MediaSource',
);
View
2 core/docs/changelog.txt
@@ -2,6 +2,8 @@
This file shows the changes in recent releases of MODX. The most current release is usually the
development release, and is only shown to give an idea of what's currently in the pipeline.
+- Add wizard for User Group creation to speed up ACL workflow
+- Add Context policy for proper managing of access to non-mgr Contexts
- Add wizard for Resource Group creation to speed up ACL workflow
MODX Revolution 2.2.1-pl (April 3, 2012)
View
2 core/docs/version.inc.php
@@ -2,7 +2,7 @@
$v= array ();
$v['version']= '2'; // Current version.
$v['major_version']= '2'; // Current major version.
-$v['minor_version']= '1'; // Current minor version.
+$v['minor_version']= '2'; // Current minor version.
$v['patch_level']= 'pl'; // Current patch level.
$v['code_name']= 'Revolution'; // Current codename.
$v['distro']= '@git@';
View
17 core/lexicon/en/access.inc.php
@@ -107,6 +107,23 @@
$_lang['resource_group_access_ugs_desc'] = 'A comma-separated list of User Group names. If non-blank, will give the User Groups specified here view access to this Resource Group for the above contexts.';
$_lang['roles_msg'] = 'A role is, by definition, a position or status one holds within a certain situation. They can be used to group Users into a position or status within a User Group. Roles in MODX also have what is called "Authority". This is a number value that can be any valid integer. Authority levels are "inheritable downward", in the sense that a Role with Authority 1 will inherit any and all Group Policies assigned to itself, and to any Roles with higher Authority level than 1.';
$_lang['source_add'] = 'Add Media Source';
+
+$_lang['user_group_aw'] = 'Access Wizard';
+$_lang['user_group_aw_desc'] = 'Note: You may have to flush sessions after adding the User Group if you check any of the options below.';
+$_lang['user_group_aw_contexts'] = 'Contexts';
+$_lang['user_group_aw_contexts_desc'] = 'A comma-separated list of Contexts that this User Group should be able to view.';
+$_lang['user_group_aw_manager_policy'] = 'Manager Policy';
+$_lang['user_group_aw_manager_policy_desc'] = 'The Policy to give the User Group for editing in the manager. Select (no policy) if you do not want to grant manager access.';
+$_lang['user_group_aw_users'] = 'Users';
+$_lang['user_group_aw_users_desc'] = 'A comma-separated list of usernames to add to this User Group. You can use the format username:role to set the role; otherwise, Member will be assumed.';
+$_lang['user_group_aw_resource_groups'] = 'Resource Groups';
+$_lang['user_group_aw_resource_groups_desc'] = 'A comma-separated list of Resource Groups to give access to in the Contexts specified above.';
+$_lang['user_group_aw_categories'] = 'Element Categories';
+$_lang['user_group_aw_categories_desc'] = 'A comma-separated list of Element Categories to give access to in the Contexts specified above.';
+$_lang['user_group_aw_parallel'] = 'Create Parallel Resource Group';
+$_lang['user_group_aw_parallel_desc'] = 'If checked, will automatically create a Resource Group with the same name, and give this User Group view access to it in the Contexts specified above.';
+
+
$_lang['user_group_category_access'] = 'Element Category Access';
$_lang['user_group_category_access_msg'] = 'Here you can set which Elements this User Group can access by the Categories the Elements are in.';
$_lang['user_group_category_authority_desc'] = 'The minimum Role that will have access to the Permissions in the selected Policy for this context. Roles with stronger Authority (lower numbers) will inherit this access as well. Most situations can leave this at "Member".';
View
256 core/model/modx/processors/security/group/create.class.php
@@ -37,7 +37,7 @@ public function beforeSave() {
$this->setProperty('parent',0);
}
- if ($this->alreadyExists()) {
+ if ($this->doesAlreadyExist(array('name' => $name))) {
$this->addFieldError('name',$this->modx->lexicon('user_group_err_already_exists'));
}
@@ -49,15 +49,261 @@ public function afterSave() {
if ($this->modx->hasPermission('usergroup_user_edit')) {
$this->setResourceGroups();
}
+
+ /* access wizard stuff */
+ $flush = false;
+ $users = $this->getProperty('aw_users','');
+ if (!empty($users)) {
+ $this->addUsersViaWizard($users);
+ }
+ $contexts = $this->getProperty('aw_contexts','');
+ if (!empty($contexts)) {
+ $contexts = is_array($contexts) ? $contexts : explode(',',$contexts);
+ $contexts = array_unique($contexts);
+
+ $adminPolicy = trim($this->getProperty('aw_manager_policy',0));
+ if (!empty($adminPolicy)) {
+ $this->addManagerContextAccessViaWizard($adminPolicy);
+ }
+
+ $policy = trim($this->getProperty('aw_contexts_policy',0));
+ if ($this->addContextAccessViaWizard($contexts,$policy)) {
+ $flush = true;
+ }
+
+ $resourceGroups = $this->getProperty('aw_resource_groups','');
+ if (!empty($resourceGroups)) {
+ $this->addResourceGroupsViaWizard($resourceGroups,$contexts);
+ }
+
+ $categories = $this->getProperty('aw_categories','');
+ if (!empty($categories)) {
+ $this->addElementCategoriesViaWizard($categories,$contexts);
+ }
+
+ $parallel = $this->getProperty('aw_parallel',false);
+ if ($parallel) {
+ $this->addParallelResourceGroup($contexts);
+ }
+ }
+
+ if ($flush) {
+ $this->flushPermissions();
+ }
+
return parent::afterSave();
}
-
+
+ /**
+ * Add user groups via a wizard property, which is a comma-separated list of username:role key pairs, ie:
+ * jimbob:Member,johndoe:Administrator,marksmith
+ *
+ * If the Role is left off, it will default to the Member role.
+ *
+ * @param string|array $users
+ * @return bool
+ */
+ public function addUsersViaWizard($users) {
+ $users = is_array($users) ? $users : explode(',',$users);
+ $users = array_unique($users);
+ foreach ($users as $userKey) {
+ $userKey = explode(':',$userKey);
+ $c = intval($userKey[0]) > 0 ? trim($userKey[0]) : array('username' => trim($userKey[0]));
+ /** @var modUser $user */
+ $user = $this->modx->getObject('modUser',$c);
+ if (empty($user)) continue;
+
+ /** @var modUserGroupRole $role */
+ if (empty($userKey[1])) $userKey[1] = 'Member';
+ $c = intval($userKey[1]) > 0 ? trim($userKey[1]) : array('name' => trim($userKey[1]));
+ $role = $this->modx->getObject('modUserGroupRole',$c);
+ if (empty($role)) continue;
+
+ /** @var modUserGroupMember $membership */
+ $membership = $this->modx->newObject('modUserGroupMember');
+ $membership->set('user_group',$this->object->get('id'));
+ $membership->set('member',$user->get('id'));
+ $membership->set('role',$role->get('id'));
+ $membership->save();
+ }
+ return true;
+ }
+
+ /**
+ * Add Manager Access via wizard property with a specified policy.
+ *
+ * @param int|string $adminPolicy
+ * @return bool
+ */
+ public function addManagerContextAccessViaWizard($adminPolicy) {
+ $c = intval($adminPolicy) > 0 ? $adminPolicy : array('name' => $adminPolicy);
+ /** @var modAccessPolicy $policy */
+ $policy = $this->modx->getObject('modAccessPolicy',$c);
+ if (!$policy) return false;
+
+ /** @var modAccessResourceGroup $acl */
+ $acl = $this->modx->newObject('modAccessContext');
+ $acl->fromArray(array(
+ 'target' => 'mgr',
+ 'principal_class' => 'modUserGroup',
+ 'principal' => $this->object->get('id'),
+ 'authority' => 9999,
+ 'policy' => $policy->get('id'),
+ ));
+ $acl->save();
+
+ return true;
+ }
+
+ /**
+ * Add Context Access via wizard property.
+ *
+ * @param array $contexts
+ * @return boolean
+ */
+ public function addContextAccessViaWizard(array $contexts) {
+ /** @var modAccessPolicy $policy */
+ $policy = $this->modx->getObject('modAccessPolicy',array(
+ 'name' => 'Context',
+ ));
+ if (!$policy) return false;
+
+ foreach ($contexts as $context) {
+ /** @var modAccessResourceGroup $acl */
+ $acl = $this->modx->newObject('modAccessContext');
+ $acl->fromArray(array(
+ 'target' => trim($context),
+ 'principal_class' => 'modUserGroup',
+ 'principal' => $this->object->get('id'),
+ 'authority' => 9999,
+ 'policy' => $policy->get('id'),
+ ));
+ $acl->save();
+ }
+ return true;
+ }
+
+ /**
+ * @param string|array $resourceGroupNames
+ * @param array $contexts
+ * @return boolean
+ */
+ public function addResourceGroupsViaWizard($resourceGroupNames,array $contexts) {
+ $resourceGroupNames = is_array($resourceGroupNames) ? $resourceGroupNames : explode(',',$resourceGroupNames);
+ $resourceGroupNames = array_unique($resourceGroupNames);
+
+ /** @var modAccessPolicy $policy */
+ $policy = $this->modx->getObject('modAccessPolicy',array('name' => 'Resource'));
+ if (!$policy) return false;
+
+ foreach ($resourceGroupNames as $resourceGroupName) {
+ /** @var modResourceGroup $resourceGroup */
+ $resourceGroup = $this->modx->getObject('modResourceGroup',array('name' => trim($resourceGroupName)));
+ if (!$resourceGroup) return false;
+
+ foreach ($contexts as $context) {
+ /** @var modAccessResourceGroup $acl */
+ $acl = $this->modx->newObject('modAccessResourceGroup');
+ $acl->fromArray(array(
+ 'target' => $resourceGroup->get('id'),
+ 'principal_class' => 'modUserGroup',
+ 'principal' => $this->object->get('id'),
+ 'authority' => 9999,
+ 'policy' => $policy->get('id'),
+ 'context_key' => trim($context),
+ ));
+ $acl->save();
+ }
+ }
+ return true;
+ }
+
+
+ /**
+ * Adds a Resource Group with the same name and grants access for the specified Contexts
+ *
+ * @param array $contexts
+ * @return boolean
+ */
+ public function addParallelResourceGroup(array $contexts) {
+ /** @var modResourceGroup $resourceGroup */
+ $resourceGroup = $this->modx->getObject('modResourceGroup',array(
+ 'name' => $this->object->get('name'),
+ ));
+ if (!$resourceGroup) {
+ $resourceGroup = $this->modx->newObject('modResourceGroup');
+ $resourceGroup->set('name',$this->object->get('name'));
+ if (!$resourceGroup->save()) {
+ return false;
+ }
+ }
+
+ /** @var modAccessPolicy $policy */
+ $policy = $this->modx->getObject('modAccessPolicy',array('name' => 'Resource'));
+ if (!$policy) return false;
+
+ foreach ($contexts as $context) {
+ /** @var modAccessResourceGroup $acl */
+ $acl = $this->modx->newObject('modAccessResourceGroup');
+ $acl->fromArray(array(
+ 'target' => $resourceGroup->get('id'),
+ 'principal_class' => 'modUserGroup',
+ 'principal' => $this->object->get('id'),
+ 'authority' => 9999,
+ 'policy' => $policy->get('id'),
+ 'context_key' => trim($context),
+ ));
+ $acl->save();
+ }
+ return true;
+ }
+
/**
- * Check to see if a group already exists with the specified name
+ * @param string|array $categoryNames
+ * @param array $contexts
* @return boolean
*/
- public function alreadyExists() {
- return $this->modx->getCount('modUserGroup',array('name' => $this->getProperty('name'))) > 0;
+ public function addElementCategoriesViaWizard($categoryNames,array $contexts) {
+ $categoryNames = is_array($categoryNames) ? $categoryNames : explode(',',$categoryNames);
+ $categoryNames = array_unique($categoryNames);
+
+ /** @var modAccessPolicy $policy */
+ $policy = $this->modx->getObject('modAccessPolicy',array('name' => 'Element'));
+ if (!$policy) return false;
+
+ foreach ($categoryNames as $categoryName) {
+ /** @var modCategory $category */
+ $category = $this->modx->getObject('modCategory',array('category' => trim($categoryName)));
+ if (!$category) return false;
+
+ foreach ($contexts as $context) {
+ /** @var modAccessCategory $acl */
+ $acl = $this->modx->newObject('modAccessCategory');
+ $acl->fromArray(array(
+ 'target' => $category->get('id'),
+ 'principal_class' => 'modUserGroup',
+ 'principal' => $this->object->get('id'),
+ 'authority' => 9999,
+ 'policy' => $policy->get('id'),
+ 'context_key' => trim($context),
+ ));
+ $acl->save();
+ }
+ }
+ return true;
+ }
+
+ public function flushPermissions() {
+ $ctxQuery = $this->modx->newQuery('modContext');
+ $ctxQuery->select($this->modx->getSelectColumns('modContext', '', '', array('key')));
+ if ($ctxQuery->prepare() && $ctxQuery->stmt->execute()) {
+ $contexts = $ctxQuery->stmt->fetchAll(PDO::FETCH_COLUMN);
+ if ($contexts) {
+ $serialized = serialize($contexts);
+ $this->modx->exec("UPDATE {$this->modx->getTableName('modUser')} SET {$this->modx->escape('session_stale')} = {$this->modx->quote($serialized)}");
+ }
+ }
+ return $this->success();
}
/**
View
10 core/model/modx/processors/security/resourcegroup/create.class.php
@@ -86,7 +86,7 @@ protected function addAdminAccess(array $contexts = array()) {
/** @var modAccessResourceGroup $acl */
$acl = $this->modx->newObject('modAccessResourceGroup');
$acl->fromArray(array(
- 'context_key' => $context,
+ 'context_key' => trim($context),
'target' => $this->object->get('id'),
'principal_class' => 'modUserGroup',
'principal' => $adminGroup->get('id'),
@@ -112,7 +112,7 @@ protected function addAnonymousAccess(array $contexts = array()) {
/** @var modAccessResourceGroup $acl */
$acl = $this->modx->newObject('modAccessResourceGroup');
$acl->fromArray(array(
- 'context_key' => $context,
+ 'context_key' => trim($context),
'target' => $this->object->get('id'),
'principal_class' => 'modUserGroup',
'principal' => 0,
@@ -150,7 +150,7 @@ protected function addParallelUserGroup(array $contexts = array()) {
/** @var modAccessResourceGroup $acl */
$acl = $this->modx->newObject('modAccessResourceGroup');
$acl->fromArray(array(
- 'context_key' => $context,
+ 'context_key' => trim($context),
'target' => $this->object->get('id'),
'principal_class' => 'modUserGroup',
'principal' => $userGroup->get('id'),
@@ -178,14 +178,14 @@ protected function addOtherUserGroups(array $userGroupNames = array(),array $con
foreach ($userGroupNames as $userGroupName) {
/** @var modUserGroup $userGroup */
- $userGroup = $this->modx->getObject('modUserGroup',array('name' => $userGroupName));
+ $userGroup = $this->modx->getObject('modUserGroup',array('name' => trim($userGroupName)));
if (!$userGroup) return false;
foreach ($contexts as $context) {
/** @var modAccessResourceGroup $acl */
$acl = $this->modx->newObject('modAccessResourceGroup');
$acl->fromArray(array(
- 'context_key' => $context,
+ 'context_key' => trim($context),
'target' => $this->object->get('id'),
'principal_class' => 'modUserGroup',
'principal' => $userGroup->get('id'),
View
122 manager/assets/modext/widgets/security/modx.tree.user.group.js
@@ -190,10 +190,15 @@ MODx.window.CreateUserGroup = function(config) {
title: _('create_user_group')
,id: this.ident
,height: 150
- ,width: 375
+ ,width: 750
+ ,stateful: false
,url: MODx.config.connectors_url+'security/group.php'
,action: 'create'
,fields: [{
+ name: 'parent'
+ ,id: 'modx-'+this.ident+'-parent'
+ ,xtype: 'hidden'
+ },{
xtype: 'textfield'
,fieldLabel: _('name')
,description: MODx.expandHelp ? '' : _('user_group_desc_name')
@@ -218,9 +223,118 @@ MODx.window.CreateUserGroup = function(config) {
,html: _('user_group_desc_description')
,cls: 'desc-under'
},{
- name: 'parent'
- ,id: 'modx-'+this.ident+'-parent'
- ,xtype: 'hidden'
+ xtype: 'fieldset'
+ ,collapsible: true
+ ,collapsed: false
+ ,autoHeight: true
+ ,title: _('user_group_aw')
+ ,items: [{
+ html: '<p style="margin: 5px 0 0">'+_('user_group_aw_desc')+'</p>'
+ ,cls: 'desc-under'
+ },{
+ layout: 'column'
+ ,border: false
+ ,defaults: {
+ layout: 'form'
+ ,labelAlign: 'top'
+ ,anchor: '100%'
+ ,border: false
+ }
+ ,items: [{
+ columnWidth: .5
+ ,items: [{
+ xtype: 'textfield'
+ ,name: 'aw_users'
+ ,fieldLabel: _('user_group_aw_users')
+ ,description: _('user_group_aw_users_desc')
+ ,id: this.ident+'-aw-users'
+ ,anchor: '100%'
+ ,value: ''
+ },{
+ xtype: MODx.expandHelp ? 'label' : 'hidden'
+ ,forId: this.ident+'-aw-users'
+ ,html: _('user_group_aw_users_desc')
+ ,cls: 'desc-under'
+ },{
+ fieldLabel: _('user_group_aw_resource_groups')
+ ,description: _('user_group_aw_resource_groups_desc')
+ ,name: 'aw_resource_groups'
+ ,id: this.ident+'-aw-resource-groups'
+ ,xtype: 'textfield'
+ ,value: ''
+ ,anchor: '100%'
+ },{
+ xtype: MODx.expandHelp ? 'label' : 'hidden'
+ ,forId: this.ident+'-aw-resource-groups'
+ ,html: _('user_group_aw_resource_groups_desc')
+ ,cls: 'desc-under'
+
+ },{
+ boxLabel: _('user_group_aw_parallel')
+ ,description: _('user_group_aw_parallel_desc')
+ ,name: 'aw_parallel'
+ ,id: this.ident+'-aw-parallel'
+ ,xtype: 'checkbox'
+ ,checked: false
+ ,inputValue: 1
+ ,anchor: '100%'
+ },{
+ xtype: MODx.expandHelp ? 'label' : 'hidden'
+ ,forId: this.ident+'-aw-parallel'
+ ,html: _('user_group_aw_parallel_desc')
+ ,cls: 'desc-under'
+ }]
+ },{
+ columnWidth: .5
+ ,items: [{
+ xtype: 'textfield'
+ ,name: 'aw_contexts'
+ ,fieldLabel: _('contexts')
+ ,description: MODx.expandHelp ? '' : _('user_group_aw_contexts_desc')
+ ,id: this.ident+'-aw-contexts'
+ ,anchor: '100%'
+ ,value: 'web'
+ },{
+ xtype: MODx.expandHelp ? 'label' : 'hidden'
+ ,forId: this.ident+'-aw-contexts'
+ ,html: _('user_group_aw_contexts_desc')
+ ,cls: 'desc-under'
+
+ },{
+ xtype: 'modx-combo-policy'
+ ,baseParams: {
+ action: 'getList'
+ ,group: 'Admin'
+ ,combo: '1'
+ }
+ ,name: 'aw_manager_policy'
+ ,fieldLabel: _('user_group_aw_manager_policy')
+ ,description: MODx.expandHelp ? '' : _('user_group_aw_manager_policy_desc')
+ ,id: this.ident+'-aw-manager-policy'
+ ,anchor: '100%'
+ },{
+ xtype: MODx.expandHelp ? 'label' : 'hidden'
+ ,forId: this.ident+'-aw-manager-policy'
+ ,html: _('user_group_aw_manager_policy_desc')
+ ,cls: 'desc-under'
+
+ },{
+ fieldLabel: _('user_group_aw_categories')
+ ,description: _('user_group_aw_categories_desc')
+ ,name: 'aw_categories'
+ ,id: this.ident+'-aw-categories'
+ ,xtype: 'textfield'
+ ,value: ''
+ ,anchor: '100%'
+ },{
+ xtype: MODx.expandHelp ? 'label' : 'hidden'
+ ,forId: this.ident+'-aw-categories'
+ ,html: _('user_group_aw_categories_desc')
+ ,cls: 'desc-under'
+
+ }]
+ }]
+ }]
}]
,keys: []
});

0 comments on commit 5ddbd03

Please sign in to comment.
Something went wrong with that request. Please try again.