-
Notifications
You must be signed in to change notification settings - Fork 2
/
CustomPageRoles.module
248 lines (204 loc) · 7.7 KB
/
CustomPageRoles.module
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
<?php
class CustomPageRoles extends WireData implements Module {
public static function getModuleInfo() {
return array(
'title' => 'Custom Page Roles',
'summary' => 'Control viewable and editable roles at the page level.',
'version' => 002,
'permanent' => false,
'autoload' => true,
'singular' => true,
);
}
public function init() {
$this->addHookAfter("Page::viewable", $this, 'viewable');
$this->addHookAfter("Page::editable", $this, 'editable');
$this->addHookAfter("Page::addable", $this, 'addable');
//$this->addHookAfter("Pages::find", $this, 'hookPagesFind');
$this->addHookAfter("ProcessPageEdit::buildForm", $this, 'hookBuildForm');
}
/**
* We hide the edit_roles and view_roles from others than superusers and users with page-roles -permission
*
*/
public function hookBuildForm(HookEvent $event) {
$user = wire('user');
if($user->hasPermission('page-roles')) return;
if($user->isSuperuser()) return;
$form = $event->return;
$field = $form->get('view_roles');
if($field) $field->collapsed = Inputfield::collapsedHidden;
$field = $form->get('edit_roles');
if($field) $field->collapsed = Inputfield::collapsedHidden;
$event->return = $form;
}
/**
* This filters find results to take page based permissions in account. Not in use currently
*
*/
public function hookPagesFind(HookEvent $event) {
$items = $event->return;
foreach($items as $item) {
if($item->template->flags & Template::flagSystem) {
// don't allow this access control on system templates
} else if (!$item->viewable()) {
$items->remove($item);
}
}
$event->return = $items;
}
/**
* Hook called after Page::viewable is called
*
*/
public function viewable(HookEvent $event) {
// get the vars we need to check access
$page = $event->object;
$user = $this->user;
// no need to check anything if it's the superuser
if($user->isSuperuser()) return;
// don't allow this access control on system templates
if($page->template->flags & Template::flagSystem) return;
if ($page->is(Page::statusUnpublished)) return;
// get the roles we'll be comparing
$pageRoles = $page->view_roles;
$userRoles = $this->user->roles;
// If there ain't no view_roles, then fallback to template permissions
if (!$pageRoles) return;
// if page has a 'view_roles' field, but none defined, then inherit 'viewable' state from parent
if(!count($pageRoles)) {
// determine access from page's parent, recursively
// We check if there is at least one parent with edit_roles
foreach($page->parents() as $p) {
if (count($p->view_roles)) {
$event->return = $p->viewable();
return;
}
}
// If not view_roles found from parents, then fallback to template access
return;
}
// we assume it's not viewable until we can prove otherwise
$viewable = false;
// loop through the pageRoles and try to match up to user
// we don't need to check permissions in the role because
// all roles are assumed to have page-view permission.
foreach($pageRoles as $role) {
if($role->name == 'guest' || $user->hasRole($role)) {
// guest role was found or the user has the required role
$viewable = true;
}
}
$event->return = $viewable;
}
public function editable(HookEvent $event) {
// get the vars we need to check access
$page = $event->object;
$user = $this->user;
// no need to check anything if it's the superuser
if($user->isSuperuser()) return;
// don't allow page based access control on system templates
if($page->template->flags & Template::flagSystem) return;
// get the roles we'll be comparing
$pageRoles = $page->edit_roles;
$userRoles = $this->user->roles;
// if page has a 'edit_roles' field, but none defined, then inherit 'editable' state from parent(s)
if(!count($pageRoles)) {
// We check if there is at least one parent with edit_roles
foreach($page->parents() as $p) {
if (count($p->edit_roles)) {
$event->return = $p->editable();
return;
}
}
// If not edit_roles found from parents, then fallback to template access
return;
}
// we assume it's not editable until we can prove otherwise
$editable = false;
// loop through the pageRoles and try to match up to user
// we don't need to check permissions in the role because
// all roles are assumed to have page-view / page-edit permission. => actually we should disallow selecting other than roles which have page-edit in first place
foreach($pageRoles as $role) {
if ($user->hasRole($role)) {
$editable = true;
break;
}
}
// This would be a setting, a "master role" for client
if ($user->hasPermission("page-roles")) $editable = true;
$event->return = $editable;
}
/**
* Add children permission is granted together with edit, at least for now
*
*/
public function addable(HookEvent $event) {
$page = $event->object;
// If page is editable and generally can have children, then allow addable
if ($page->editable() && !$page->template->noChildren) {
$event->return = true;
} else {
$event->return = false;
}
}
/**
* Install the module
*
*/
public function ___install() {
if($this->fields->get('view_roles')) {
$this->error("You already have a 'view_roles' field.");
return;
}
if($this->fields->get('edit_roles')) {
$this->error("You already have a 'edit_roles' field.");
return;
}
$field = new Field();
$field->type = $this->modules->get("FieldtypePage");
$field->name = 'view_roles';
$field->label = 'Roles that can view this page';
$field->description =
"Check the roles that may view this page. At least one role must be checked (like one of your roles or superuser), " .
"otherwise this page does not define access. When access is not defined here, it is inherited from the template " .
"or parent(s). If this page's template allows 'view' access to the user, then it will check the parent(s). " .
"Access will inherit from parents that also have a custom page roles field. ";
$field->derefAsPage = 0;
$field->parent_id = $this->config->rolesPageID;
$field->labelFieldName = 'name';
$field->inputfield = 'InputfieldCheckboxes';
$field->save();
$this->message("Added fields 'view_roles'. Add this field to any templates where you want to control view access.");
$field = new Field();
$field->type = $this->modules->get("FieldtypePage");
$field->name = 'edit_roles';
$field->label = 'Roles that can edit this page';
$field->description =
"Check the roles that may edit this page. At least one role must be checked (like one of your roles or superuser), " .
"otherwise this page does not define access. When access is not defined here, it is inherited from the template " .
"or parent(s). If this page's template allows 'view' access to the user, then it will check the parent(s). " .
"Access will inherit from parents that also have a custom page roles field. ";
$field->derefAsPage = 0;
$field->parent_id = $this->config->rolesPageID;
$field->labelFieldName = 'name';
$field->inputfield = 'InputfieldCheckboxes';
$field->findPagesCode = '
$editRoles = $page->getAccessTemplate()->editRoles;
$editRolePages = new PageArray;
foreach($editRoles as $roleId) {
$editRolePages->add($pages->get($roleId));
}
return $editRolePages;
';
$field->save();
$this->message("Added fields 'edit_roles'. Add this field to any templates where you want to control edit access.");
}
/**
* Uninstall the module
*
*/
public function ___uninstall() {
$this->message("To complete uninstall, remove the 'view_roles' and 'edit_roles' field from all templates and then delete the fields.");
}
}