mirror of
https://github.com/processwire/processwire.git
synced 2025-08-09 08:17:12 +02:00
Add improved Roles editor that now lets you manage permissions by template
This commit is contained in:
@@ -45,7 +45,7 @@ class ProcessWire extends Wire {
|
|||||||
* Reversion revision number
|
* Reversion revision number
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
const versionRevision = 80;
|
const versionRevision = 81;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Version suffix string (when applicable)
|
* Version suffix string (when applicable)
|
||||||
|
@@ -25,6 +25,8 @@ class Role extends Page {
|
|||||||
/**
|
/**
|
||||||
* Create a new Role page in memory.
|
* Create a new Role page in memory.
|
||||||
*
|
*
|
||||||
|
* @param Template $tpl
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public function __construct(Template $tpl = null) {
|
public function __construct(Template $tpl = null) {
|
||||||
parent::__construct($tpl);
|
parent::__construct($tpl);
|
||||||
|
@@ -362,7 +362,7 @@ class Template extends WireData implements Saveable, Exportable {
|
|||||||
* - `edit`
|
* - `edit`
|
||||||
* - `create`
|
* - `create`
|
||||||
* - `add`
|
* - `add`
|
||||||
* - Or a `Permission` object
|
* - Or a `Permission` object of `page-view` or `page-edit`
|
||||||
* @return bool True if template has the role, false if not
|
* @return bool True if template has the role, false if not
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -402,12 +402,12 @@ class Template extends WireData implements Saveable, Exportable {
|
|||||||
* #pw-group-manipulation
|
* #pw-group-manipulation
|
||||||
*
|
*
|
||||||
* @param array|PageArray $value Role objects or array or Role IDs.
|
* @param array|PageArray $value Role objects or array or Role IDs.
|
||||||
* @param string Specify one of the following:
|
* @param string $type Specify one of the following:
|
||||||
* - `view` (default)
|
* - `view` (default)
|
||||||
* - `edit`
|
* - `edit`
|
||||||
* - `create`
|
* - `create`
|
||||||
* - `add`
|
* - `add`
|
||||||
* - Or a `Permission` object
|
* - Or a `Permission` object of `page-view` or `page-edit`
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setRoles($value, $type = 'view') {
|
public function setRoles($value, $type = 'view') {
|
||||||
@@ -433,6 +433,40 @@ class Template extends WireData implements Saveable, Exportable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a permission that applies to users having a specific role with pages using this template
|
||||||
|
*
|
||||||
|
* Note that the change is not committed until you save() the template.
|
||||||
|
*
|
||||||
|
* @param Permission|int|string $permission Permission object, name, or id
|
||||||
|
* @param Role|int|string $role Role object, name or id
|
||||||
|
* @param bool $test Specify true to only test if an update would be made, without changing anything
|
||||||
|
* @return bool Returns true if an update was made (or would be made), false if not
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function addPermissionByRole($permission, $role, $test = false) {
|
||||||
|
return $this->wire('templates')->setTemplatePermissionByRole($this, $permission, $role, false, $test);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Revoke a permission that applies to users having a specific role with pages using this template
|
||||||
|
*
|
||||||
|
* Note that the change is not committed until you save() the template.
|
||||||
|
*
|
||||||
|
* @param Permission|int|string $permission Permission object, name, or id
|
||||||
|
* @param Role|int|string $role Role object, name or id
|
||||||
|
* @param bool $test Specify true to only test if an update would be made, without changing anything
|
||||||
|
* @return bool Returns true if an update was made (or would be made), false if not
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function revokePermissionByRole($permission, $role, $test = false) {
|
||||||
|
return $this->wire('templates')->setTemplatePermissionByRole($this, $permission, $role, true, $test);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasPermissionByRole($permission, $role) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does this template have the given Field?
|
* Does this template have the given Field?
|
||||||
*
|
*
|
||||||
@@ -748,7 +782,7 @@ class Template extends WireData implements Saveable, Exportable {
|
|||||||
*
|
*
|
||||||
* #pw-group-manipulation
|
* #pw-group-manipulation
|
||||||
*
|
*
|
||||||
* @return $this|bool Returns Template if successful, or false if not
|
* @return Template|bool Returns Template if successful, or false if not
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function save() {
|
public function save() {
|
||||||
@@ -809,7 +843,7 @@ class Template extends WireData implements Saveable, Exportable {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function hookFinished(HookEvent $e) {
|
public function hookFinished(HookEvent $e) {
|
||||||
foreach($this->wire('templates') as $template) {
|
foreach($e->wire('templates') as $template) {
|
||||||
if($template->isChanged('modified') || $template->isChanged('ns')) $template->save();
|
if($template->isChanged('modified') || $template->isChanged('ns')) $template->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1041,7 +1075,7 @@ class Template extends WireData implements Saveable, Exportable {
|
|||||||
*
|
*
|
||||||
* #pw-group-identification
|
* #pw-group-identification
|
||||||
*
|
*
|
||||||
* @param $icon Font-awesome icon name
|
* @param string $icon Font-awesome icon name
|
||||||
* @return $this
|
* @return $this
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@@ -556,6 +556,88 @@ class Templates extends WireSaveableItems {
|
|||||||
return $this->getParentPage($template, $checkAccess, true);
|
return $this->getParentPage($template, $checkAccess, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a Permission for a Template for and specific Role
|
||||||
|
*
|
||||||
|
* Note: you must also save() the template to commit the change.
|
||||||
|
*
|
||||||
|
* #pw-internal
|
||||||
|
*
|
||||||
|
* @param Template $template
|
||||||
|
* @param Permission|string|int $permission
|
||||||
|
* @param Role|string|int $role
|
||||||
|
* @param bool $revoke Specify true to revoke the permission, or omit to add the permission
|
||||||
|
* @param bool $test When true, no changes are made but return value still applicable
|
||||||
|
* @return bool True if an update was made (or would be made), false if not
|
||||||
|
* @throws WireException If given unknown Role or Permission
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function setTemplatePermissionByRole(Template $template, $permission, $role, $revoke = false, $test = false) {
|
||||||
|
|
||||||
|
if(!$template->useRoles) throw new WireException("Template $template does not have access control enabled");
|
||||||
|
|
||||||
|
$defaultPermissions = array('page-view', 'page-edit', 'page-create', 'page-add');
|
||||||
|
$updated = false;
|
||||||
|
|
||||||
|
if(is_string($role) || is_int($role)) $role = $this->wire('roles')->get($role);
|
||||||
|
if(!$role instanceof Role) throw new WireException("Unknown role for Template::setPermissionByRole");
|
||||||
|
|
||||||
|
if(is_string($permission) && in_array($permission, $defaultPermissions)) {
|
||||||
|
$permissionName = $permission;
|
||||||
|
} else if($permission instanceof Permission) {
|
||||||
|
$permissionName = $permission->name;
|
||||||
|
} else {
|
||||||
|
$permission = $this->wire('permissions')->get($permission);
|
||||||
|
$permissionName = $permission ? $permission->name : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if(in_array($permissionName, $defaultPermissions)) {
|
||||||
|
// use pre-defined view/edit/create/add roles
|
||||||
|
$roles = $template->getRoles($permissionName);
|
||||||
|
$has = $roles->has($role);
|
||||||
|
if($revoke) {
|
||||||
|
if($has) {
|
||||||
|
if($test) return true;
|
||||||
|
$roles->remove($role);
|
||||||
|
$template->setRoles($roles, $permissionName);
|
||||||
|
$updated = true;
|
||||||
|
}
|
||||||
|
} else if(!$has) {
|
||||||
|
if($test) return true;
|
||||||
|
$roles->add($role);
|
||||||
|
$template->setRoles($roles, $permissionName);
|
||||||
|
$updated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if($permission instanceof Permission) {
|
||||||
|
$rolesPermissions = $template->get('rolesPermissions');
|
||||||
|
if(!is_array($rolesPermissions)) $rolesPermissions = array();
|
||||||
|
$rolePermissions = isset($rolesPermissions["$role->id"]) ? $rolesPermissions["$role->id"] : array();
|
||||||
|
$_rolePermissions = $rolePermissions;
|
||||||
|
if($revoke) {
|
||||||
|
$key = array_search("$permission->id", $rolePermissions);
|
||||||
|
if($key !== false) unset($rolePermissions[$key]);
|
||||||
|
if(!in_array("-$permission->id", $rolePermissions)) $rolePermissions[] = "-$permission->id";
|
||||||
|
} else {
|
||||||
|
$key = array_search("-$permission->id", $rolePermissions);
|
||||||
|
if($key !== false) unset($rolePermissions[$key]);
|
||||||
|
if(!in_array("$permission->id", $rolePermissions)) $rolePermissions[] = "$permission->id";
|
||||||
|
}
|
||||||
|
if($rolePermissions !== $_rolePermissions) {
|
||||||
|
if($test) return true;
|
||||||
|
$rolesPermissions["$role->id"] = $rolePermissions;
|
||||||
|
$template->set('rolesPermissions', $rolesPermissions);
|
||||||
|
$updated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new WireException("Unknown permission for Templates::setPermissionByRole");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FUTURE USE: Is the parent/child relationship allowed?
|
* FUTURE USE: Is the parent/child relationship allowed?
|
||||||
*
|
*
|
||||||
|
@@ -44,6 +44,7 @@ class InputfieldCheckboxes extends InputfieldSelectMultiple implements Inputfiel
|
|||||||
/** @var MarkupAdminDataTable $table */
|
/** @var MarkupAdminDataTable $table */
|
||||||
$table = $this->modules->get("MarkupAdminDataTable");
|
$table = $this->modules->get("MarkupAdminDataTable");
|
||||||
$table->setEncodeEntities(false);
|
$table->setEncodeEntities(false);
|
||||||
|
$table->setSortable(false);
|
||||||
$table->addClass('pw-no-select');
|
$table->addClass('pw-no-select');
|
||||||
if($this->thead) $table->headerRow(explode('|', htmlspecialchars($this->thead, ENT_QUOTES, 'UTF-8')));
|
if($this->thead) $table->headerRow(explode('|', htmlspecialchars($this->thead, ENT_QUOTES, 'UTF-8')));
|
||||||
|
|
||||||
|
@@ -6,15 +6,12 @@ label.level2 {
|
|||||||
padding-left: 2.25em;
|
padding-left: 2.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#wrap_Inputfield_permissions td i.fa {
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
#wrap_Inputfield_permissions table td {
|
#wrap_Inputfield_permissions table td {
|
||||||
width: 70%;
|
width: 75%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#wrap_Inputfield_permissions table > tbody > tr > td:first-child {
|
#wrap_Inputfield_permissions table > tbody > tr > td:first-child {
|
||||||
width: 30%;
|
width: 25%;
|
||||||
}
|
}
|
||||||
|
|
||||||
tr:not(.permission32):not(.permission0-page-add):not(.permission0-page-create).permission-checked .permission-added {
|
tr:not(.permission32):not(.permission0-page-add):not(.permission0-page-create).permission-checked .permission-added {
|
||||||
@@ -58,3 +55,56 @@ p.description + p.description {
|
|||||||
margin: 0.5em 0;
|
margin: 0.5em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.template-permissions {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
|
.template-permissions:not(.template-permissions-open) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.template-permissions > p {
|
||||||
|
margin: 0.5em 0;
|
||||||
|
}
|
||||||
|
.template-permissions label {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-template-permissions {
|
||||||
|
display: block;
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.permission-title {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-edit-templates .permission-title {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.permission-page-edit:not(.permission-checked) .toggle-template-permissions {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
tr.permission-page-edit:not(.permission-checked) .template-permissions,
|
||||||
|
tr.permission-page-edit:not(.permission-checked) .template-permissions-open {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
tr.permission-checked .template-permissions label.template-permission-add {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
tr.permission-checked .description-not-checked {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
tr:not(.permission-checked) .description-checked {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
tr:not(.permission-checked) .template-permissions label.template-permission-revoke {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#ProcessPageEdit table.AdminDataTable tr > th,
|
||||||
|
#ProcessPageEdit table.AdminDataTable tr > td {
|
||||||
|
/* AdminThemeDefault and AdminThemeReno */
|
||||||
|
border-left: none;
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
function ProcessRoleUpdatePermissions(init, $checkbox) {
|
function ProcessRoleUpdatePermissions(init, $checkbox) {
|
||||||
|
|
||||||
var $inputfield = $("#wrap_Inputfield_permissions");
|
var $inputfield = $("#wrap_Inputfield_permissions");
|
||||||
var $checkboxes = $checkbox == null ? $inputfield.find(".permission > input[type=checkbox]") : $checkbox;
|
var $checkboxes = $checkbox == null ? $inputfield.find("input.global-permission") : $checkbox;
|
||||||
|
|
||||||
if(init) {
|
if(init) {
|
||||||
// update row classes to be the same as the label classes
|
// update row classes to be the same as the label classes
|
||||||
@@ -30,11 +30,21 @@ function ProcessRoleUpdatePermissions(init, $checkbox) {
|
|||||||
$children = $children.filter(".level" + (level+1));
|
$children = $children.filter(".level" + (level+1));
|
||||||
init ? $children.show() : $children.fadeIn();
|
init ? $children.show() : $children.fadeIn();
|
||||||
$row.addClass('permission-checked');
|
$row.addClass('permission-checked');
|
||||||
|
if($row.hasClass('permission-page-edit')) {
|
||||||
|
if(!$row.find('.template-permissions-open').length) {
|
||||||
|
$row.find('.toggle-template-permissions').click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$children.find("input:not(:disabled)").removeAttr('checked');
|
$children.find("input.global-permission:not(:disabled)").removeAttr('checked');
|
||||||
init ? $children.hide() : $children.fadeOut();
|
init ? $children.hide() : $children.fadeOut();
|
||||||
$row.removeClass('permission-checked');
|
$row.removeClass('permission-checked');
|
||||||
|
if($row.hasClass('permission-page-edit')) {
|
||||||
|
if($row.find('.template-permissions-open').length) {
|
||||||
|
$row.find('.toggle-template-permissions').click();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -46,7 +56,7 @@ $(document).ready(function() {
|
|||||||
|
|
||||||
ProcessRoleUpdatePermissions(true, null);
|
ProcessRoleUpdatePermissions(true, null);
|
||||||
|
|
||||||
$("#wrap_Inputfield_permissions").on("click", "input[type=checkbox], label.checkbox-disabled", function(e) {
|
$("#wrap_Inputfield_permissions").on("click", "input.global-permission, label.checkbox-disabled", function(e) {
|
||||||
|
|
||||||
if($(this).is("label")) {
|
if($(this).is("label")) {
|
||||||
var $label = $(this);
|
var $label = $(this);
|
||||||
@@ -76,4 +86,36 @@ $(document).ready(function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(".toggle-template-permissions").click(function() {
|
||||||
|
var $div = $(this).closest('tr').find('.template-permissions');
|
||||||
|
if($div.hasClass('template-permissions-open')) {
|
||||||
|
$div.fadeOut('fast', function() {
|
||||||
|
$div.removeClass('template-permissions-open');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$div.fadeIn('fast', function() {
|
||||||
|
$div.addClass('template-permissions-open');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var $icon = $(this).find('i');
|
||||||
|
$icon.toggleClass($icon.attr('data-toggle'));
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// make some of the open when page loads
|
||||||
|
$('.template-permissions-click').each(function() {
|
||||||
|
$(this).closest('tr').find('.toggle-template-permissions').click();
|
||||||
|
$(this).removeClass('template-permissions-click');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.permission-title').click(function() {
|
||||||
|
$(this).closest('tr').find('.toggle-template-permissions').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
// ensure checkbox classes are consistent (like for uk-checkbox)
|
||||||
|
a = $('input.global-permission:eq(0)');
|
||||||
|
b = $('<div />').addClass(a.attr('class')).removeClass('permission permission-checked global-permission');
|
||||||
|
c = $('input.template-permission').addClass(b.attr('class'));
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1 +1 @@
|
|||||||
function ProcessRoleUpdatePermissions(d,b){var a=$("#wrap_Inputfield_permissions");var c=b==null?a.find(".permission > input[type=checkbox]"):b;if(d){c.each(function(){var g=$(this);var f=g.closest("label");var e=g.closest("tr");e.addClass(f.attr("class"))})}c.each(function(){var k=$(this);var f=k.closest("label");var e=k.closest("tr");var i=$("#"+f.attr("data-parent"));var h=f.text();var j=parseInt(f.attr("data-level"));var g=e.nextAll(".parent-"+f.attr("id"));e.addClass(f.attr("id"));if(k.is(":checked")){g=g.filter(".level"+(j+1));d?g.show():g.fadeIn();e.addClass("permission-checked")}else{g.find("input:not(:disabled)").removeAttr("checked");d?g.hide():g.fadeOut();e.removeClass("permission-checked")}})}$(document).ready(function(){var a=$("#Inputfield_permissions_36");if(!a.is(":checked")){a.attr("checked","checked")}ProcessRoleUpdatePermissions(true,null);$("#wrap_Inputfield_permissions").on("click","input[type=checkbox], label.checkbox-disabled",function(f){if($(this).is("label")){var b=$(this);var c=b.children("input")}else{var c=$(this);var b=c.parent()}var g=b.attr("data-alert");var d=b.attr("data-confirm");if(typeof g!="undefined"&&g.length){ProcessWire.alert(g);return false}else{if(typeof d!="undefined"&&d.length){if(c.is(":checked")){if(!confirm(d)){return false}}}}if($(this).is("input")){var c=$(this);setTimeout(function(){ProcessRoleUpdatePermissions(false,c)},100)}})});
|
function ProcessRoleUpdatePermissions(g,e){var d=$("#wrap_Inputfield_permissions");var f=e==null?d.find("input.global-permission"):e;if(g){f.each(function(){var j=$(this);var i=j.closest("label");var h=j.closest("tr");h.addClass(i.attr("class"))})}f.each(function(){var n=$(this);var i=n.closest("label");var h=n.closest("tr");var l=$("#"+i.attr("data-parent"));var k=i.text();var m=parseInt(i.attr("data-level"));var j=h.nextAll(".parent-"+i.attr("id"));h.addClass(i.attr("id"));if(n.is(":checked")){j=j.filter(".level"+(m+1));g?j.show():j.fadeIn();h.addClass("permission-checked");if(h.hasClass("permission-page-edit")){if(!h.find(".template-permissions-open").length){h.find(".toggle-template-permissions").click()}}}else{j.find("input.global-permission:not(:disabled)").removeAttr("checked");g?j.hide():j.fadeOut();h.removeClass("permission-checked");if(h.hasClass("permission-page-edit")){if(h.find(".template-permissions-open").length){h.find(".toggle-template-permissions").click()}}}})}$(document).ready(function(){var d=$("#Inputfield_permissions_36");if(!d.is(":checked")){d.attr("checked","checked")}ProcessRoleUpdatePermissions(true,null);$("#wrap_Inputfield_permissions").on("click","input.global-permission, label.checkbox-disabled",function(i){if($(this).is("label")){var f=$(this);var g=f.children("input")}else{var g=$(this);var f=g.parent()}var j=f.attr("data-alert");var h=f.attr("data-confirm");if(typeof j!="undefined"&&j.length){ProcessWire.alert(j);return false}else{if(typeof h!="undefined"&&h.length){if(g.is(":checked")){if(!confirm(h)){return false}}}}if($(this).is("input")){var g=$(this);setTimeout(function(){ProcessRoleUpdatePermissions(false,g)},100)}});$(".toggle-template-permissions").click(function(){var f=$(this).closest("tr").find(".template-permissions");if(f.hasClass("template-permissions-open")){f.fadeOut("fast",function(){f.removeClass("template-permissions-open")})}else{f.fadeIn("fast",function(){f.addClass("template-permissions-open")})}var e=$(this).find("i");e.toggleClass(e.attr("data-toggle"));return false});$(".template-permissions-click").each(function(){$(this).closest("tr").find(".toggle-template-permissions").click();$(this).removeClass("template-permissions-click")});$(".permission-title").click(function(){$(this).closest("tr").find(".toggle-template-permissions").click()});a=$("input.global-permission:eq(0)");b=$("<div />").addClass(a.attr("class")).removeClass("permission permission-checked global-permission");c=$("input.template-permission").addClass(b.attr("class"))});
|
@@ -16,7 +16,7 @@ class ProcessRole extends ProcessPageType {
|
|||||||
static public function getModuleInfo() {
|
static public function getModuleInfo() {
|
||||||
return array(
|
return array(
|
||||||
'title' => __('Roles', __FILE__), // getModuleInfo title
|
'title' => __('Roles', __FILE__), // getModuleInfo title
|
||||||
'version' => 103,
|
'version' => 104,
|
||||||
'summary' => __('Manage user roles and what permissions are attached', __FILE__), // getModuleInfo summary
|
'summary' => __('Manage user roles and what permissions are attached', __FILE__), // getModuleInfo summary
|
||||||
'permanent' => true,
|
'permanent' => true,
|
||||||
'permission' => 'role-admin', // add this permission if you want this Process available for roles other than Superuser
|
'permission' => 'role-admin', // add this permission if you want this Process available for roles other than Superuser
|
||||||
@@ -26,10 +26,28 @@ class ProcessRole extends ProcessPageType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected $icons = array();
|
protected $icons = array();
|
||||||
|
protected $templatePermissionNotes = array();
|
||||||
|
protected $templatePermissionDescriptions = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Role
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected $guestRole;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Init and attach hooks
|
||||||
|
*
|
||||||
|
*/
|
||||||
public function init() {
|
public function init() {
|
||||||
|
|
||||||
parent::init();
|
parent::init();
|
||||||
|
|
||||||
|
$this->wire('modules')->get('JqueryUI')->use('vex');
|
||||||
|
$this->guestRole = $this->wire('roles')->get($this->wire('config')->guestUserRolePageID);
|
||||||
$this->addHookBefore('InputfieldForm::render', $this, 'hookFormRender');
|
$this->addHookBefore('InputfieldForm::render', $this, 'hookFormRender');
|
||||||
|
$this->addHookBefore('ProcessPageEdit::processInput', $this, 'hookProcessInput');
|
||||||
|
|
||||||
$this->icons = array(
|
$this->icons = array(
|
||||||
'edit' => wireIconMarkup('certificate', 'fw'),
|
'edit' => wireIconMarkup('certificate', 'fw'),
|
||||||
'page' => wireIconMarkup('gear', 'fw'),
|
'page' => wireIconMarkup('gear', 'fw'),
|
||||||
@@ -38,55 +56,80 @@ class ProcessRole extends ProcessPageType {
|
|||||||
'revoke' => wireIconMarkup('minus-circle', 'fw'),
|
'revoke' => wireIconMarkup('minus-circle', 'fw'),
|
||||||
'help' => wireIconMarkup('question-circle'),
|
'help' => wireIconMarkup('question-circle'),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$this->templatePermissionDescriptions = array(
|
||||||
|
'page-view' => $this->_('Which types of pages may this role view?'),
|
||||||
|
'page-edit' => $this->_('Which types of pages may this role edit?'),
|
||||||
|
'page-add' => $this->_('Which types of pages may this role add children to?'),
|
||||||
|
'page-create' => $this->_('Which types of pages may this role create?'),
|
||||||
|
'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.'),
|
||||||
|
'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.'),
|
||||||
|
);
|
||||||
|
|
||||||
|
$pageEditRequired = $this->_('Note that role must also have page-edit permission for any checked templates above.');
|
||||||
|
|
||||||
|
$this->templatePermissionNotes = array(
|
||||||
|
'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).'),
|
||||||
|
'page-create' => $pageEditRequired,
|
||||||
|
'page-publish' => $pageEditRequired,
|
||||||
|
'page-add' => $this->_('Unlike most other permissions, page-edit permission to a template is not a pre-requisite for this permission.'),
|
||||||
|
'page-edit' => '',
|
||||||
|
'page-view' => '',
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook ProcessPageEdit::processInput to save permission options
|
||||||
|
*
|
||||||
|
* @param HookEvent $event
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function hookProcessInput(HookEvent $event) {
|
||||||
|
if($event->wire('input')->post('_pw_page_name')) {
|
||||||
|
$this->savePermissionOptions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook before InputfieldForm::render to manipulate output of permissions field
|
||||||
|
*
|
||||||
|
* @param HookEvent $event
|
||||||
|
*
|
||||||
|
*/
|
||||||
public function hookFormRender(HookEvent $event) {
|
public function hookFormRender(HookEvent $event) {
|
||||||
|
|
||||||
|
/** @var Inputfieldform $form */
|
||||||
$form = $event->object;
|
$form = $event->object;
|
||||||
|
/** @var InputfieldPage $f */
|
||||||
$f = $form->getChildByName('permissions');
|
$f = $form->getChildByName('permissions');
|
||||||
if(!$f) return;
|
if(!$f) return;
|
||||||
|
|
||||||
if($this->getPage()->id == $this->wire('config')->superUserRolePageID) {
|
if($this->getPage()->id == $this->wire('config')->superUserRolePageID) {
|
||||||
$f->wrapAttr('style', 'display:none');
|
$f->wrapAttr('style', 'display:none');
|
||||||
$fn = $form->getChildByName('_pw_page_name');
|
$fn = $form->getChildByName('_pw_page_name');
|
||||||
if($fn) $fn->notes = $this->_('Note: superuser role always has all permissions, so permissions field is not shown.');
|
if($fn) $fn->notes = $this->_('Note: superuser role always has all permissions, so permissions field is not shown.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$f->entityEncodeText = false;
|
$f->entityEncodeText = false;
|
||||||
|
$f->addClass('global-permission');
|
||||||
$f->label = $this->_('Permissions');
|
$f->label = $this->_('Permissions');
|
||||||
$f->description = $f->entityEncode(sprintf($this->_('For detailed descriptions of these permissions, please see the [permissions reference](%s).'), 'https://processwire.com/api/user-access/permissions/'), true); // Permissions documentation info
|
$f->description = $f->entityEncode(
|
||||||
$strikethrough = '<s>' . $this->_('strikethrough') . '</s>';
|
sprintf(
|
||||||
$f->appendMarkup =
|
$this->_('For detailed descriptions of these permissions, please see the [permissions reference](%s).'), // Permissions documentation info
|
||||||
"<div class='permissions-footer detail'>" .
|
'https://processwire.com/api/user-access/permissions/'
|
||||||
"<p>" .
|
), true
|
||||||
$this->icons['edit'] .
|
);
|
||||||
$this->_('Checking the page-edit permission here does not grant edit access to any pages on its own. Instead, it enables you to configure edit access for this role in template access settings. The page-edit permission is also what enables users to see Pages in the admin. This permission is recommended for all administrative users.') . // Description of page-edit
|
|
||||||
"</p>" .
|
|
||||||
"<p>" .
|
|
||||||
$this->icons['page'] .
|
|
||||||
$this->_('Indicates permission may be optionally added or revoked from user roles in template access settings. Checking the permission enables it for all editable templates. If you only want a user role to have one of these permissions for pages using specific template(s), you should leave it unchecked here and instead select it in a template "Access" tab.') . // Description of permission that can be assigned by templates
|
|
||||||
"</p>" .
|
|
||||||
"<p>" .
|
|
||||||
$this->icons['info'] .
|
|
||||||
$this->_('The page-add and page-create permissions can only be added from the template access settings and are shown here just for informational purposes.') . // Description of informational permissions
|
|
||||||
"</p>" .
|
|
||||||
"<p>" .
|
|
||||||
$this->icons['add'] .
|
|
||||||
sprintf($this->_('Indicates a template that adds the permission. Click to open a window to the access settings for that template. If the template name has %s it indicates the permission is added at the template, but being overridden by your selection here.'), $strikethrough) . // Description of template added permission
|
|
||||||
"</p>" .
|
|
||||||
"<p>" .
|
|
||||||
$this->icons['revoke'] .
|
|
||||||
$this->_('Same as the above except that the permission is being revoked by that template (rather than added).') . // Description of template revoked permission
|
|
||||||
"</p>" .
|
|
||||||
"</div>";
|
|
||||||
|
|
||||||
$f = $f->getInputfield();
|
$f = $f->getInputfield();
|
||||||
|
/** @var InputfieldCheckboxes $f */
|
||||||
$f->table = true;
|
$f->table = true;
|
||||||
$f->thead = $this->_('name|description'); // Table head with each column title separated by a pipe "|"
|
$f->thead = $this->_('name|description| '); // Table head with each column title separated by a pipe "|"
|
||||||
$value = $f->attr('value');
|
$value = $f->attr('value');
|
||||||
$options = $f->getOptions();
|
$options = $f->getOptions();
|
||||||
$pageViewID = 0;
|
$pageViewID = 0;
|
||||||
|
|
||||||
foreach($options as $name => $label) $f->removeOption($name);
|
foreach($options as $name => $label) $f->removeOption($name);
|
||||||
$permissions = array();
|
|
||||||
|
|
||||||
// establish root permission containers
|
// establish root permission containers
|
||||||
foreach($this->wire('permissions') as $permission) {
|
foreach($this->wire('permissions') as $permission) {
|
||||||
@@ -98,9 +141,15 @@ class ProcessRole extends ProcessPageType {
|
|||||||
$permissions[$permission->name]['page-create'] = array();
|
$permissions[$permission->name]['page-create'] = array();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ksort($permissions);
|
ksort($permissions);
|
||||||
|
$pageView = $permissions['page-view'];
|
||||||
|
$pageEdit = $permissions['page-edit'];
|
||||||
|
$permissions = array_merge(array('page-view' => $pageView, 'page-edit' => $pageEdit), $permissions);
|
||||||
|
|
||||||
foreach($this->wire('permissions') as $permission) {
|
foreach($this->wire('permissions') as $permission) {
|
||||||
|
/** @var Permission $permission */
|
||||||
|
/** @var Permission $parent */
|
||||||
$parent = $permission->getParentPermission();
|
$parent = $permission->getParentPermission();
|
||||||
if(!$parent->id) continue;
|
if(!$parent->id) continue;
|
||||||
if(isset($permissions[$parent->name])) {
|
if(isset($permissions[$parent->name])) {
|
||||||
@@ -126,8 +175,19 @@ class ProcessRole extends ProcessPageType {
|
|||||||
$f->attr('value', $value);
|
$f->attr('value', $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add permission options to checkboxes Inputfield
|
||||||
|
*
|
||||||
|
* @param array $permissions
|
||||||
|
* @param Inputfield $f
|
||||||
|
* @param int $level
|
||||||
|
* @param $inputfieldValue
|
||||||
|
*
|
||||||
|
*/
|
||||||
protected function addPermissionOptions(array $permissions, Inputfield $f, $level = 0, &$inputfieldValue) {
|
protected function addPermissionOptions(array $permissions, Inputfield $f, $level = 0, &$inputfieldValue) {
|
||||||
|
|
||||||
|
/** @var InputfieldCheckboxes $f */
|
||||||
|
/** @var Role $role */
|
||||||
$role = $this->getPage();
|
$role = $this->getPage();
|
||||||
|
|
||||||
foreach($permissions as $name => $children) {
|
foreach($permissions as $name => $children) {
|
||||||
@@ -138,14 +198,21 @@ class ProcessRole extends ProcessPageType {
|
|||||||
$revokedTemplates = array();
|
$revokedTemplates = array();
|
||||||
$disabled = false;
|
$disabled = false;
|
||||||
$checked = false;
|
$checked = false;
|
||||||
|
$appliesAllEditable = false;
|
||||||
|
$templateCheckboxes = array();
|
||||||
|
$pageEditTemplates = array();
|
||||||
|
|
||||||
if($name == 'page-add' || $name == 'page-create') {
|
if($name == 'page-add' || $name == 'page-create') {
|
||||||
$parent = $this->wire('permissions')->get('page-edit');
|
$parent = $this->wire('permissions')->get('page-edit');
|
||||||
$rootParent = $parent;
|
$rootParent = $parent;
|
||||||
$permission = $this->wire('pages')->newNullPage();
|
$permission = new Permission();
|
||||||
if($name == 'page-add') $title = $this->_('Add children to pages using template');
|
$permission->set('name', $name);
|
||||||
else $title = $this->_('Create pages using template');
|
if($name == 'page-add') {
|
||||||
$alert = $this->_('This permission can only be assigned by template access settings.');
|
$title = $this->_('Add children to pages using template');
|
||||||
|
} else {
|
||||||
|
$title = $this->_('Create pages using template');
|
||||||
|
}
|
||||||
|
$alert = $this->_('This permission can only be assigned by template.');
|
||||||
} else {
|
} else {
|
||||||
$permission = $this->wire('permissions')->get($name);
|
$permission = $this->wire('permissions')->get($name);
|
||||||
if(!$permission->id) continue;
|
if(!$permission->id) continue;
|
||||||
@@ -155,31 +222,39 @@ class ProcessRole extends ProcessPageType {
|
|||||||
$checked = in_array($permission->id, $inputfieldValue);
|
$checked = in_array($permission->id, $inputfieldValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$title = "<span class='permission-title'>$title</span>";
|
||||||
|
|
||||||
if($name == 'page-view') {
|
if($name == 'page-view') {
|
||||||
$title .= " <span class='detail'>" . $this->_('(required)') . "</span>";
|
$title .= $this->renderDetail($this->_('(required)'));
|
||||||
$alert = $this->_('This permission is required for all roles.');
|
$alert = $this->_('This permission is required for all roles.');
|
||||||
} else if($name == 'page-edit') {
|
} else if($name == 'page-edit') {
|
||||||
$title = $this->icons['edit'] . $title;
|
|
||||||
}
|
}
|
||||||
if(($parent->name == 'page-edit' || $rootParent->name == 'page-edit') && strpos($name, 'page-') === 0) {
|
if(($parent->name == 'page-edit' || $rootParent->name == 'page-edit') && strpos($name, 'page-') === 0) {
|
||||||
if($name == 'page-add' || $name == 'page-create') {
|
if($name == 'page-add' || $name == 'page-create') {
|
||||||
$title = $this->icons['info'] . $title;
|
$title = $title;
|
||||||
} else {
|
} else {
|
||||||
$title = $this->icons['page'] . $title . ' ' .
|
$appliesAllEditable = true;
|
||||||
"<span class='detail permission-all-templates'>(" . $this->_('applies to all editable templates') . ')</span>';
|
$title .= $this->renderDetail('(' . $this->_('applies to all editable templates') . ')', 'permission-all-templates');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($this->wire('templates') as $template) {
|
foreach($this->wire('templates') as $template) {
|
||||||
|
/** @var Template $template */
|
||||||
|
|
||||||
if(!$template->useRoles) continue;
|
if(!$template->useRoles) continue;
|
||||||
|
$rolesPermissions = $template->rolesPermissions;
|
||||||
|
|
||||||
$templateEditURL = "../../../setup/template/edit?id=$template->id#tab_access";
|
$templateEditURL = "../../../setup/template/edit?id=$template->id#tab_access";
|
||||||
$templateEditLink =
|
$templateEditLink = $this->renderLink($templateEditURL, $this->icons['add'] . $template->name, array(
|
||||||
"<a class='tooltip' title='{tooltip}' target='_blank' href='$templateEditURL'>" .
|
'class' => 'tooltip',
|
||||||
$this->icons['add'] . "$template->name</a>";
|
'target' => '_blank',
|
||||||
|
'title' => '{tooltip}',
|
||||||
|
));
|
||||||
|
|
||||||
if($name == 'page-edit') {
|
if($name == 'page-edit') {
|
||||||
if(in_array($role->id, $template->editRoles)) {
|
if(in_array($role->id, $template->editRoles)) {
|
||||||
$addedTemplates[$template->name] = $templateEditLink;
|
$addedTemplates[$template->name] = $templateEditLink;
|
||||||
|
$pageEditTemplates[$template->name] = $template;
|
||||||
}
|
}
|
||||||
} else if($name == 'page-create') {
|
} else if($name == 'page-create') {
|
||||||
if(in_array($role->id, $template->createRoles)) {
|
if(in_array($role->id, $template->createRoles)) {
|
||||||
@@ -191,27 +266,38 @@ class ProcessRole extends ProcessPageType {
|
|||||||
$checked = true;
|
$checked = true;
|
||||||
$addedTemplates[$template->name] = $templateEditLink;
|
$addedTemplates[$template->name] = $templateEditLink;
|
||||||
}
|
}
|
||||||
} else {
|
} else if(isset($rolesPermissions[$role->id])) {
|
||||||
$rolesPermissions = $template->rolesPermissions;
|
// custom added or revoked permission
|
||||||
if(!isset($rolesPermissions[$role->id])) continue;
|
|
||||||
if(in_array($permission->id, $rolesPermissions[$role->id])) {
|
if(in_array($permission->id, $rolesPermissions[$role->id])) {
|
||||||
$addedTemplates[$template->name] = $templateEditLink;
|
$addedTemplates[$template->name] = $templateEditLink;
|
||||||
} else if(in_array($permission->id * -1, $rolesPermissions[$role->id])) {
|
} else if(in_array($permission->id * -1, $rolesPermissions[$role->id])) {
|
||||||
$revokedTemplates[$template->name] = str_replace($this->icons['add'], $this->icons['revoke'], $templateEditLink);
|
$revokedTemplates[$template->name] = str_replace($this->icons['add'], $this->icons['revoke'], $templateEditLink);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if a system template, then do nothing further
|
||||||
|
if($template->flags & Template::flagSystem) continue;
|
||||||
|
|
||||||
|
if(isset($this->templatePermissionDescriptions[$name]) || $appliesAllEditable) {
|
||||||
|
// base permission: page-view, page-edit, page-create, page-add
|
||||||
|
$checked = isset($addedTemplates[$template->name]);
|
||||||
|
$templateCheckboxes[] = $this->renderTemplatePermissionCheckbox($template, $permission, $checked);
|
||||||
}
|
}
|
||||||
|
} // foreach(templates)
|
||||||
|
|
||||||
if(count($addedTemplates) || count($revokedTemplates)) {
|
if(count($addedTemplates) || count($revokedTemplates)) {
|
||||||
|
// permission was added or revoked from specific templates
|
||||||
|
|
||||||
|
/*
|
||||||
foreach($addedTemplates as $templateName => $link) {
|
foreach($addedTemplates as $templateName => $link) {
|
||||||
$tooltip = sprintf($this->_('%1$s added by template %2$s, click to edit'), $name, $templateName);
|
$tooltip = sprintf($this->_('%1$s added by template %2$s, click to edit'), $name, $templateName);
|
||||||
$addedTemplates[$templateName] = str_replace('{tooltip}', $tooltip, $link);
|
$addedTemplates[$templateName] = str_replace('{tooltip}', $tooltip, $link);
|
||||||
}
|
}
|
||||||
foreach($revokedTemplates as $templateName => $link) {
|
foreach($revokedTemplates as $templateName => $link) {
|
||||||
$tooltip = sprintf($this->_('%1$s revoked by template %2$s, click to edit'), $name, $templateName);
|
$tooltip = sprintf($this->_('%1$s revoked by template %2$s, click to edit'), $name, $templateName);
|
||||||
$addedTemplates[$templateName] = str_replace('{tooltip}', $tooltip, $link);
|
$revokedTemplates[$templateName] = str_replace('{tooltip}', $tooltip, $link);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
if($name != 'page-edit' && $permission->id) {
|
if($name != 'page-edit' && $permission->id) {
|
||||||
if(!in_array($permission->id, $inputfieldValue)) {
|
if(!in_array($permission->id, $inputfieldValue)) {
|
||||||
@@ -219,62 +305,394 @@ class ProcessRole extends ProcessPageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
if(count($addedTemplates)) {
|
if(count($addedTemplates)) {
|
||||||
$label = implode(' ', $addedTemplates);
|
$label = implode(' ', $addedTemplates);
|
||||||
$title .= " <span class='detail permission-added'>$label</span> ";
|
$title .= $this->renderDetail($label, 'permission-added');
|
||||||
}
|
}
|
||||||
|
|
||||||
if(count($revokedTemplates)) {
|
if(count($revokedTemplates)) {
|
||||||
$label = implode(' ', $revokedTemplates);
|
$label = implode(' ', $revokedTemplates);
|
||||||
$title .= " <span class='detail permission-revoked'>$label</span>";
|
$title .= $this->renderDetail($label, 'permission-revoked');
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if($name == 'page-edit') {
|
$classes = array(
|
||||||
$title .= " <span class='detail permission-added'>(" . $this->_('not currently applied to any templates') . ")</span>";
|
"permission",
|
||||||
}
|
"permission-$name",
|
||||||
|
"level$level",
|
||||||
|
);
|
||||||
|
|
||||||
$class = "permission level$level";
|
|
||||||
$p = $parent;
|
$p = $parent;
|
||||||
|
|
||||||
while($p->id) {
|
while($p->id) {
|
||||||
$class .= " parent-permission$p->id";
|
$classes[] = "parent-permission$p->id";
|
||||||
$p = $p->getParentPermission($p);
|
$classes[] = "parent-permission-$p->name";
|
||||||
|
$p = $p->getParentPermission();
|
||||||
}
|
}
|
||||||
|
|
||||||
if($permission->id) {
|
if($permission->id) {
|
||||||
$value = $permission->id;
|
$value = $permission->id;
|
||||||
$id = "permission$permission->id";
|
$id = "permission$permission->id";
|
||||||
|
if($appliesAllEditable) $classes[] = "page-edit-templates";
|
||||||
} else {
|
} else {
|
||||||
$value = "0-$name";
|
$value = "0-$name";
|
||||||
$id = "permission0-$name";
|
$id = "permission0-$name";
|
||||||
$disabled = true;
|
$disabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($disabled) $classes[] = 'checkbox-disabled';
|
||||||
|
|
||||||
$attributes = array(
|
$attributes = array(
|
||||||
"id" => $id,
|
"id" => $id,
|
||||||
"class" => $class,
|
"class" => implode(' ', $classes),
|
||||||
"data-parent" => "permission$parent->id",
|
"data-parent" => "permission$parent->id",
|
||||||
"data-level" => $level
|
"data-level" => $level
|
||||||
);
|
);
|
||||||
|
|
||||||
if(!$permission->id && $checked) $inputfieldValue[] = $value;
|
if($disabled) $attributes['disabled'] = 'disabled';
|
||||||
if($disabled) {
|
|
||||||
$attributes['disabled'] = 'disabled';
|
|
||||||
$attributes['class'] .= ' checkbox-disabled';
|
|
||||||
}
|
|
||||||
if($alert) $attributes['data-alert'] = $alert;
|
if($alert) $attributes['data-alert'] = $alert;
|
||||||
if($confirm) $attributes['data-confirm'] = $confirm;
|
if($confirm) $attributes['data-confirm'] = $confirm;
|
||||||
|
|
||||||
|
if(!$permission->id && $checked) $inputfieldValue[] = $value;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
$title =
|
$title =
|
||||||
"<a class='permission-help' target='_blank' href='https://processwire.com/api/user-access/permissions/#$name'>" .
|
"<a class='permission-help' target='_blank' href='https://processwire.com/api/user-access/permissions/#$name'>" .
|
||||||
$this->icons['help'] . "</a>" . $title;
|
$this->icons['help'] . "</a>" . $title;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$f->addOption($value, "$name|$title", $attributes);
|
if(count($templateCheckboxes)) {
|
||||||
|
$checkboxes = $this->renderTemplatePermissionCheckboxes($permission, $templateCheckboxes);
|
||||||
|
$toggle = $this->renderTemplatePermissionToggle();
|
||||||
|
$f->addOption($value, "$name|$title$checkboxes|$toggle", $attributes);
|
||||||
|
} else {
|
||||||
|
$f->addOption($value, "$name|$title| ", $attributes);
|
||||||
|
}
|
||||||
|
|
||||||
if(count($children)) {
|
if(count($children)) {
|
||||||
$this->addPermissionOptions($children, $f, $level+1, $inputfieldValue);
|
$this->addPermissionOptions($children, $f, $level+1, $inputfieldValue);
|
||||||
}
|
}
|
||||||
|
} // foreach(permissions)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render a div containing template permission checkboxes
|
||||||
|
*
|
||||||
|
* @param Permission $permission
|
||||||
|
* @param array $checkboxes Array of individually rendered checkboxes for each template
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function renderTemplatePermissionCheckboxes(Permission $permission, array $checkboxes) {
|
||||||
|
|
||||||
|
$name = $permission->name;
|
||||||
|
if(isset($this->templatePermissionNotes[$name])) {
|
||||||
|
$note = $this->templatePermissionNotes[$name];
|
||||||
|
} else {
|
||||||
|
$note = $this->templatePermissionNotes['default'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($this->templatePermissionDescriptions[$name])) {
|
||||||
|
$desc =
|
||||||
|
"<p class='description'>" . $this->templatePermissionDescriptions[$name] . "</p>";
|
||||||
|
} else {
|
||||||
|
$desc =
|
||||||
|
"<p class='description description-not-checked'>" .
|
||||||
|
str_replace('{permission}', $name, $this->templatePermissionDescriptions['default-add']) .
|
||||||
|
"</p>" .
|
||||||
|
"<p class='description description-checked'>" .
|
||||||
|
str_replace('{permission}', $name, $this->templatePermissionDescriptions['default-revoke']) .
|
||||||
|
"</p>";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$class = 'template-permissions';
|
||||||
|
$checkboxes = implode('', $checkboxes);
|
||||||
|
|
||||||
|
if(strpos($checkboxes, ' checked ') || in_array($name, array('page-edit', 'page-view', 'page-add', 'page-create'))) {
|
||||||
|
$class .= ' template-permissions-click';
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
"<div class='$class'>" .
|
||||||
|
$desc .
|
||||||
|
"<p class='template-checkboxes'>$checkboxes</p>" .
|
||||||
|
($note ? "<p class='detail'>$note</p>" : "") .
|
||||||
|
"</div>";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render a single template permission checkbox
|
||||||
|
*
|
||||||
|
* @param Template $template
|
||||||
|
* @param Permission $permission
|
||||||
|
* @param bool $checked
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function renderTemplatePermissionCheckbox(Template $template, Permission $permission, $checked) {
|
||||||
|
|
||||||
|
$disabled = false;
|
||||||
|
$note = '';
|
||||||
|
|
||||||
|
if($permission->name == 'page-view' && $this->guestRole->hasPermission('page-view', $template)) {
|
||||||
|
$checked = true;
|
||||||
|
$disabled = true;
|
||||||
|
$note = $this->_('(inherited from guest role)');
|
||||||
|
}
|
||||||
|
|
||||||
|
$checked = $checked ? 'checked' : '';
|
||||||
|
$disabled = $disabled ? 'disabled' : '';
|
||||||
|
$class = "template-permission template{$template->id}-permission$permission->id";
|
||||||
|
|
||||||
|
// note: pt=permission+template, tp=template+permission
|
||||||
|
|
||||||
|
if($permission->name == 'page-add') {
|
||||||
|
$name = "pt_add_$template->id";
|
||||||
|
} else if($permission->name == 'page-create') {
|
||||||
|
$name = "pt_create_$template->id";
|
||||||
|
} else if(in_array($permission->name, array('page-edit', 'page-view'))) {
|
||||||
|
$name = "pt_{$permission->id}_{$template->id}";
|
||||||
|
} else {
|
||||||
|
$name = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if($name) {
|
||||||
|
// checkbox
|
||||||
|
$out =
|
||||||
|
"<label>" .
|
||||||
|
"<input type='checkbox' $checked $disabled name='$name' value='1' class='$class'>" .
|
||||||
|
"$template->name <span class='detail'>$note</span>" .
|
||||||
|
"</label>";
|
||||||
|
} else {
|
||||||
|
// select add or revoke
|
||||||
|
/** @var Role $role */
|
||||||
|
$role = $this->getPage();
|
||||||
|
$name = "tp_{$template->id}[]";
|
||||||
|
$rolesPermissions = $template->rolesPermissions;
|
||||||
|
$rolePermissions = isset($rolesPermissions["$role->id"]) ? $rolesPermissions["$role->id"] : array();
|
||||||
|
$addChecked = in_array("$permission->id", $rolePermissions) ? 'checked' : '';
|
||||||
|
$revokeChecked = in_array("-$permission->id", $rolePermissions) ? 'checked' : '';
|
||||||
|
$out =
|
||||||
|
"<label class='template-permission-add'>" .
|
||||||
|
"<input type='checkbox' name='add_$name' value='$permission->id' $addChecked class='$class'>" .
|
||||||
|
sprintf($this->_('Add to: %s'), $template->name) .
|
||||||
|
"</label>" .
|
||||||
|
"<label class='template-permission-revoke'>" .
|
||||||
|
"<input type='checkbox' name='revoke_$name' value='$permission->id' $revokeChecked class='$class'>" .
|
||||||
|
sprintf($this->_('Revoke from: %s'), $template->name) .
|
||||||
|
"</label>";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the toggle that can trigger the template permission checkboxes
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function renderTemplatePermissionToggle() {
|
||||||
|
return
|
||||||
|
"<a href='#' class='toggle-template-permissions tooltip' title='" . $this->_('Click to open/close permission settings by template') . "'>" .
|
||||||
|
"<i class='fa fa-chevron-circle-right' data-toggle='fa-chevron-circle-down fa-chevron-circle-right'></i>" .
|
||||||
|
"</a>";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render an <a> link
|
||||||
|
*
|
||||||
|
* @param string $href
|
||||||
|
* @param string $text
|
||||||
|
* @param array $attr
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function renderLink($href, $text, array $attr = array()) {
|
||||||
|
$attr['href'] = $href;
|
||||||
|
$out = "<a ";
|
||||||
|
foreach($attr as $key => $value) {
|
||||||
|
$out .= " $key='" . $this->wire('sanitizer')->entities($value) . "'";
|
||||||
|
}
|
||||||
|
$out .= ">$text</a>";
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render a detail
|
||||||
|
*
|
||||||
|
* @param string $text Markup to render in the detail
|
||||||
|
* @param string $class May be omitted if not needed
|
||||||
|
* @param string $tag Default is span
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function renderDetail($text, $class = '', $tag = 'span') {
|
||||||
|
$class = $class ? "detail $class" : "detail";
|
||||||
|
return ' ' . $this->renderText($text, $class, $tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render paragraph of text (or other tag as specified)
|
||||||
|
*
|
||||||
|
* @param string $text
|
||||||
|
* @param string $class Default is blank
|
||||||
|
* @param string $tag Default is p
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function renderText($text, $class = '', $tag = 'p') {
|
||||||
|
$class = $class ? " class='$class'" : "";
|
||||||
|
return "<$tag$class>$text</$tag>";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save posted permission options to templates
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function savePermissionOptions() {
|
||||||
|
|
||||||
|
$role = $this->getPage();
|
||||||
|
if(!$role->id) return;
|
||||||
|
$isGuestRole = $role->id == $this->guestRole->id;
|
||||||
|
|
||||||
|
/** @var WireInput $input */
|
||||||
|
$input = $this->wire('input');
|
||||||
|
|
||||||
|
$viewPermission = $this->wire('permissions')->get('page-view');
|
||||||
|
$editPermission = $this->wire('permissions')->get('page-edit');
|
||||||
|
|
||||||
|
foreach($this->wire('templates') as $template) {
|
||||||
|
|
||||||
|
/** @var Template $template */
|
||||||
|
if(!$template->useRoles) continue;
|
||||||
|
|
||||||
|
$updates = array();
|
||||||
|
$createRoles = $template->createRoles;
|
||||||
|
$addRoles = $template->addRoles;
|
||||||
|
$editRoles = $template->editRoles;
|
||||||
|
$guestHasView = $this->guestRole->hasPermission($viewPermission, $template);
|
||||||
|
$rolesPermissions = $template->rolesPermissions;
|
||||||
|
$rolePermissions = isset($rolesPermissions["$role->id"]) ? $rolesPermissions["$role->id"] : array();
|
||||||
|
|
||||||
|
$view = $input->post("pt_{$viewPermission->id}_{$template->id}");
|
||||||
|
$edit = $input->post("pt_{$editPermission->id}_{$template->id}");
|
||||||
|
$add = $input->post("pt_add_{$template->id}");
|
||||||
|
$create = $input->post("pt_create_{$template->id}");
|
||||||
|
|
||||||
|
// page-view
|
||||||
|
if($view) {
|
||||||
|
if(!$template->roles->has($role)) {
|
||||||
|
$template->roles->add($role);
|
||||||
|
$updates[] = "Added page-view to template $template->name";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if($template->roles->has($role)) {
|
||||||
|
if($isGuestRole || !$guestHasView) {
|
||||||
|
$template->roles->remove($role);
|
||||||
|
$updates[] = "Removed page-view from template $template->name";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$isGuestRole) {
|
||||||
|
|
||||||
|
// page-edit
|
||||||
|
if($edit) {
|
||||||
|
if(!in_array($role->id, $editRoles)) {
|
||||||
|
$editRoles[] = $role->id;
|
||||||
|
$updates[] = "Added page-edit to template $template->name";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$key = array_search($role->id, $editRoles);
|
||||||
|
if($key !== false) {
|
||||||
|
unset($editRoles[$key]);
|
||||||
|
$updates[] = "Removed page-edit from template $template->name";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// page-add
|
||||||
|
if($add) {
|
||||||
|
if(!in_array($role->id, $addRoles)) {
|
||||||
|
$addRoles[] = $role->id;
|
||||||
|
$updates[] = "Added page-add to template $template->name";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$key = array_search($role->id, $addRoles);
|
||||||
|
if($key !== false) {
|
||||||
|
unset($addRoles[$key]);
|
||||||
|
$updates[] = "Removed page-add from template $template->name";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// page-create
|
||||||
|
if($create) {
|
||||||
|
if(!in_array($role->id, $createRoles)) {
|
||||||
|
$createRoles[] = $role->id;
|
||||||
|
$updates[] = "Added page-create to template $template->name";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$key = array_search($role->id, $createRoles);
|
||||||
|
if($key !== false) {
|
||||||
|
unset($createRoles[$key]);
|
||||||
|
$updates[] = "Removed page-create from template $template->name";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // if(!isGuestRole)
|
||||||
|
|
||||||
|
// rolesPermissions
|
||||||
|
$adds = $input->post->intArray("add_tp_$template->id");
|
||||||
|
$revokes = $input->post->intArray("revoke_tp_$template->id");
|
||||||
|
|
||||||
|
foreach($adds as $key => $permissionID) {
|
||||||
|
// force as strings
|
||||||
|
$adds[$key] = "$permissionID";
|
||||||
|
}
|
||||||
|
foreach($revokes as $key => $permissionID) {
|
||||||
|
// force as negative integer strings
|
||||||
|
$revokes[$key] = (string) (-1 * $permissionID);
|
||||||
|
}
|
||||||
|
$rolePermissionsNew = array_merge($adds, $revokes);
|
||||||
|
sort($rolePermissionsNew);
|
||||||
|
sort($rolePermissions);
|
||||||
|
if($rolePermissionsNew != $rolePermissions) {
|
||||||
|
if($this->wire('config')->debug) {
|
||||||
|
$removedPermissions = array_diff($rolePermissions, $rolePermissionsNew);
|
||||||
|
$addedPermissions = array_diff($rolePermissionsNew, $rolePermissions);
|
||||||
|
foreach($removedPermissions as $permissionID) {
|
||||||
|
$permissionID = (int) $permissionID;
|
||||||
|
$permission = $this->wire('permissions')->get(abs($permissionID));
|
||||||
|
$updates[] = ($permissionID < 0 ? "Removed revoke" : "Removed add") . " " .
|
||||||
|
"$permission->name for template $template->name" ;
|
||||||
|
}
|
||||||
|
foreach($addedPermissions as $permissionID) {
|
||||||
|
$permissionID = (int) $permissionID;
|
||||||
|
$permission = $this->wire('permissions')->get(abs($permissionID));
|
||||||
|
$updates[] = ($permissionID < 0 ? "Added revoke" : "Added add") . " " .
|
||||||
|
"$permission->name for template $template->name" ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$updates[] = "Updated rolesPermissions for template $template->name";
|
||||||
|
$rolesPermissions["$role->id"] = $rolePermissionsNew;
|
||||||
|
$template->rolesPermissions = $rolesPermissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
// save changes
|
||||||
|
if(count($updates)) {
|
||||||
|
|
||||||
|
if($editRoles != $template->editRoles) $template->editRoles = $editRoles;
|
||||||
|
if($addRoles != $template->addRoles) $template->addRoles = $addRoles;
|
||||||
|
if($createRoles != $template->createRoles) $template->createRoles = $createRoles;
|
||||||
|
|
||||||
|
if($this->wire('config')->debug) {
|
||||||
|
foreach($updates as $update) $this->message($update);
|
||||||
|
}
|
||||||
|
|
||||||
|
$template->save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -608,6 +608,10 @@ class ProcessTemplate extends Process {
|
|||||||
*/
|
*/
|
||||||
public function ___executeEdit() {
|
public function ___executeEdit() {
|
||||||
|
|
||||||
|
if(substr($this->wire('input')->url(), -1) === '/') {
|
||||||
|
// we require non-trailing slash for edit requests
|
||||||
|
$this->wire('session')->redirect("../edit?id={$this->template->id}");
|
||||||
|
}
|
||||||
$this->wire('breadcrumbs')->add(new Breadcrumb('./', $this->moduleInfo['title']));
|
$this->wire('breadcrumbs')->add(new Breadcrumb('./', $this->moduleInfo['title']));
|
||||||
$min = $this->wire('config')->debug ? '' : '.min';
|
$min = $this->wire('config')->debug ? '' : '.min';
|
||||||
$this->wire('config')->scripts->add($this->wire('config')->urls->ProcessTemplate . "ProcessTemplateFieldCreator$min.js?v=1");
|
$this->wire('config')->scripts->add($this->wire('config')->urls->ProcessTemplate . "ProcessTemplateFieldCreator$min.js?v=1");
|
||||||
|
Reference in New Issue
Block a user