1 <?php
2 3 4 5 6 7
8 class Group extends DataObject {
9
10 static $db = array(
11 "Title" => "Varchar",
12 "Description" => "Text",
13 "Code" => "Varchar",
14 "Locked" => "Boolean",
15 "Sort" => "Int",
16 "IPRestrictions" => "Text",
17 "HtmlEditorConfig" => "Varchar"
18 );
19
20 static $has_one = array(
21 "Parent" => "Group",
22 );
23
24 static $has_many = array(
25 "Permissions" => "Permission",
26 "Groups" => "Group"
27 );
28
29 static $many_many = array(
30 "Members" => "Member",
31 "Roles" => "PermissionRole",
32 );
33
34 static $extensions = array(
35 "Hierarchy",
36 );
37
38 function getAllChildren() {
39 $doSet = new DataObjectSet();
40
41 if ($children = DataObject::get('Group', '"ParentID" = '.$this->ID)) {
42 foreach($children as $child) {
43 $doSet->push($child);
44 $doSet->merge($child->getAllChildren());
45 }
46 }
47
48 return $doSet;
49 }
50
51 52 53 54 55
56 public function getCMSFields() {
57 $fields = new FieldSet(
58 new TabSet("Root",
59 new Tab('Members',_t('SecurityAdmin.MEMBERS','Members'),
60 new TextField("Title", $this->fieldLabel('Title')),
61 $memberList = new MemberTableField(
62 $this,
63 "Members",
64 $this
65 )
66 ),
67
68 $permissionsTab = new Tab('Permissions', _t('SecurityAdmin.PERMISSIONS', 'Permissions'),
69 new PermissionCheckboxSetField(
70 'Permissions',
71 false,
72 'Permission',
73 'GroupID',
74 $this
75 )
76 ),
77
78 new Tab('IP Addresses',_t('Security.IPADDRESSES', 'IP Addresses'),
79 new LiteralField("", _t('SecurityAdmin.IPADDRESSESHELP',"<p>You can restrict this group to a particular
80 IP address range (one range per line). <br />Ranges can be in any of the following forms: <br />
81 203.96.152.12<br />
82 203.96.152/24<br />
83 203.96/16<br />
84 203/8<br /><br />If you enter one or more IP address ranges in this box, then members will only get
85 the rights of being in this group if they log on from one of the valid IP addresses. It won't prevent
86 people from logging in. This is because the same user might have to log in to access parts of the
87 system without IP address restrictions.")),
88 new TextareaField("IPRestrictions", _t('Security.IP_RANGES', "IP Ranges"), 10)
89 )
90 )
91 );
92
93
94
95 $editorConfigMap = HtmlEditorConfig::get_available_configs_map();
96 if(count($editorConfigMap) > 1) {
97 $fields->addFieldToTab('Root.Permissions',
98 new DropdownField(
99 'HtmlEditorConfig',
100 'HTML Editor Configuration',
101 $editorConfigMap
102 ),
103 'Permissions'
104 );
105 }
106
107 if(!Permission::check('EDIT_PERMISSIONS')) {
108 $fields->removeFieldFromTab('Root', 'Permissions');
109 $fields->removeFieldFromTab('Root', 'IP Addresses');
110 }
111
112
113
114 if(Permission::check('APPLY_ROLES') && DataObject::get('PermissionRole')) {
115 $fields->findOrMakeTab('Root.Roles', _t('SecurityAdmin.ROLES', 'Roles'));
116 $fields->addFieldToTab('Root.Roles',
117 new LiteralField(
118 "",
119 "<p>" .
120 _t('SecurityAdmin.ROLESDESCRIPTION',
121 "This section allows you to add roles to this group. Roles are logical groupings of permissions, which can be editied in the Roles tab"
122 ) .
123 "</p>"
124 )
125 );
126
127
128 $allRoles = Permission::check('ADMIN') ? DataObject::get('PermissionRole') : DataObject::get('PermissionRole', 'OnlyAdminCanApply = 0');
129 $groupRoles = $this->Roles();
130 $inheritedRoles = new DataObjectSet();
131 $ancestors = $this->getAncestors();
132 foreach($ancestors as $ancestor) {
133 $ancestorRoles = $ancestor->Roles();
134 if($ancestorRoles) $inheritedRoles->merge($ancestorRoles);
135 }
136 $fields->addFieldToTab(
137 'Root.Roles',
138 $rolesField = new CheckboxSetField('Roles', _t('Group.Roles', 'Roles'), $allRoles)
139 );
140 $rolesField->setDefaultItems($inheritedRoles->column('ID'));
141 $rolesField->setDisabledItems($inheritedRoles->column('ID'));
142 }
143
144 $memberList->setController($this);
145 $memberList->setPermissions(array('edit', 'delete', 'export', 'add'));
146 $memberList->setParentClass('Group');
147 $memberList->setPopupCaption(_t('SecurityAdmin.VIEWUSER', 'View User'));
148 $memberList->setRelationAutoSetting(false);
149
150 $fields->push($idField = new HiddenField("ID"));
151
152 $this->extend('updateCMSFields', $fields);
153
154 return $fields;
155 }
156
157 158 159 160 161
162 function fieldLabels($includerelations = true) {
163 $labels = parent::fieldLabels($includerelations);
164 $labels['Title'] = _t('SecurityAdmin.GROUPNAME', 'Group name');
165 $labels['Description'] = _t('Group.Description', 'Description');
166 $labels['Code'] = _t('Group.Code', 'Group Code', PR_MEDIUM, 'Programmatical code identifying a group');
167 $labels['Locked'] = _t('Group.Locked', 'Locked?', PR_MEDIUM, 'Group is locked in the security administration area');
168 $labels['Sort'] = _t('Group.Sort', 'Sort Order');
169 $labels['IPRestrictions'] = _t('Group.IPRestrictions', 'IP Address Restrictions');
170 if($includerelations){
171 $labels['Parent'] = _t('Group.Parent', 'Parent Group', PR_MEDIUM, 'One group has one parent group');
172 $labels['Permissions'] = _t('Group.has_many_Permissions', 'Permissions', PR_MEDIUM, 'One group has many permissions');
173 $labels['Members'] = _t('Group.many_many_Members', 'Members', PR_MEDIUM, 'One group has many members');
174 }
175
176 return $labels;
177 }
178
179 180 181 182 183 184 185
186 static function addToGroupByName($member, $groupcode) {
187 $group = DataObject::get_one('Group', "\"Code\" = '" . Convert::raw2sql($groupcode). "'");
188 if($group) {
189 $member->Groups()->add($group);
190 }
191 else {
192 $group = new Group();
193 $group->Code = $groupcode;
194 $group->Title = $groupcode;
195 $group->write();
196
197 $member->Groups()->add($group);
198 }
199 }
200
201 202 203 204 205 206 207 208 209 210 211 212
213 public function Members($limit = "", $offset = "", $filter = "", $sort = "", $join = "") {
214 $table = "Group_Members";
215 if($filter) $filter = is_array($filter) ? $filter : array($filter);
216
217 if( is_numeric( $limit ) ) {
218 if( is_numeric( $offset ) )
219 $limit = "$limit OFFSET $offset";
220 else
221 $limit = "$limit OFFSET 0";
222 } else {
223 $limit = "";
224 }
225
226
227 $groupFamily = implode(", ", $this->collateFamilyIDs());
228
229 $filter[] = "\"$table\".\"GroupID\" IN ($groupFamily)";
230 $join .= " INNER JOIN \"$table\" ON \"$table\".\"MemberID\" = \"Member\".\"ID\"" . Convert::raw2sql($join);
231
232 $result = singleton("Member")->instance_get(
233 $filter,
234 $sort,
235 $join,
236 $limit,
237 "ComponentSet"
238 );
239
240 if(!$result) $result = new ComponentSet();
241
242 $result->setComponentInfo("many-to-many", $this, "Group", $table, "Member");
243 foreach($result as $item) $item->GroupID = $this->ID;
244 return $result;
245 }
246
247 public function map($filter = "", $sort = "", $blank="") {
248 $ret = new SQLMap(singleton('Group')->extendedSQL($filter, $sort));
249 if($blank){
250 $blankGroup = new Group();
251 $blankGroup->Title = $blank;
252 $blankGroup->ID = 0;
253
254 $ret->getItems()->shift($blankGroup);
255 }
256 return $ret;
257 }
258
259 260 261 262 263
264 public function collateFamilyIDs() {
265 $familyIDs = array();
266 $chunkToAdd = array(array("ID" => $this->ID));
267
268 while($chunkToAdd) {
269 $idList = array();
270 foreach($chunkToAdd as $item) {
271 $idList[] = $item['ID'];
272 $familyIDs[] = $item['ID'];
273 }
274 $idList = implode(',', $idList);
275
276
277
278 $sql = $this->extendedSQL("\"ParentID\" IN ($idList)", "");
279 $dbResult = $sql->execute();
280 $chunkToAdd = array();
281 foreach($dbResult as $item) $chunkToAdd[] = $item;
282 }
283
284 return $familyIDs;
285 }
286
287 288 289
290 public function collateAncestorIDs() {
291 $parent = $this;
292 while(isset($parent)) {
293 $items[] = $parent->ID;
294 $parent = $parent->Parent;
295 }
296 return $items;
297 }
298
299 300 301 302
303 function cmsCleanup_parentChanged() {
304 }
305
306 307 308
309 public function stageChildren() {
310 return DataObject::get('Group', "\"Group\".\"ParentID\" = " . (int)$this->ID . " AND \"Group\".\"ID\" != " . (int)$this->ID, '"Sort"');
311 }
312
313 public function TreeTitle() {
314 if($this->hasMethod('alternateTreeTitle')) return $this->alternateTreeTitle();
315 else return htmlspecialchars($this->Title, ENT_QUOTES);
316 }
317
318 function CMSTreeClasses($controller) {
319 $classes = $this->class;
320
321 if(!$this->canEdit()) $classes .= " disabled";
322
323 return $classes;
324 }
325
326 327 328
329 public function setCode($val){
330 $this->setField("Code",SiteTree::generateURLSegment($val));
331 }
332
333 function onBeforeWrite() {
334 parent::onBeforeWrite();
335
336 if(stripos($this->Code, _t('SecurityAdmin.NEWGROUPPREFIX','new-')) === 0) {
337 $this->setCode($this->Title);
338 }
339 }
340
341 function onAfterDelete() {
342 parent::onAfterDelete();
343
344
345 $permissions = $this->Permissions();
346 foreach ( $permissions as $permission ) {
347 $permission->delete();
348 }
349 }
350
351 352 353 354 355 356 357
358 public function canEdit($member = null) {
359 if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
360
361
362 $results = $this->extend('canEdit', $member);
363 if($results && is_array($results)) if(!min($results)) return false;
364
365 if(
366
367 (bool)Permission::checkMember($member, "ADMIN")
368 || (
369
370
371
372 Permission::checkMember($member, "CMS_ACCESS_SecurityAdmin") &&
373 !DataObject::get("Permission", "GroupID = $this->ID AND Code = 'ADMIN'")
374 )
375 ) {
376 return true;
377 }
378
379 return false;
380 }
381
382 383 384 385 386 387
388 public function canView($member = null) {
389 if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
390
391
392 $results = $this->extend('canView', $member);
393 if($results && is_array($results)) if(!min($results)) return false;
394
395
396 if(Permission::checkMember($member, "CMS_ACCESS_SecurityAdmin")) return true;
397
398 return false;
399 }
400
401 public function canDelete($member = null) {
402 if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
403
404
405 $results = $this->extend('canDelete', $member);
406 if($results && is_array($results)) if(!min($results)) return false;
407
408 return $this->canEdit($member);
409 }
410
411 412 413 414
415 function AllChildrenIncludingDeleted() {
416 $extInstance = $this->getExtensionInstance('Hierarchy');
417 $extInstance->setOwner($this);
418 $children = $extInstance->AllChildrenIncludingDeleted();
419 $extInstance->clearOwner();
420
421 $filteredChildren = new DataObjectSet();
422
423 if($children) foreach($children as $child) {
424 if($child->canView()) $filteredChildren->push($child);
425 }
426
427 return $filteredChildren;
428 }
429
430 431 432 433
434 function allowedIPAddress($ip) {
435 if(!$this->IPRestrictions) return true;
436 if(!$ip) return false;
437
438 $ipPatterns = explode("\n", $this->IPRestrictions);
439 foreach($ipPatterns as $ipPattern) {
440 $ipPattern = trim($ipPattern);
441 if(preg_match('/^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$/', $ipPattern, $matches)) {
442 if($ip == $ipPattern) return true;
443 } else if(preg_match('/^([0-9]+\.[0-9]+\.[0-9]+)\/24$/', $ipPattern, $matches)
444 || preg_match('/^([0-9]+\.[0-9]+)\/16$/', $ipPattern, $matches)
445 || preg_match('/^([0-9]+)\/8$/', $ipPattern, $matches)) {
446 if(substr($ip, 0, strlen($matches[1])) == $matches[1]) return true;
447 }
448 }
449 return false;
450 }
451
452 453 454 455 456 457
458 public function requireDefaultRecords() {
459 parent::requireDefaultRecords();
460
461
462 $allGroups = DataObject::get('Group');
463 if(!$allGroups) {
464 $authorGroup = new Group();
465 $authorGroup->Code = 'content-authors';
466 $authorGroup->Title = _t('Group.DefaultGroupTitleContentAuthors', 'Content Authors');
467 $authorGroup->Sort = 1;
468 $authorGroup->write();
469 Permission::grant($authorGroup->ID, 'CMS_ACCESS_CMSMain');
470 Permission::grant($authorGroup->ID, 'CMS_ACCESS_AssetAdmin');
471 Permission::grant($authorGroup->ID, 'CMS_ACCESS_CommentAdmin');
472 Permission::grant($authorGroup->ID, 'CMS_ACCESS_ReportAdmin');
473 Permission::grant($authorGroup->ID, 'SITETREE_REORGANISE');
474 }
475
476
477 $adminGroups = Permission::get_groups_by_permission('ADMIN');
478 if(!$adminGroups) {
479 $adminGroup = new Group();
480 $adminGroup->Code = 'administrators';
481 $adminGroup->Title = _t('Group.DefaultGroupTitleAdministrators', 'Administrators');
482 $adminGroup->Sort = 0;
483 $adminGroup->write();
484 Permission::grant($adminGroup->ID, 'ADMIN');
485 }
486
487
488 }
489 }
490
491 ?>
[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the
Silverstripe Forums to ask development related questions.
-