Subversion Repositories web.active

Rev

Rev 1 | Details | Compare with Previous | Last modification | View Log

Rev Author Line No. Line
1 mjordaan 1
<?php namespace ProcessWire;
2
 
3
/**
4
 * ProcessWire Role Process
5
 *
6
 * For more details about how Process modules work, please see: 
7
 * /wire/core/Process.php 
8
 * 
45 mjordaan 9
 * ProcessWire 3.x, Copyright 2023 by Ryan Cramer
1 mjordaan 10
 * https://processwire.com
11
 *
12
 */
13
 
14
class ProcessRole extends ProcessPageType {
15
 
16
	static public function getModuleInfo() {
17
		return array(
18
			'title' => __('Roles', __FILE__), // getModuleInfo title
19
			'version' => 104, 
20
			'summary' => __('Manage user roles and what permissions are attached', __FILE__), // getModuleInfo summary 
21
			'permanent' => true, 
22
			'permission' => 'role-admin', // add this permission if you want this Process available for roles other than Superuser
23
			'icon' => 'gears',
24
			'useNavJSON' => true,
45 mjordaan 25
		); 
1 mjordaan 26
	}
27
 
28
	/**
29
	 * Array of [ 'icon-name' => 'icon markup' ]
30
	 * 
31
	 * @var array
32
	 * 
33
	 */
34
	protected $icons = array();
35
 
36
	/**
37
	 * Array of [ 'permission-name' => 'Additional notes for permission' ]
38
	 * 
39
	 * @var array
40
	 * 
41
	 */
42
	protected $templatePermissionNotes = array();
43
 
44
	/**
45
	 * Array of [ 'permission-name' => 'Description of permission' ]
46
	 * 
47
	 * @var array
48
	 * 
49
	 */
50
	protected $templatePermissionDescriptions = array();
51
 
52
	/**
53
	 * Role object for guest role
54
	 * 
55
	 * @var Role
56
	 * 
57
	 */
58
	protected $guestRole;
59
 
60
	/**
61
	 * Init and attach hooks
62
	 * 
63
	 */
64
	public function init() {
65
 
66
		parent::init();
45 mjordaan 67
 
68
		/** @var JqueryUI $jQueryUI */
69
		$jQueryUI = $this->wire()->modules->get('JqueryUI');
70
		$jQueryUI->use('vex');
71
 
72
		$this->guestRole = $this->wire()->roles->get($this->wire()->config->guestUserRolePageID);
1 mjordaan 73
		$this->addHookBefore('InputfieldForm::render', $this, 'hookFormRender');
74
		$this->addHookBefore('ProcessPageEdit::processInput', $this, 'hookProcessInput');
75
 
76
		$this->icons = array(
77
			'edit' => wireIconMarkup('certificate', 'fw'),
78
			'page' => wireIconMarkup('gear', 'fw'), 
79
			'info' => wireIconMarkup('info-circle', 'fw'), 
80
			'add' => wireIconMarkup('plus-circle', 'fw'),
81
			'revoke' => wireIconMarkup('minus-circle', 'fw'),
82
			'help' => wireIconMarkup('question-circle'),
83
		);
84
 
85
		$this->templatePermissionDescriptions = array(
86
			'page-view' => $this->_('Which types of pages may this role view?'),
87
			'page-edit' => $this->_('Which types of pages may this role edit?'),
88
			'page-add' => $this->_('Which types of pages may this role add children to?'),
89
			'page-create' => $this->_('Which types of pages may this role create?'),
90
			'default-add' => $this->_('If you want to add {permission} only to specific templates, check the boxes below for the templates you want to add it to, and leave the {permission} permission unchecked.'),
91
			'default-revoke' => $this->_('The {permission} permission is checked, making it apply to all templates that are editable to the role. To revoke {permission} permission from specific templates, check the boxes below. To add this permission to only specific templates, un-check the {permission} permission first.'),
92
		);
93
 
94
		$pageEditRequired = $this->_('Note that role must also have page-edit permission for any checked templates above.');
95
 
96
		$this->templatePermissionNotes = array(
97
			'default' => $this->_('Most permissions that can be assigned by template also require that the user have page-edit permission to the template. If a template you need is not listed, you must enable access control for it first (see “Access” tab when editing a template).'),
98
			'page-create' => $pageEditRequired,
99
			'page-publish' => $pageEditRequired, 
100
			'page-add' => $this->_('Unlike most other permissions, page-edit permission to a template is not a pre-requisite for this permission.'), 
101
			'page-edit' => $this->_('Templates with an asterisk (*) are configured for edit-related permissions to also inherit to children and through the page tree, unless/until overridden by a page using a different access controlled template.'),
102
			'page-view' => $this->_('This permission is also inherited to children and through the page tree, unless/until overridden by a page using a different access controlled template.'), 
103
		);
104
 
105
	}
106
 
107
	/**
108
	 * Hook ProcessPageEdit::processInput to save permission options
109
	 * 
110
	 * @param HookEvent $event
111
	 * 
112
	 */
113
	public function hookProcessInput(HookEvent $event) {
114
		static $n = 0;
45 mjordaan 115
		if(!$n && $event->wire()->input->post('_pw_page_name')) {
1 mjordaan 116
			$this->savePermissionOptions();
117
			$n++;
118
		}
119
	}
120
 
121
	/**
122
	 * Hook before InputfieldForm::render to manipulate output of permissions field
123
	 * 
124
	 * @param HookEvent $event
125
	 * 
126
	 */
127
	public function hookFormRender(HookEvent $event) {
128
 
129
		/** @var Inputfieldform $form */
130
		$form = $event->object;
131
		/** @var InputfieldPage $f */
132
		$f = $form->getChildByName('permissions');
133
		if(!$f) return;
134
 
45 mjordaan 135
		if($this->getPage()->id == $this->wire()->config->superUserRolePageID) {
1 mjordaan 136
			$f->wrapAttr('style', 'display:none');
137
			$fn = $form->getChildByName('_pw_page_name');
138
			if($fn) $fn->notes = $this->_('Note: superuser role always has all permissions, so permissions field is not shown.'); 
139
		}
140
 
141
		$f->entityEncodeText = false;
142
		$f->addClass('global-permission');
143
		$f->label = $this->_('Permissions'); 
144
		$f->description = $f->entityEncode(
145
			sprintf(
146
				$this->_('For detailed descriptions of these permissions, please see the [permissions reference](%s).'), // Permissions documentation info
147
				'https://processwire.com/api/user-access/permissions/'
148
			), true
149
		); 
150
 
151
		$f = $f->getInputfield();
152
		/** @var InputfieldCheckboxes $f */
153
		$f->table = true;
154
		$f->thead = $this->_('name|description| '); // Table head with each column title separated by a pipe "|"
155
		$value = $f->attr('value');
156
		$options = $f->getOptions();
157
		$pageViewID = 0; 
158
 
45 mjordaan 159
		foreach($options as $name => $label) {
160
			$f->removeOption($name);
161
		}
1 mjordaan 162
 
163
		// establish root permission containers
45 mjordaan 164
		foreach($this->wire()->permissions as $permission) {
1 mjordaan 165
			if($permission->getParentPermission()->id) continue;
166
			$permissions[$permission->name] = array();
167
			if($permission->name == 'page-view') $pageViewID = $permission->id;
168
			if($permission->name == 'page-edit') {
169
				$permissions[$permission->name]['page-add'] = array();
170
				$permissions[$permission->name]['page-create'] = array();
171
			}
172
		}
173
 
174
		ksort($permissions);
175
		$pageView = $permissions['page-view'];
176
		$pageEdit = $permissions['page-edit'];
177
		$permissions = array_merge(array('page-view' => $pageView, 'page-edit' => $pageEdit), $permissions); 
178
 
45 mjordaan 179
		foreach($this->wire()->permissions as $permission) {
1 mjordaan 180
			/** @var Permission $permission */
181
			/** @var Permission $parent */
182
			$parent = $permission->getParentPermission();
183
			if(!$parent->id) continue;
184
			if(isset($permissions[$parent->name])) {
185
				$permissions[$parent->name][$permission->name] = array();
186
			} else {
187
				$grandparent = $parent->getParentPermission();
188
				if($grandparent->id) {
189
					if(!isset($permissions[$grandparent->name][$parent->name])) {
190
						$permissions[$grandparent->name][$parent->name] = array();
191
					}
192
					$permissions[$grandparent->name][$parent->name][$permission->name] = array();
193
				} else {
194
					// this should not be able to occur, but here as a fallback just in case
195
					$permissions[$parent->name][$permission->name] = array();
196
				}
197
			}
198
		}
199
 
200
		if(!in_array($pageViewID, $value)) $value[] = $pageViewID;  // required
201
 
202
		$this->addPermissionOptions($permissions, $f, 0, $value);
203
 
204
		$f->attr('value', $value);
205
	}
206
 
207
	/**
208
	 * Add permission options to checkboxes Inputfield 
209
	 * 
210
	 * @param array $permissions
211
	 * @param Inputfield $f
212
	 * @param int $level
213
	 * @param $inputfieldValue
214
	 * 
215
	 */
216
	protected function addPermissionOptions(array $permissions, Inputfield $f, $level, &$inputfieldValue) {
217
 
218
		/** @var InputfieldCheckboxes $f */
219
		/** @var Role $role */
220
		$role = $this->getPage();
221
 
222
		foreach($permissions as $name => $children) {
223
 
224
			$alert = '';
225
			$confirm = '';
226
			$addedTemplates = array();
227
			$revokedTemplates = array();
228
			$disabled = false;
229
			$checked = false;
230
			$appliesAllEditable = false;
231
			$templateCheckboxes = array();
232
			$pageEditTemplates = array();
233
 
234
			if($name == 'page-add' || $name == 'page-create') {
45 mjordaan 235
				$parent = $this->wire()->permissions->get('page-edit');
1 mjordaan 236
				$rootParent = $parent;
237
				$permission = new Permission(); 
238
				$permission->set('name', $name); 
239
				if($name == 'page-add') {
240
					$title = $this->_('Add children to pages using template');
241
				} else {
242
					$title = $this->_('Create pages using template');
243
				}
244
				$alert = $this->_('This permission can only be assigned by template.');
245
			} else {
45 mjordaan 246
				$permission = $this->wire()->permissions->get($name);
1 mjordaan 247
				if(!$permission->id) continue;
45 mjordaan 248
				$title = str_replace('|', ' ', $this->wire()->sanitizer->entities($permission->getUnformatted('title')));
1 mjordaan 249
				$parent = $permission->getParentPermission();
250
				$rootParent = $permission->getRootParentPermission();
251
				$checked = in_array($permission->id, $inputfieldValue);
252
			}
253
 
254
			$title = "<span class='permission-title'>$title</span>";
255
 
256
			if($name == 'page-view') {
257
				$title .= $this->renderDetail($this->_('(required)'));
258
				$alert = $this->_('This permission is required for all roles.');
259
			} else if($name == 'page-edit') {
260
			}
261
			if(($parent->name == 'page-edit' || $rootParent->name == 'page-edit') && strpos($name, 'page-') === 0) {
262
				if($name == 'page-add' || $name == 'page-create') {
263
					// $title = $title;
264
				} else {
265
					$appliesAllEditable = true; 
266
					$title .= $this->renderDetail('(' . $this->_('applies to all editable templates') . ')', 'permission-all-templates');
267
				}
268
			}
269
 
45 mjordaan 270
			foreach($this->wire()->templates as $template) {
1 mjordaan 271
 
272
				if(!$template->useRoles) continue;
273
				$rolesPermissions = $template->rolesPermissions;
274
 
275
				$templateEditURL = "../../../setup/template/edit?id=$template->id#tab_access";
276
				$templateEditLink = $this->renderLink($templateEditURL, $this->icons['add'] . $template->name, array(
277
					'class' => 'tooltip',
278
					'target' => '_blank', 
279
					'title' => '{tooltip}',
280
				));
281
 
282
				if($name == 'page-edit') {
283
					if(in_array($role->id, $template->editRoles)) {
284
						$addedTemplates[$template->name] = $templateEditLink;
285
						$pageEditTemplates[$template->name] = $template;
286
					}
287
				} else if($name == 'page-create') {
288
					if(in_array($role->id, $template->createRoles)) {
289
						$checked = true;
290
						$addedTemplates[$template->name] = $templateEditLink;
291
					}
292
				} else if($name == 'page-add') {
293
					if(in_array($role->id, $template->addRoles)) {
294
						$checked = true;
295
						$addedTemplates[$template->name] = $templateEditLink;
296
					}
297
				} else if($name == 'page-view') {
298
					if($template->hasRole($role)) {
299
						$checked = true;
300
						$addedTemplates[$template->name] = $templateEditLink;
301
					}
302
				} else if(isset($rolesPermissions[$role->id])) {
303
					// custom added or revoked permission
304
					if(in_array($permission->id, $rolesPermissions[$role->id])) {
305
						$addedTemplates[$template->name] = $templateEditLink;
306
					} else if(in_array($permission->id * -1, $rolesPermissions[$role->id])) {
307
						$revokedTemplates[$template->name] = str_replace($this->icons['add'], $this->icons['revoke'], $templateEditLink);
308
					}
309
				}
310
 
311
				// if a system template, then do nothing further 
312
				if($template->flags & Template::flagSystem) continue;
313
 
314
				if(isset($this->templatePermissionDescriptions[$name]) || $appliesAllEditable) {
315
					// base permission: page-view, page-edit, page-create, page-add
316
					$checked = isset($addedTemplates[$template->name]);
317
					$templateCheckboxes[] = $this->renderTemplatePermissionCheckbox($template, $permission, $checked); 
318
				}
319
			} // foreach(templates)
320
 
321
			if(count($addedTemplates) || count($revokedTemplates)) {
322
				// permission was added or revoked from specific templates
323
 
324
				/*
325
				foreach($addedTemplates as $templateName => $link) {
326
					$tooltip = sprintf($this->_('%1$s added by template %2$s, click to edit'), $name, $templateName); 
327
					$addedTemplates[$templateName] = str_replace('{tooltip}', $tooltip, $link);
328
				}
329
				foreach($revokedTemplates as $templateName => $link) {
330
					$tooltip = sprintf($this->_('%1$s revoked by template %2$s, click to edit'), $name, $templateName); 
331
					$revokedTemplates[$templateName] = str_replace('{tooltip}', $tooltip, $link);
332
				}
333
				*/
334
 
335
				if($name != 'page-edit' && $permission->id) {
336
					if(!in_array($permission->id, $inputfieldValue)) {
337
						$confirm = $this->_('Checking this box adds the permission for all editable templates, but this permission is already being applied separately by one or more templates. To keep things tidy, we suggest removing the permission from those templates before enabling it for all. Are you sure you want to enable it now?'); // Alert for enabling a permission for all templates
338
					}
339
				}
340
 
341
				/*
342
				if(count($addedTemplates)) {
343
					$label = implode(' ', $addedTemplates);
344
					$title .= $this->renderDetail($label, 'permission-added'); 
345
				}
346
 
347
				if(count($revokedTemplates)) {
348
					$label = implode(' ', $revokedTemplates);
349
					$title .= $this->renderDetail($label, 'permission-revoked'); 
350
				}
351
				*/
352
			}
353
 
354
			$classes = array(
355
				"permission",
356
				"permission-$name", 
357
				"level$level", 
358
			);
359
 
360
			$p = $parent;
361
 
362
			while($p->id) {
363
				$classes[] = "parent-permission$p->id"; 
364
				$classes[] = "parent-permission-$p->name";
365
				$p = $p->getParentPermission();
366
			}
367
 
368
			if($permission->id) {
369
				$value = $permission->id;
370
				$id = "permission$permission->id";
371
				if($appliesAllEditable) $classes[] = "page-edit-templates";
372
			} else {
373
				$value = "0-$name";
374
				$id = "permission0-$name";
375
				$disabled = true; 
376
			}
377
 
378
			if($disabled) $classes[] = 'checkbox-disabled';
379
 
380
			$attributes = array(
381
				"id" => $id, 
382
				"class" => implode(' ', $classes),
383
				"data-parent" => "permission$parent->id",
384
				"data-level" => $level
385
			);
386
 
387
			if($disabled) $attributes['disabled'] = 'disabled';
388
			if($alert) $attributes['data-alert'] = $alert;
389
			if($confirm) $attributes['data-confirm'] = $confirm;
390
 
391
			if(!$permission->id && $checked) $inputfieldValue[] = $value;
392
 
393
			/*
394
			$title = 
395
				"<a class='permission-help' target='_blank' href='https://processwire.com/api/user-access/permissions/#$name'>" . 
396
				$this->icons['help'] . "</a>" . $title;
397
			*/
398
 
399
			if(count($templateCheckboxes)) {
400
				$checkboxes = $this->renderTemplatePermissionCheckboxes($permission, $templateCheckboxes); 
401
				$toggle = $this->renderTemplatePermissionToggle();
402
				$f->addOption($value, "$name|$title$checkboxes|$toggle", $attributes);
403
			} else {
404
				$f->addOption($value, "$name|$title| ", $attributes);
405
			}
406
 
407
			if(count($children)) {
408
				$this->addPermissionOptions($children, $f, $level+1, $inputfieldValue);
409
			}
410
		} // foreach(permissions)
411
	}
412
 
413
	/**
414
	 * Render a div containing template permission checkboxes
415
	 * 
416
	 * @param Permission $permission
417
	 * @param array $checkboxes Array of individually rendered checkboxes for each template
418
	 * @return string
419
	 * 
420
	 */
421
	protected function renderTemplatePermissionCheckboxes(Permission $permission, array $checkboxes) {
422
 
423
		$name = $permission->name;
424
		if(isset($this->templatePermissionNotes[$name])) {
425
			$note = $this->templatePermissionNotes[$name];
426
		} else {
427
			$note = $this->templatePermissionNotes['default'];
428
		}
429
 
430
		if(isset($this->templatePermissionDescriptions[$name])) {
431
			$desc = 
432
				"<p class='description'>" . $this->templatePermissionDescriptions[$name] . "</p>";
433
		} else {
434
			$desc = 
435
				"<p class='description description-not-checked'>" . 
436
					str_replace('{permission}', $name, $this->templatePermissionDescriptions['default-add']) . 
437
				"</p>" .
438
				"<p class='description description-checked'>" . 
439
					str_replace('{permission}', $name, $this->templatePermissionDescriptions['default-revoke']) . 
440
				"</p>";
441
 
442
		}
443
 
444
		$class = 'template-permissions';
445
		$checkboxes = implode('', $checkboxes);
446
 
447
		if(strpos($checkboxes, ' checked ') || in_array($name, array('page-edit', 'page-view', 'page-add', 'page-create'))) {
448
			$class .= ' template-permissions-click';
449
		}
450
 
451
		return 
452
			"<div class='$class'>" .
453
				$desc . 	
454
				"<p class='template-checkboxes'>$checkboxes</p>" .
455
				($note ? "<p class='detail'>$note</p>" : "") .
456
			"</div>";
457
	}
458
 
459
	/**
460
	 * Render a single template permission checkbox
461
	 * 
462
	 * @param Template $template
463
	 * @param Permission $permission
464
	 * @param bool $checked 
465
	 * @return string
466
	 * 
467
	 */
468
	protected function renderTemplatePermissionCheckbox(Template $template, Permission $permission, $checked) {
469
 
470
		$disabled = false;
471
		$perm = $permission->name;
472
		$templateLabel = $template->name;
473
		$note = '';
474
 
475
		if($perm == 'page-view' && $this->guestRole->hasPermission('page-view', $template)) {
476
			$checked = true;
477
			$disabled = true;
478
			$note = $this->_('(required because inherited from guest role)');
479
		} else if($perm == 'page-edit' && !$template->noInherit) {
480
			$templateLabel .= '*';
481
		}
482
 
483
		$checked = $checked ? 'checked' : '';
484
		$disabled = $disabled ? 'onclick="return false"' : '';
485
		$class = "template-permission template{$template->id}-permission$permission->id";
486
 
487
		// note: pt=permission+template, tp=template+permission
488
 
489
		if($perm == 'page-add') {
490
			$name = "pt_add_$template->id";
491
		} else if($perm == 'page-create') {
492
			$name = "pt_create_$template->id";
493
		} else if($perm == 'page-edit' || $perm == 'page-view') {
494
			$name = "pt_{$permission->id}_{$template->id}";
495
		} else {
496
			$name = '';
497
		}
498
 
499
		if($name) {
500
			// checkbox
501
			$out = 
502
				"<label>" .
503
					"<input type='checkbox' $checked $disabled name='$name' value='1' class='$class'>" .
504
					"$templateLabel <span class='detail'>$note</span>" .
505
				"</label>";
506
		} else {
507
			// select add or revoke
508
			/** @var Role $role */
509
			$role = $this->getPage();
510
			$name = "tp_{$template->id}[]";
511
			$rolesPermissions = $template->rolesPermissions;
512
			$rolePermissions = isset($rolesPermissions["$role->id"]) ? $rolesPermissions["$role->id"] : array();
513
			$addChecked = in_array("$permission->id", $rolePermissions) ? 'checked' : ''; 
514
			$revokeChecked = in_array("-$permission->id", $rolePermissions) ? 'checked' : '';
515
			$out =
516
				"<label class='template-permission-add'>" .
517
					"<input type='checkbox' name='add_$name' value='$permission->id' $addChecked class='$class'>" .
518
					sprintf($this->_('Add to: %s'), $templateLabel) . 
519
				"</label>" . 
520
				"<label class='template-permission-revoke'>" .
521
					"<input type='checkbox' name='revoke_$name' value='$permission->id' $revokeChecked class='$class'>" .
522
					sprintf($this->_('Revoke from: %s'), $templateLabel) . 
523
				"</label>";
524
		}
525
 
526
		return $out;
527
	}
528
 
529
	/**
530
	 * Render the toggle that can trigger the template permission checkboxes
531
	 *
532
	 * @return string
533
	 *
534
	 */
535
	protected function renderTemplatePermissionToggle() {
536
		return
537
			"<a href='#' class='toggle-template-permissions tooltip' title='" . $this->_('Click to open/close permission settings by template') . "'>" .
538
			"<i class='fa fa-chevron-circle-right' data-toggle='fa-chevron-circle-down fa-chevron-circle-right'></i>" .
539
			"</a>";
540
	}
541
 
542
	/**
543
	 * Render an <a> link
544
	 * 
545
	 * @param string $href
546
	 * @param string $text
547
	 * @param array $attr
548
	 * @return string
549
	 * 
550
	 */
551
	protected function renderLink($href, $text, array $attr = array()) {
552
		$attr['href'] = $href;
553
		$out = "<a ";
554
		foreach($attr as $key => $value) {
45 mjordaan 555
			$out .= " $key='" . $this->wire()->sanitizer->entities($value) . "'";
1 mjordaan 556
		}
557
		$out .= ">$text</a>";
558
		return $out; 
559
	}
560
 
561
	/**
562
	 * Render a detail
563
	 * 
564
	 * @param string $text Markup to render in the detail
565
	 * @param string $class May be omitted if not needed
566
	 * @param string $tag Default is span
567
	 * @return string
568
	 * 
569
	 */
570
	protected function renderDetail($text, $class = '', $tag = 'span') {
571
		$class = $class ? "detail $class" : "detail";
572
		return ' ' . $this->renderText($text, $class, $tag); 
573
	}
574
 
575
	/**
576
	 * Render paragraph of text (or other tag as specified)
577
	 * 
578
	 * @param string $text
579
	 * @param string $class Default is blank
580
	 * @param string $tag Default is p
581
	 * @return string
582
	 * 
583
	 */
584
	protected function renderText($text, $class = '', $tag = 'p') {
585
		$class = $class ? " class='$class'" : "";	
586
		return "<$tag$class>$text</$tag>";
587
	}
588
 
589
	/**
590
	 * Save posted permission options to templates
591
	 * 
592
	 */
593
	protected function savePermissionOptions() {
594
 
595
		$role = $this->getPage();
596
		if(!$role->id) return;
597
		$isGuestRole = $role->id == $this->guestRole->id;
598
 
45 mjordaan 599
		$input = $this->wire()->input;
600
		$permissions = $this->wire()->permissions;
1 mjordaan 601
 
45 mjordaan 602
		$viewPermission = $permissions->get('page-view');
603
		$editPermission = $permissions->get('page-edit');
1 mjordaan 604
 
45 mjordaan 605
		foreach($this->wire()->templates as $template) {
1 mjordaan 606
 
607
			/** @var Template $template */
608
			if(!$template->useRoles) continue;
609
			if($template->flags & Template::flagSystem) continue;
610
 
611
			$updates = array();
612
			$createRoles = $template->createRoles;
613
			$addRoles = $template->addRoles;
614
			$editRoles = $template->editRoles;
615
			$guestHasView = $this->guestRole->hasPermission($viewPermission, $template); 
616
			$rolesPermissions = $template->rolesPermissions;
617
			$rolePermissions = isset($rolesPermissions["$role->id"]) ? $rolesPermissions["$role->id"] : array();
618
 
619
			$view = $input->post("pt_{$viewPermission->id}_{$template->id}"); 
620
			$edit = $input->post("pt_{$editPermission->id}_{$template->id}"); 
621
			$add = $input->post("pt_add_{$template->id}");
622
			$create = $input->post("pt_create_{$template->id}"); 
623
 
624
			// page-view
625
			if($view) {
626
				if(!$template->hasRole($role)) {
627
					$template->addRole($role); 
628
					$updates[] = "Added page-view to template $template->name";
629
				}
630
			} else {
631
				if($template->hasRole($role)) {
632
					if($isGuestRole || !$guestHasView) {
633
						$template->removeRole($role);
634
						$updates[] = "Removed page-view from template $template->name";
635
						// view is a pre-requisite for edit, add and create permissions
636
						if($edit) $updates[] = "Also removed all edit-related permissions because edit requires view permission";
637
					}
638
				}
639
				if($isGuestRole || !$guestHasView) {
640
					$edit = false;
641
					$add = false;
642
					$create = false;
643
				}
644
			}
645
 
646
			if(!$isGuestRole) {
647
 
648
				// page-edit
649
				if($edit) {
650
					if(!in_array($role->id, $editRoles)) {
651
						$editRoles[] = $role->id;
652
						$updates[] = "Added page-edit to template $template->name";
653
					}
654
				} else {
655
					$key = array_search($role->id, $editRoles);
656
					if($key !== false) {
657
						unset($editRoles[$key]);
658
						$updates[] = "Removed page-edit from template $template->name";
659
					}
660
				}
661
 
662
				// page-add
663
				if($add) {
664
					if(!in_array($role->id, $addRoles)) {
665
						$addRoles[] = $role->id;
666
						$updates[] = "Added page-add to template $template->name";
667
					}
668
				} else {
669
					$key = array_search($role->id, $addRoles);
670
					if($key !== false) {
671
						unset($addRoles[$key]);
672
						$updates[] = "Removed page-add from template $template->name";
673
					}
674
				}
675
 
676
				// page-create
677
				if($create) {
678
					if(!in_array($role->id, $createRoles)) {
679
						$createRoles[] = $role->id;
680
						$updates[] = "Added page-create to template $template->name";
681
					}
682
				} else {
683
					$key = array_search($role->id, $createRoles);
684
					if($key !== false) {
685
						unset($createRoles[$key]);
686
						$updates[] = "Removed page-create from template $template->name";
687
					}
688
				}
689
			} // if(!isGuestRole)
690
 
691
			// rolesPermissions
692
			$adds = $input->post->intArray("add_tp_$template->id");
693
			$revokes = $input->post->intArray("revoke_tp_$template->id");
694
 
695
			foreach($adds as $key => $permissionID) {
696
				// force as strings
697
				$adds[$key] = "$permissionID"; // placement intentional
698
 
699
				if(!$edit) {
700
					/** @var Permission $permission */
45 mjordaan 701
					$permission = $permissions->get((int) $permissionID);
1 mjordaan 702
					if(!$permission->id) continue;
703
					$parentPermission = $permission->getParentPermission();
704
					// if permission requires page-edit, and user doesn't have page-edit, don't allow it to be added
705
					if($parentPermission->name == 'page-edit') {
706
						unset($adds[$key]); // placement intentional
707
						$this->warning(sprintf(
708
							$this->_('Permission “%1$s” for template “%2$s” not allowed (requires “%3$s” permission)'),
709
							$permission->name, $template->name, $parentPermission->name	
710
						));
711
					}
712
				}
713
			}
714
 
715
			foreach($revokes as $key => $permissionID) {
716
				// force as negative integer strings
717
				$revokes[$key] = (string) (-1 * $permissionID);
718
			}
719
 
720
			$rolePermissionsNew = array_merge($adds, $revokes); 
721
			sort($rolePermissionsNew); 
722
			sort($rolePermissions);
723
			if($rolePermissionsNew != $rolePermissions) { 
45 mjordaan 724
				if($this->wire()->config->debug) {
1 mjordaan 725
					$removedPermissions = array_diff($rolePermissions, $rolePermissionsNew);
726
					$addedPermissions = array_diff($rolePermissionsNew, $rolePermissions);
727
					foreach($removedPermissions as $permissionID) {
728
						$permissionID = (int) $permissionID;
45 mjordaan 729
						$permission = $permissions->get(abs($permissionID));
1 mjordaan 730
						$updates[] = ($permissionID < 0 ? "Removed revoke" : "Removed add") . " " . 
731
							"$permission->name for template $template->name" ;
732
					}
733
					foreach($addedPermissions as $permissionID) {
734
						$permissionID = (int) $permissionID;
45 mjordaan 735
						$permission = $permissions->get(abs($permissionID));
1 mjordaan 736
						$updates[] = ($permissionID < 0 ? "Added revoke" : "Added add") . " " .
737
							"$permission->name for template $template->name" ;
738
					}
739
				}
740
				$updates[] = "Updated rolesPermissions for template $template->name";
741
				$rolesPermissions["$role->id"] = $rolePermissionsNew;
742
				$template->rolesPermissions = $rolesPermissions;
743
			}
744
 
745
			// save changes
746
			if(count($updates)) {
747
 
748
				if($editRoles != $template->editRoles) $template->editRoles = $editRoles;
749
				if($addRoles != $template->addRoles) $template->addRoles = $addRoles;
750
				if($createRoles != $template->createRoles) $template->createRoles = $createRoles;
751
 
45 mjordaan 752
				if($this->wire()->config->debug) {
1 mjordaan 753
					foreach($updates as $update) $this->message($update);
754
				}
755
 
756
				$template->save();
757
			}
758
		}
759
	}
760
}