1 <?php
2 3 4 5 6
7 class SecurityAdmin extends LeftAndMain implements PermissionProvider {
8
9 static $url_segment = 'security';
10
11 static $url_rule = '/$Action/$ID/$OtherID';
12
13 static = 'Security';
14
15 static $tree_class = 'Group';
16
17 static $subitem_class = 'Member';
18
19 static $allowed_actions = array(
20 'addgroup',
21 'addmember',
22 'autocomplete',
23 'removememberfromgroup',
24 'savemember',
25 'AddRecordForm',
26 'MemberForm',
27 'EditForm',
28 'MemberImportForm',
29 'memberimport',
30 'GroupImportForm',
31 'groupimport',
32 'RootForm'
33 );
34
35 36 37
38 static $hidden_permissions = array();
39
40 public function init() {
41 parent::init();
42
43 Requirements::javascript(CMS_DIR . '/javascript/hover.js');
44 Requirements::javascript(THIRDPARTY_DIR . "/scriptaculous/controls.js");
45
46
47 Requirements::add_i18n_javascript(SAPPHIRE_DIR . '/javascript/lang');
48 Requirements::javascript(SAPPHIRE_DIR . "/javascript/TableListField.js");
49 Requirements::javascript(SAPPHIRE_DIR . "/javascript/TableField.js");
50 Requirements::javascript(SAPPHIRE_DIR . "/javascript/ComplexTableField.js");
51 Requirements::javascript(CMS_DIR . "/javascript/MemberTableField.js");
52 Requirements::css(THIRDPARTY_DIR . "/greybox/greybox.css");
53 Requirements::css(SAPPHIRE_DIR . "/css/ComplexTableField.css");
54
55 Requirements::javascript(CMS_DIR . '/javascript/SecurityAdmin_left.js');
56 Requirements::javascript(CMS_DIR . '/javascript/SecurityAdmin_right.js');
57
58 Requirements::javascript(THIRDPARTY_DIR . "/greybox/AmiJS.js");
59 Requirements::javascript(THIRDPARTY_DIR . "/greybox/greybox.js");
60 }
61
62 function getEditForm($id = null) {
63 if(!$id) $id = $this->currentPageID();
64
65 if($id && $id != 'root') {
66 $record = DataObject::get_by_id($this->stat('tree_class'), $id);
67 if(!$record) return false;
68 }
69
70 if($id && is_numeric($id)) {
71 $fields = $record->getCMSFields();
72
73 if($fields->hasTabSet()) {
74 $fields->findOrMakeTab('Root.Import',_t('Group.IMPORTTABTITLE', 'Import'));
75 $fields->addFieldToTab('Root.Import',
76 new LiteralField(
77 'MemberImportFormIframe',
78 sprintf(
79 '<iframe src="%s" id="MemberImportFormIframe" width="100%%" height="400px" border="0"></iframe>',
80 $this->Link('memberimport')
81 )
82 )
83 );
84 if(Permission::check('APPLY_ROLES')) {
85 $fields->findOrMakeTab('Root.Roles', _t('SecurityAdmin.ROLES', 'Roles'));
86 $fields->addFieldToTab(
87 'Root.Roles',
88 new LiteralField(
89 'RolesAddEditLink',
90 sprintf(
91 '<p class="add-role"><a href="%s">%s</a></p>',
92 $this->Link('show/root'),
93
94
95 _t('Group.RolesAddEditLink', 'Add/edit roles')
96 )
97 )
98 );
99 }
100 }
101
102 $actions = new FieldSet(
103 new FormAction('addmember',_t('SecurityAdmin.ADDMEMBER','Add Member'))
104 );
105
106 if (Permission::check('EDIT_PERMISSIONS')) {
107 $actions->push(new FormAction('save',_t('SecurityAdmin.SAVE','Save')));
108 }
109
110 $form = new Form($this, "EditForm", $fields, $actions);
111 $form->loadDataFrom($record);
112
113 if(!$record->canEdit()) {
114 $readonlyFields = $form->Fields()->makeReadonly();
115 $form->setFields($readonlyFields);
116 }
117
118
119 $permissionField = $form->Fields()->dataFieldByName('Permissions');
120 if($permissionField) $permissionField->setHiddenPermissions(self::$hidden_permissions);
121
122 $this->extend('updateEditForm', $form);
123 } else {
124 $form = $this->RootForm();
125 }
126
127 return $form;
128 }
129
130 131 132
133 function RootForm() {
134 $memberList = new MemberTableField(
135 $this,
136 "Members"
137 );
138
139 $memberList->setPermissions(array('edit', 'delete', 'add'));
140 $memberList->setRelationAutoSetting(false);
141
142 $fields = new FieldSet(
143 new TabSet(
144 'Root',
145 new Tab('Members', singleton('Member')->i18n_plural_name(),
146 $memberList,
147 new LiteralField('MembersCautionText',
148 sprintf('<p class="caution-remove"><strong>%s</strong></p>',
149 _t(
150 'SecurityAdmin.MemberListCaution',
151 'Caution: Removing members from this list will remove them from all groups and the database'
152 )
153 )
154 )
155 ),
156 new Tab('Import', _t('SecurityAdmin.TABIMPORT', 'Import'),
157 new LiteralField(
158 'GroupImportFormIframe',
159 sprintf(
160 '<iframe src="%s" id="GroupImportFormIframe" width="100%%" height="400px" border="0"></iframe>',
161 $this->Link('groupimport')
162 )
163 )
164 )
165 ),
166
167 new HiddenField('ID', false, 0)
168 );
169
170
171 if(Permission::check('APPLY_ROLES')) {
172 $rolesCTF = new ComplexTableField(
173 $this,
174 'Roles',
175 'PermissionRole'
176 );
177 $rolesCTF->setPermissions(array('add', 'edit', 'delete'));
178
179 $rolesTab = $fields->findOrMakeTab('Root.Roles', _t('SecurityAdmin.TABROLES', 'Roles'));
180 $rolesTab->push(new LiteralField(
181 'RolesDescription',
182 ''
183 ));
184 $rolesTab->push($rolesCTF);
185 }
186
187 $actions = new FieldSet(
188 new FormAction('addmember',_t('SecurityAdmin.ADDMEMBER','Add Member'))
189 );
190
191 $this->extend('updateRootFormFields', $fields, $actions);
192
193 $form = new Form(
194 $this,
195 'EditForm',
196 $fields,
197 $actions
198 );
199
200 return $form;
201 }
202
203 public function memberimport() {
204 Requirements::clear();
205 Requirements::css(SAPPHIRE_DIR . '/css/Form.css');
206 Requirements::css(CMS_DIR . '/css/typography.css');
207 Requirements::css(CMS_DIR . '/css/cms_right.css');
208 Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js');
209 Requirements::javascript(THIRDPARTY_DIR . '/jquery-livequery/jquery.livequery.js');
210 Requirements::javascript(SAPPHIRE_DIR . '/javascript/jquery_improvements.js');
211 Requirements::css(CMS_DIR . '/css/MemberImportForm.css');
212 Requirements::javascript(CMS_DIR . '/javascript/MemberImportForm.js');
213
214 return $this->renderWith('BlankPage', array(
215 'Form' => $this->MemberImportForm()
216 ));
217 }
218
219 220 221 222 223
224 public function MemberImportForm() {
225 $group = $this->currentPage();
226 $form = new MemberImportForm(
227 $this,
228 'MemberImportForm'
229 );
230 $form->setGroup($group);
231
232 return $form;
233 }
234
235 public function groupimport() {
236 Requirements::clear();
237 Requirements::css(SAPPHIRE_DIR . '/css/Form.css');
238 Requirements::css(CMS_DIR . '/css/typography.css');
239 Requirements::css(CMS_DIR . '/css/cms_right.css');
240 Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js');
241 Requirements::javascript(THIRDPARTY_DIR . '/jquery-livequery/jquery.livequery.js');
242 Requirements::javascript(SAPPHIRE_DIR . '/javascript/jquery_improvements.js');
243 Requirements::css(CMS_DIR . '/css/MemberImportForm.css');
244 Requirements::javascript(CMS_DIR . '/javascript/MemberImportForm.js');
245
246 return $this->renderWith('BlankPage', array(
247 'Form' => $this->GroupImportForm()
248 ));
249 }
250
251 252 253 254 255
256 public function GroupImportForm() {
257 $form = new GroupImportForm(
258 $this,
259 'GroupImportForm'
260 );
261
262 return $form;
263 }
264
265 public function AddRecordForm() {
266 $m = Object::create('MemberTableField',
267 $this,
268 "Members",
269 $this->currentPageID()
270 );
271 return $m->AddRecordForm();
272 }
273
274 275 276
277 public function autocomplete() {
278 $fieldName = $this->urlParams['ID'];
279 $fieldVal = $_REQUEST[$fieldName];
280 $result = '';
281
282
283 if(!singleton($this->stat('subitem_class'))->hasDatabaseField($fieldName) || $fieldName == 'Password') return;
284
285 $matches = DataObject::get($this->stat('subitem_class'),"\"$fieldName\" LIKE '" . Convert::raw2sql($fieldVal) . "%'");
286 if($matches) {
287 $result .= "<ul>";
288 foreach($matches as $match) {
289 if(!$match->canView()) continue;
290
291 $data = $match->FirstName;
292 $data .= ",$match->Surname";
293 $data .= ",$match->Email";
294 $result .= "<li>" . $match->$fieldName . "<span class=\"informal\">($match->FirstName $match->Surname, $match->Email)</span><span class=\"informal data\">$data</span></li>";
295 }
296 $result .= "</ul>";
297 return $result;
298 }
299 }
300
301 public function MemberForm() {
302 $id = $_REQUEST['ID'] ? $_REQUEST['ID'] : Session::get('currentMember');
303 if($id) return $this->getMemberForm($id);
304 }
305
306 public function getMemberForm($id) {
307 if($id && $id != 'new') $record = DataObject::get_by_id('Member', (int) $id);
308 if($record || $id == 'new') {
309 $fields = new FieldSet(
310 new HiddenField('MemberListBaseGroup', '', $this->currentPageID() )
311 );
312
313 if($extraFields = $record->getCMSFields()) {
314 foreach($extraFields as $extra) {
315 $fields->push( $extra );
316 }
317 }
318
319 $fields->push($idField = new HiddenField('ID'));
320 $fields->push($groupIDField = new HiddenField('GroupID'));
321
322 $actions = new FieldSet();
323 $actions->push(new FormAction('savemember', _t('SecurityAdmin.SAVE')));
324
325 $form = new Form($this, 'MemberForm', $fields, $actions);
326 if($record) $form->loadDataFrom($record);
327
328 $idField->setValue($id);
329 $groupIDField->setValue($this->currentPageID());
330
331 if($record && !$record->canEdit()) {
332 $readonlyFields = $form->Fields()->makeReadonly();
333 $form->setFields($readonlyFields);
334 }
335
336 return $form;
337 }
338 }
339
340 function savemember() {
341 $data = $_REQUEST;
342 $className = $this->stat('subitem_class');
343
344 $id = $_REQUEST['ID'];
345 if($id == 'new') $id = null;
346
347 if($id) {
348 $record = DataObject::get_by_id($className, $id);
349 if($record && !$record->canEdit()) return Security::permissionFailure($this);
350 } else {
351 if(!singleton($this->stat('subitem_class'))->canCreate()) return Security::permissionFailure($this);
352 $record = new $className();
353 }
354
355 $record->update($data);
356 $record->ID = $id;
357 $record->write();
358
359 $record->Groups()->add($data['GroupID']);
360
361 FormResponse::add("reloadMemberTableField();");
362
363 return FormResponse::respond();
364 }
365
366 function addmember($className=null) {
367 $data = $_REQUEST;
368 unset($data['ID']);
369 if($className == null) $className = $this->stat('subitem_class');
370
371 if(!singleton($this->stat('subitem_class'))->canCreate()) return Security::permissionFailure($this);
372
373 $record = new $className();
374
375 $record->update($data);
376 $record->write();
377
378 if($data['GroupID']) $record->Groups()->add((int)$data['GroupID']);
379
380 FormResponse::add("reloadMemberTableField();");
381
382 return FormResponse::respond();
383 }
384
385 public function removememberfromgroup() {
386 $groupID = $this->urlParams['ID'];
387 $memberID = $this->urlParams['OtherID'];
388 if(is_numeric($groupID) && is_numeric($memberID)) {
389 $member = DataObject::get_by_id('Member', (int) $memberID);
390
391 if(!$member->canDelete()) return Security::permissionFailure($this);
392
393 $member->Groups()->remove((int)$groupID);
394
395 FormResponse::add("reloadMemberTableField();");
396 } else {
397 user_error("SecurityAdmin::removememberfromgroup: Bad parameters: Group=$groupID, Member=$memberID", E_USER_ERROR);
398 }
399
400 return FormResponse::respond();
401 }
402
403 404 405 406
407 public function SiteTreeAsUL() {
408 $obj = singleton($this->stat('tree_class'));
409 $obj->markPartialTree();
410
411 if($p = $this->currentPage()) $obj->markToExpose($p);
412
413
414 $siteTreeList = $obj->getChildrenAsUL(
415 '',
416 '"<li id=\"record-$child->ID\" class=\"$child->class " . $child->markingClasses() . ($extraArg->isCurrentPage($child) ? " current" : "") . "\">" . ' .
417 '"<a href=\"" . Controller::join_links(substr($extraArg->Link(),0,-1), "show", $child->ID) . "\" >" . $child->TreeTitle() . "</a>" ',
418 $this,
419 true
420 );
421
422
423 $rootLink = $this->Link() . 'show/root';
424 $rootTitle = _t('SecurityAdmin.SGROUPS', 'Security Groups');
425 if(!isset($rootID)) {
426 $siteTree = "<ul id=\"sitetree\" class=\"tree unformatted\"><li id=\"record-root\" class=\"Root\"><a href=\"$rootLink\"><strong>{$rootTitle}</strong></a>"
427 . $siteTreeList . "</li></ul>";
428 }
429
430 return $siteTree;
431 }
432
433 public function addgroup() {
434 if(!singleton($this->stat('tree_class'))->canCreate()) return Security::permissionFailure($this);
435
436 $newGroup = Object::create($this->stat('tree_class'));
437 $newGroup->Title = _t('SecurityAdmin.NEWGROUP',"New Group");
438 $newGroup->Code = "new-group";
439 $newGroup->ParentID = (is_numeric($_REQUEST['ParentID'])) ? (int)$_REQUEST['ParentID'] : 0;
440 $newGroup->write();
441
442 return $this->returnItemToUser($newGroup);
443 }
444
445 public function EditedMember() {
446 if(Session::get('currentMember')) return DataObject::get_by_id('Member', (int) Session::get('currentMember'));
447 }
448
449 function providePermissions() {
450 return array(
451 'EDIT_PERMISSIONS' => array(
452 'name' => _t('SecurityAdmin.EDITPERMISSIONS', 'Manage permissions for groups'),
453 'category' => _t('Permissions.PERMISSIONS_CATEGORY', 'Roles and access permissions'),
454 'help' => _t('SecurityAdmin.EDITPERMISSIONS_HELP', 'Ability to edit Permissions and IP Addresses for a group. Requires the "Access to \'Security\' section" permission.'),
455 'sort' => 0
456 ),
457 'APPLY_ROLES' => array(
458 'name' => _t('SecurityAdmin.APPLY_ROLES', 'Apply roles to groups'),
459 'category' => _t('Permissions.PERMISSIONS_CATEGORY', 'Roles and access permissions'),
460 'help' => _t('SecurityAdmin.APPLY_ROLES_HELP', 'Ability to edit the roles assigned to a group. Requires the "Access to \'Security\' section" permission.'),
461 'sort' => 0
462 )
463 );
464 }
465
466 467 468 469 470 471
472 static function add_hidden_permission($codes){
473 if(is_string($codes)) $codes = array($codes);
474 self::$hidden_permissions = array_merge(self::$hidden_permissions, $codes);
475 }
476
477 478 479
480 static function remove_hidden_permission($codes){
481 if(is_string($codes)) $codes = array($codes);
482 self::$hidden_permissions = array_diff(self::$hidden_permissions, $codes);
483 }
484
485 486 487
488 static function get_hidden_permissions(){
489 return self::$hidden_permissions;
490 }
491
492 493 494
495 static function clear_hidden_permissions(){
496 self::$hidden_permissions = array();
497 }
498 }
499
500 ?>
501
[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.
-