case 'form':
$info['definition'] = $this->definition + [
'title' => '',
- 'permission' => 'access CiviCRM',
+ 'permission' => ['access CiviCRM'],
'layout' => [
[
'#tag' => 'af-form',
case 'search':
$info['definition'] = $this->definition + [
'title' => '',
- 'permission' => 'access CiviCRM',
+ 'permission' => ['access CiviCRM'],
'layout' => [
[
'#tag' => 'div',
"type": "system",
"title": "Submissions",
"server_route": "civicrm/admin/afform/submissions",
- "permission": [["administer CiviCRM", "administer afform"]]
+ "permission": ["administer CiviCRM", "administer afform"],
+ "permission_operator": "OR"
}
color: #0071bd;
}
+#afGuiEditor #af_config_form_permission {
+ width: calc(100% - 55px);
+}
+#afGuiEditor #af_config_form_permission_operator {
+ width: 45px;
+}
+
#afGuiEditor .af-gui-layout-icon {
width: 12px;
height: 11px;
editor.searchDisplays = getSearchDisplaysOnForm();
}
+ editor.afform.permission_operator = editor.afform.permission_operator || 'AND';
+
// Initialize undo history
undoAction = 'initialLoad';
undoHistory = [{
<label for="af_config_form_permission">
{{:: ts('Permission') }}
</label>
- <input ng-model="editor.afform.permission" class="form-control" id="af_config_form_permission" crm-ui-select="{data: editor.meta.permissions}" >
- <p class="help-block">{{:: ts('What permission is required to use this form?') }}</p>
+ <div class="form-inline" >
+ <input ng-model="editor.afform.permission" class="form-control" id="af_config_form_permission" crm-ui-select="{data: editor.meta.permissions, multiple: true}" ng-list >
+ <select ng-model="editor.afform.permission_operator" class="form-control" id="af_config_form_permission_operator" >
+ <option value="AND">{{:: ts('And') }}</option>
+ <option value="OR">{{:: ts('Or') }}</option>
+ </select>
+ </div>
+ <p class="help-block">
+ {{:: ts('What permission is required to use this form?') }}
+ {{:: ts('Join multiple permissions with "And" to require all, or "Or" to require at least one.') }}
+ </p>
</div>
<!-- Placement options do not apply to blocks -->
'is_dashlet' => FALSE,
'is_public' => FALSE,
'is_token' => FALSE,
- 'permission' => 'access CiviCRM',
+ 'permission' => ['access CiviCRM'],
'type' => 'system',
];
if ($metaFile !== NULL) {
$r = array_merge($defaults, json_decode(file_get_contents($metaFile), 1));
// Previous revisions of GUI allowed permission==''. array_merge() doesn't catch all forms of missing-ness.
- if ($r['permission'] === '') {
+ if (empty($r['permission'])) {
$r['permission'] = $defaults['permission'];
}
return $r;
if ($getComputed) {
$scanner->addComputedFields($afforms[$name]);
}
+ if (isset($afforms[$name]['permission']) && is_string($afforms[$name]['permission'])) {
+ $afforms[$name]['permission'] = explode(',', $afforms[$name]['permission']);
+ }
if ($getLayout || $getSearchDisplays) {
// Autogenerated layouts will already be in values but can be overridden; scanner takes priority
$afforms[$name]['layout'] = $scanner->getLayout($name) ?? $afforms[$name]['layout'] ?? '';
'is_dashlet' => FALSE,
'is_public' => FALSE,
'is_token' => FALSE,
- 'permission' => 'access CiviCRM',
+ 'permission' => ['access CiviCRM'],
'join_entity' => 'Custom_' . $custom['name'],
'entity_type' => $custom['extends'],
];
],
[
'name' => 'permission',
+ 'data_type' => 'Array',
+ ],
+ [
+ 'name' => 'permission_operator',
+ 'data_type' => 'String',
+ 'options' => \CRM_Core_SelectValues::andOr(),
],
[
'name' => 'redirect',
$meta = $item + (array) $orig;
unset($meta['layout'], $meta['name']);
+ if (isset($meta['permission']) && is_string($meta['permission'])) {
+ $meta['permission'] = explode(',', $meta['permission']);
+ }
if (!empty($meta)) {
$metaPath = $scanner->createSiteLocalPath($item['name'], \CRM_Afform_AfformScanner::METADATA_FILE);
\CRM_Utils_File::createDir(dirname($metaPath));
'values' => [
'name' => $afform['name'],
'label' => $afform['navigation']['label'] ?: $afform['title'],
- 'permission' => (array) $afform['permission'],
- 'permission_operator' => 'OR',
+ 'permission' => $afform['permission'],
+ 'permission_operator' => $afform['permission_operator'] ?? 'AND',
'weight' => $afform['navigation']['weight'] ?? 0,
'url' => $afform['server_route'],
'is_active' => 1,
if (preg_match('/^@afform:(.*)/', $permission, $m)) {
$name = $m[1];
- $afform = \Civi\Api4\Afform::get()
- ->setCheckPermissions(FALSE)
+ $afform = \Civi\Api4\Afform::get(FALSE)
->addWhere('name', '=', $name)
- ->setSelect(['permission'])
+ ->addSelect('permission', 'permission_operator')
->execute()
->first();
+ // No permissions found... this shouldn't happen but just in case, set default.
+ if ($afform && empty($afform['permission'])) {
+ $afform['permission'] = ['access CiviCRM'];
+ }
if ($afform) {
- $granted = CRM_Core_Permission::check($afform['permission'], $contactId);
+ $check = (array) $afform['permission'];
+ if ($afform['permission_operator'] === 'OR') {
+ $check = [$check];
+ }
+ $granted = CRM_Core_Permission::check($check, $contactId);
}
}
}
public function getBasicDirectives() {
return [
- ['mockPage', ['title' => '', 'description' => '', 'server_route' => 'civicrm/mock-page', 'permission' => 'access Foobar', 'is_dashlet' => TRUE]],
- ['mockBareFile', ['title' => '', 'description' => '', 'permission' => 'access CiviCRM', 'is_dashlet' => FALSE]],
- ['mockFoo', ['title' => '', 'description' => '', 'permission' => 'access CiviCRM']],
- ['mock-weird-name', ['title' => 'Weird Name', 'description' => '', 'permission' => 'access CiviCRM']],
+ ['mockPage', ['title' => '', 'description' => '', 'server_route' => 'civicrm/mock-page', 'permission' => ['access Foobar'], 'is_dashlet' => TRUE]],
+ ['mockBareFile', ['title' => '', 'description' => '', 'permission' => ['access CiviCRM'], 'is_dashlet' => FALSE]],
+ ['mockFoo', ['title' => '', 'description' => '', 'permission' => ['access CiviCRM']]],
+ ['mock-weird-name', ['title' => 'Weird Name', 'description' => '', 'permission' => ['access CiviCRM']]],
];
}
$result = Civi\Api4\Afform::update()
->addWhere('name', '=', $formName)
->addValue('description', 'The temporary description')
- ->addValue('permission', 'access foo')
+ ->addValue('permission', ['access foo', 'access bar'])
->addValue('is_dashlet', empty($originalMetadata['is_dashlet']))
->execute();
$this->assertEquals($formName, $result[0]['name'], $message);
$this->assertEquals('The temporary description', $get($result[0], 'description'), $message);
$this->assertEquals(empty($originalMetadata['is_dashlet']), $get($result[0], 'is_dashlet'), $message);
$this->assertEquals($get($originalMetadata, 'server_route'), $get($result[0], 'server_route'), $message);
- $this->assertEquals('access foo', $get($result[0], 'permission'), $message);
+ $this->assertEquals(['access foo', 'access bar'], $get($result[0], 'permission'), $message);
$this->assertTrue(is_array($result[0]['layout']), $message);
$this->assertEquals(TRUE, $get($result[0], 'has_base'), $message);
$this->assertEquals(TRUE, $get($result[0], 'has_local'), $message);