]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/PagePerm.php
php_closing_tag [PSR-2] The closing ?> tag MUST be omitted from files containing...
[SourceForge/phpwiki.git] / lib / PagePerm.php
1 <?php // -*-php-*-
2
3 /*
4  * Copyright 2004,2007 $ThePhpWikiProgrammingTeam
5  * Copyright 2009-2010 Marc-Etienne Vargenau, Alcatel-Lucent
6  *
7  * This file is part of PhpWiki.
8  *
9  * PhpWiki is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * PhpWiki is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with PhpWiki; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24 /**
25  * Permissions per page and action based on current user,
26  * ownership and group membership implemented with ACL's (Access Control Lists),
27  * opposed to the simplier unix-like ugo:rwx system.
28  * The previous system was only based on action and current user. (lib/main.php)
29  *
30  * Permissions may be inherited from its parent pages, a optional the
31  * optional master page ("."), and predefined default permissions, if "."
32  * is not defined.
33  * Pagenames starting with "." have special default permissions.
34  * For Authentication see WikiUserNew.php, WikiGroup.php and main.php
35  * Page Permissions are in PhpWiki since v1.3.9 and enabled since v1.4.0
36  *
37  * This file might replace the following functions from main.php:
38  *   Request::_notAuthorized($require_level)
39  *     display the denied message and optionally a login form
40  *     to gain higher privileges
41  *   Request::getActionDescription($action)
42  *     helper to localize the _notAuthorized message per action,
43  *     when login is tried.
44  *   Request::getDisallowedActionDescription($action)
45  *     helper to localize the _notAuthorized message per action,
46  *     when it aborts
47  *   Request::requiredAuthority($action)
48  *     returns the needed user level
49  *     has a hook for plugins on POST
50  *   Request::requiredAuthorityForAction($action)
51  *     just returns the level per action, will be replaced with the
52  *     action + page pair
53  *
54  *   The defined main.php actions map to simplier access types:
55  *     browse => view
56  *     edit   => edit
57  *     create => edit or create
58  *     remove => remove
59  *     rename => change
60  *     store prefs => change
61  *     list in PageList => list
62  */
63
64 /* Symbolic special ACL groups. Untranslated to be stored in page metadata*/
65 define('ACL_EVERY',       '_EVERY');
66 define('ACL_ANONYMOUS',       '_ANONYMOUS');
67 define('ACL_BOGOUSER',       '_BOGOUSER');
68 define('ACL_HASHOMEPAGE',  '_HASHOMEPAGE');
69 define('ACL_SIGNED',       '_SIGNED');
70 define('ACL_AUTHENTICATED','_AUTHENTICATED');
71 define('ACL_ADMIN',       '_ADMIN');
72 define('ACL_OWNER',       '_OWNER');
73 define('ACL_CREATOR',       '_CREATOR');
74
75 // Return an page permissions array for this page.
76 // To provide ui helpers to view and change page permissions:
77 //   <tr><th>Group</th><th>Access</th><th>Allow or Forbid</th></tr>
78 //   <tr><td>$group</td><td>_($access)</td><td> [ ] </td></tr>
79 function pagePermissions($pagename) {
80     global $request;
81     $page = $request->getPage($pagename);
82     // Page not found (new page); returned inherited permissions, to be displayed in gray
83     if (! $page->exists() ) {
84         if ($pagename == '.') // stop recursion
85             return array('default', new PagePermission());
86         else {
87             return array('inherited', pagePermissions(getParentPage($pagename)));
88         }
89     } elseif ($perm = getPagePermissions($page)) {
90         return array('page', $perm);
91     // or no permissions defined; returned inherited permissions, to be displayed in gray
92     } elseif ($pagename == '.') { // stop recursion in pathological case.
93         // "." defined, without any acl
94         return array('default', new PagePermission());
95     } else {
96         return array('inherited', pagePermissions(getParentPage($pagename)));
97     }
98 }
99
100 function pagePermissionsSimpleFormat($perm_tree, $owner, $group=false) {
101     list($type,$perm) = pagePermissionsAcl($perm_tree[0], $perm_tree);
102     /*
103     $type = $perm_tree[0];
104     $perm = pagePermissionsAcl($perm_tree);
105     if (is_object($perm_tree[1]))
106         $perm = $perm_tree[1];
107     elseif (is_array($perm_tree[1])) {
108         $perm_tree = pagePermissionsSimpleFormat($perm_tree[1],$owner,$group);
109     if (isa($perm_tree[1],'pagepermission'))
110         $perm = $perm_tree[1];
111     elseif (isa($perm_tree,'htmlelement'))
112             return $perm_tree;
113     }
114     */
115     if ($type == 'page')
116         return HTML::tt(HTML::strong($perm->asRwxString($owner, $group)));
117     elseif ($type == 'default')
118         return HTML::tt($perm->asRwxString($owner, $group));
119     elseif ($type == 'inherited') {
120         return HTML::tt(array('class'=>'inherited', 'style'=>'color:#aaa;'),
121                         $perm->asRwxString($owner, $group));
122     }
123 }
124
125 function pagePermissionsAcl($type,$perm_tree) {
126     $perm = $perm_tree[1];
127     while (!is_object($perm)) {
128         $perm_tree = pagePermissionsAcl($type, $perm);
129         $perm = $perm_tree[1];
130     }
131     return array($type,$perm);
132 }
133
134 // view => who
135 // edit => who
136 function pagePermissionsAclFormat($perm_tree, $editable=false) {
137     list($type,$perm) = pagePermissionsAcl($perm_tree[0], $perm_tree);
138     if ($editable)
139         return $perm->asEditableTable($type);
140     else
141         return $perm->asTable($type);
142 }
143
144 /**
145  * Check the permissions for the current action.
146  * Walk down the inheritance tree. Collect all permissions until
147  * the minimum required level is gained, which is not
148  * overruled by more specific forbid rules.
149  * Todo: cache result per access and page in session?
150  */
151 function requiredAuthorityForPage ($action) {
152     global $request;
153     $auth = _requiredAuthorityForPagename(action2access($action),
154                                           $request->getArg('pagename'));
155     assert($auth !== -1);
156     if ($auth)
157         return $request->_user->_level;
158     else
159         return WIKIAUTH_UNOBTAINABLE;
160 }
161
162 // Translate action or plugin to the simplier access types:
163 function action2access ($action) {
164     global $request;
165     switch ($action) {
166     case 'browse':
167     case 'viewsource':
168     case 'diff':
169     case 'select':
170     case 'search':
171     case 'pdf':
172     case 'captcha':
173         return 'view';
174
175     // performance and security relevant
176     case 'xmlrpc':
177     case 'soap':
178     case 'zip':
179     case 'ziphtml':
180     case 'dumphtml':
181     case 'dumpserial':
182         return 'dump';
183
184     // invent a new access-perm massedit? or switch back to change, or keep it at edit?
185     case _("PhpWikiAdministration")."/"._("Rename"):
186     case _("PhpWikiAdministration")."/"._("SearchReplace"):
187     case 'replace':
188     case 'rename':
189     case 'revert':
190     case 'edit':
191         return 'edit';
192     case 'create':
193         $page = $request->getPage();
194         if (!$page->exists())
195             return 'create';
196         else
197             return 'view';
198         break;
199     case 'upload':
200     case 'loadfile':
201     // probably create/edit but we cannot check all page permissions, can we?
202     case 'remove':
203     case 'purge':
204     case 'lock':
205     case 'unlock':
206     case 'upgrade':
207     case 'chown':
208     case 'setacl':
209     return 'change';
210     default:
211         //Todo: Plugins should be able to override its access type
212         if (isWikiWord($action))
213             return 'view';
214         else
215             return 'change';
216         break;
217     }
218 }
219
220 // Recursive helper to do the real work.
221 // Using a simple perm cache for page-access pairs.
222 // Maybe page-(current+edit+change?)action pairs will help
223 function _requiredAuthorityForPagename($access, $pagename) {
224     static $permcache = array();
225
226     if (array_key_exists($pagename, $permcache)
227         and array_key_exists($access, $permcache[$pagename]))
228         return $permcache[$pagename][$access];
229
230     global $request;
231     $page = $request->getPage($pagename);
232
233     // Exceptions:
234     if (FUSIONFORGE) {
235         if ($pagename != '.' && isset($request->_user->_is_external) && $request->_user->_is_external && ! $page->get('external')) {
236             $permcache[$pagename][$access] = 0;
237             return 0;
238         }
239     }
240     if ((READONLY or $request->_dbi->readonly)
241         and in_array($access, array('edit','create','change')))
242     {
243         return 0;
244     }
245
246     // Page not found; check against default permissions
247     if (! $page->exists() ) {
248         $perm = new PagePermission();
249         $result = ($perm->isAuthorized($access, $request->_user) === true);
250         $permcache[$pagename][$access] = $result;
251         return $result;
252     }
253     // no ACL defined; check for special dotfile or walk down
254     if (! ($perm = getPagePermissions($page))) {
255         if ($pagename == '.') {
256             $perm = new PagePermission();
257             if ($perm->isAuthorized('change', $request->_user)) {
258                 // warn the user to set ACL of ".", if he has permissions to do so.
259                 trigger_error(". (dotpage == rootpage for inheriting pageperm ACLs) exists without any ACL!\n".
260                               "Please do ?action=setacl&pagename=.", E_USER_WARNING);
261             }
262             $result = ($perm->isAuthorized($access, $request->_user) === true);
263             $permcache[$pagename][$access] = $result;
264             return $result;
265         } elseif ($pagename[0] == '.') {
266             $perm = new PagePermission(PagePermission::dotPerms());
267             $result = ($perm->isAuthorized($access, $request->_user) === true);
268             $permcache[$pagename][$access] = $result;
269             return $result;
270         }
271         return _requiredAuthorityForPagename($access, getParentPage($pagename));
272     }
273     // ACL defined; check if isAuthorized returns true or false or undecided
274     $authorized = $perm->isAuthorized($access, $request->_user);
275     if ($authorized !== -1) { // interestingly true is also -1
276         $permcache[$pagename][$access] = $authorized;
277         return $authorized;
278     } elseif ($pagename == '.') {
279         return false;
280     } else {
281         return _requiredAuthorityForPagename($access, getParentPage($pagename));
282     }
283 }
284
285 /**
286  * @param  string $pagename   page from which the parent page is searched.
287  * @return string parent      pagename or the (possibly pseudo) dot-pagename.
288  */
289 function getParentPage($pagename) {
290     if (isSubPage($pagename)) {
291         return subPageSlice($pagename, 0);
292     } else {
293         return '.';
294     }
295 }
296
297 // Read the ACL from the page
298 // Done: Not existing pages should NOT be queried.
299 // Check the parent page instead and don't take the default ACL's
300 function getPagePermissions ($page) {
301     if ($hash = $page->get('perm'))  // hash => object
302         return new PagePermission(unserialize($hash));
303     else
304         return false;
305 }
306
307 // Store the ACL in the page
308 function setPagePermissions ($page,$perm) {
309     $perm->store($page);
310 }
311
312 function getAccessDescription($access) {
313     static $accessDescriptions;
314     if (! $accessDescriptions) {
315         $accessDescriptions = array(
316                                     'list'     => _("List this page and all subpages"),
317                                     'view'     => _("View this page and all subpages"),
318                                     'edit'     => _("Edit this page and all subpages"),
319                                     'create'   => _("Create a new (sub)page"),
320                                     'dump'     => _("Download page contents"),
321                                     'change'   => _("Change page attributes"),
322                                     'remove'   => _("Remove this page"),
323                                     'purge'    => _("Purge this page"),
324                                     );
325     }
326     if (in_array($access, array_keys($accessDescriptions)))
327         return $accessDescriptions[$access];
328     else
329         return $access;
330 }
331
332 /**
333  * The ACL object per page. It is stored in a page, but can also
334  * be merged with ACL's from other pages or taken from the master (pseudo) dot-file.
335  *
336  * A hash of "access" => "requires" pairs.
337  *   "access"   is a shortcut for common actions, which map to main.php actions
338  *   "requires" required username or groupname or any special group => true or false
339  *
340  * Define any special rules here, like don't list dot-pages.
341  */
342 class PagePermission {
343     var $perm;
344
345     function PagePermission($hash = array()) {
346         $this->_group = &$GLOBALS['request']->getGroup();
347         if (is_array($hash) and !empty($hash)) {
348             $accessTypes = $this->accessTypes();
349             foreach ($hash as $access => $requires) {
350                 if (in_array($access, $accessTypes))
351                     $this->perm[$access] = $requires;
352                 else
353                     trigger_error(sprintf(_("Unsupported ACL access type %s ignored."), $access),
354                                   E_USER_WARNING);
355             }
356         } else {
357             // set default permissions, the so called dot-file acl's
358             $this->perm = $this->defaultPerms();
359         }
360         return $this;
361     }
362
363     /**
364      * The workhorse to check the user against the current ACL pairs.
365      * Must translate the various special groups to the actual users settings
366      * (userid, group membership).
367      */
368     function isAuthorized($access, $user) {
369         $allow = -1;
370         if (!empty($this->perm{$access})) {
371             foreach ($this->perm[$access] as $group => $bool) {
372                 if ($this->isMember($user, $group)) {
373                     return $bool;
374                 } elseif ($allow == -1) { // not a member and undecided: check other groups
375                     $allow = !$bool;
376                 }
377             }
378         }
379         return $allow; // undecided
380     }
381
382     /**
383      * Translate the various special groups to the actual users settings
384      * (userid, group membership).
385      */
386     function isMember($user, $group) {
387         global $request;
388         if ($group === ACL_EVERY) return true;
389         if (!isset($this->_group)) $member =& $request->getGroup();
390         else $member =& $this->_group;
391         //$user = & $request->_user;
392         if ($group === ACL_ADMIN)   // WIKI_ADMIN or member of _("Administrators")
393             return $user->isAdmin() or
394                    ($user->isAuthenticated() and
395                    $member->isMember(GROUP_ADMIN));
396         if ($group === ACL_ANONYMOUS)
397             return ! $user->isSignedIn();
398         if ($group === ACL_BOGOUSER)
399             if (ENABLE_USER_NEW)
400                 return isa($user,'_BogoUser') or
401                       (isWikiWord($user->_userid) and $user->_level >= WIKIAUTH_BOGO);
402             else return isWikiWord($user->UserName());
403         if ($group === ACL_HASHOMEPAGE)
404             return $user->hasHomePage();
405         if ($group === ACL_SIGNED)
406             return $user->isSignedIn();
407         if ($group === ACL_AUTHENTICATED)
408             return $user->isAuthenticated();
409         if ($group === ACL_OWNER) {
410             if (!$user->isAuthenticated()) return false;
411             $page = $request->getPage();
412             $owner = $page->getOwner();
413             return ($owner === $user->UserName()
414                     or $member->isMember($owner));
415         }
416         if ($group === ACL_CREATOR) {
417             if (!$user->isAuthenticated()) return false;
418             $page = $request->getPage();
419             $creator = $page->getCreator();
420             return ($creator === $user->UserName()
421                     or $member->isMember($creator));
422         }
423         /* Or named groups or usernames.
424            Note: We don't seperate groups and users here.
425            Users overrides groups with the same name.
426         */
427         return $user->UserName() === $group or
428                $member->isMember($group);
429     }
430
431     /**
432      * returns hash of default permissions.
433      * check if the page '.' exists and returns this instead.
434      */
435     function defaultPerms() {
436         //Todo: check for the existance of '.' and take this instead.
437         //Todo: honor more config.ini auth settings here
438         $perm = array('view'   => array(ACL_EVERY => true),
439                       'edit'   => array(ACL_EVERY => true),
440                       'create' => array(ACL_EVERY => true),
441                       'list'   => array(ACL_EVERY => true),
442                       'remove' => array(ACL_ADMIN => true,
443                                         ACL_OWNER => true),
444                       'purge'  => array(ACL_ADMIN => true,
445                                         ACL_OWNER => true),
446                       'dump'   => array(ACL_ADMIN => true,
447                                         ACL_OWNER => true),
448                       'change' => array(ACL_ADMIN => true,
449                                         ACL_OWNER => true));
450         if (ZIPDUMP_AUTH)
451             $perm['dump'] = array(ACL_ADMIN => true,
452                                   ACL_OWNER => true);
453         elseif (INSECURE_ACTIONS_LOCALHOST_ONLY) {
454             if (is_localhost())
455                 $perm['dump'] = array(ACL_EVERY => true);
456             else
457                 $perm['dump'] = array(ACL_ADMIN => true);
458         }
459         else
460             $perm['dump'] = array(ACL_EVERY => true);
461         if (defined('REQUIRE_SIGNIN_BEFORE_EDIT') && REQUIRE_SIGNIN_BEFORE_EDIT)
462             $perm['edit'] = array(ACL_SIGNED => true);
463         // view:
464         if (!ALLOW_ANON_USER) {
465             if (!ALLOW_USER_PASSWORDS)
466                 $perm['view'] = array(ACL_SIGNED => true);
467             else
468                 $perm['view'] = array(ACL_AUTHENTICATED => true);
469             $perm['view'][ACL_BOGOUSER] = ALLOW_BOGO_LOGIN ? true : false;
470         }
471         // edit:
472         if (!ALLOW_ANON_EDIT) {
473             if (!ALLOW_USER_PASSWORDS)
474                 $perm['edit'] = array(ACL_SIGNED => true);
475             else
476                 $perm['edit'] = array(ACL_AUTHENTICATED => true);
477             $perm['edit'][ACL_BOGOUSER] = ALLOW_BOGO_LOGIN ? true : false;
478             $perm['create'] = $perm['edit'];
479         }
480         return $perm;
481     }
482
483     /**
484      * FIXME: check valid groups and access
485      */
486     function sanify() {
487         foreach ($this->perm as $access => $groups) {
488             foreach ($groups as $group => $bool) {
489                 $this->perm[$access][$group] = (boolean) $bool;
490             }
491         }
492     }
493
494     /**
495      * do a recursive comparison
496      */
497     function equal($otherperm) {
498         // The equal function seems to be unable to detect removed perm.
499         // Use case is when a rule is removed.
500         return (print_r($this->perm, true) === print_r($otherperm, true));
501     }
502
503     /**
504      * returns list of all supported access types.
505      */
506     function accessTypes() {
507         return array_keys(PagePermission::defaultPerms());
508     }
509
510     /**
511      * special permissions for dot-files, beginning with '.'
512      * maybe also for '_' files?
513      */
514     function dotPerms() {
515         $def = array(ACL_ADMIN => true,
516                      ACL_OWNER => true);
517         $perm = array();
518         foreach (PagePermission::accessTypes() as $access) {
519             $perm[$access] = $def;
520         }
521         return $perm;
522     }
523
524     /**
525      *  dead code. not needed inside the object. see getPagePermissions($page)
526      */
527     function retrieve($page) {
528         $hash = $page->get('perm');
529         if ($hash)  // hash => object
530             $perm = new PagePermission(unserialize($hash));
531         else
532             $perm = new PagePermission();
533         $perm->sanify();
534         return $perm;
535     }
536
537     function store($page) {
538         // object => hash
539         $this->sanify();
540         return $page->set('perm',serialize($this->perm));
541     }
542
543     function groupName ($group) {
544         if ($group[0] == '_') return constant("GROUP".$group);
545         else return $group;
546     }
547
548     /* type: page, default, inherited */
549     function asTable($type) {
550         $table = HTML::table();
551         foreach ($this->perm as $access => $perms) {
552             $td = HTML::table(array('class' => 'cal'));
553             foreach ($perms as $group => $bool) {
554                 $td->pushContent(HTML::tr(HTML::td(array('align'=>'right'),$group),
555                                                    HTML::td($bool ? '[X]' : '[ ]')));
556             }
557             $table->pushContent(HTML::tr(array('valign' => 'top'),
558                                          HTML::td($access),HTML::td($td)));
559         }
560         if ($type == 'default')
561             $table->setAttr('style','border: dotted thin black; background-color:#eee;');
562         elseif ($type == 'inherited')
563             $table->setAttr('style','border: dotted thin black; background-color:#ddd;');
564         elseif ($type == 'page')
565             $table->setAttr('style','border: solid thin black; font-weight: bold;');
566         return $table;
567     }
568
569     /* type: page, default, inherited */
570     function asEditableTable($type) {
571         global $WikiTheme;
572         if (!isset($this->_group)) {
573             $this->_group =& $GLOBALS['request']->getGroup();
574         }
575         $table = HTML::table();
576         $table->pushContent(HTML::tr(
577                                      HTML::th(array('align' => 'left'),
578                                               _("Access")),
579                                      HTML::th(array('align'=>'right'),
580                                               _("Group/User")),
581                                      HTML::th(_("Grant")),
582                                      HTML::th(_("Del/+")),
583                                      HTML::th(_("Description"))));
584
585         $allGroups = $this->_group->_specialGroups();
586         foreach ($this->_group->getAllGroupsIn() as $group) {
587             if (!in_array($group,$this->_group->specialGroups()))
588                 $allGroups[] = $group;
589         }
590         //array_unique(array_merge($this->_group->getAllGroupsIn(),
591         $deletesrc = $WikiTheme->_findData('images/delete.png');
592         $addsrc = $WikiTheme->_findData('images/add.png');
593         $nbsp = HTML::raw('&nbsp;');
594         foreach ($this->perm as $access => $groups) {
595             //$permlist = HTML::table(array('class' => 'cal'));
596             $first_only = true;
597             $newperm = HTML::input(array('type' => 'checkbox',
598                                          'name' => "acl[_new_perm][$access]",
599                                          'value' => 1));
600             $addbutton = HTML::input(array('type' => 'checkbox',
601                                            'name' => "acl[_add_group][$access]",
602                                            //'src'  => $addsrc,
603                                            //'alt'   => "Add",
604                                            'title' => _("Add this ACL"),
605                                            'value' => 1));
606             $newgroup = HTML::select(array('name' => "acl[_new_group][$access]",
607                                            'style'=> 'text-align: right;',
608                                            'size' => 1));
609             foreach ($allGroups as $groupname) {
610                 if (!isset($groups[$groupname]))
611                     $newgroup->pushContent(HTML::option(array('value' => $groupname),
612                                                         $this->groupName($groupname)));
613             }
614             if (empty($groups)) {
615                 $addbutton->setAttr('checked','checked');
616                 $newperm->setAttr('checked','checked');
617                 $table->pushContent(
618                     HTML::tr(array('valign' => 'top'),
619                              HTML::td(HTML::strong($access.":")),
620                              HTML::td($newgroup),
621                              HTML::td($nbsp,$newperm),
622                              HTML::td($nbsp,$addbutton),
623                              HTML::td(HTML::em(getAccessDescription($access)))));
624             }
625             foreach ($groups as $group => $bool) {
626                 $checkbox = HTML::input(array('type' => 'checkbox',
627                                               'name' => "acl[$access][$group]",
628                                               'title' => _("Allow / Deny"),
629                                               'value' => 1));
630                 if ($bool) $checkbox->setAttr('checked','checked');
631                 $checkbox = HTML(HTML::input(array('type' => 'hidden',
632                                                    'name' => "acl[$access][$group]",
633                                                    'value' => 0)),
634                                  $checkbox);
635                 $deletebutton = HTML::input(array('type' => 'checkbox',
636                                                   'name' => "acl[_del_group][$access][$group]",
637                                                   'style' => 'background: #aaa url('.$deletesrc.')',
638                                                   //'src'  => $deletesrc,
639                                                   //'alt'   => "Del",
640                                                   'title' => _("Delete this ACL"),
641                                                   'value' => 1));
642                 if ($first_only) {
643                     $table->pushContent(
644                         HTML::tr(
645                                  HTML::td(HTML::strong($access.":")),
646                                  HTML::td(array('class' => 'cal-today','align'=>'right'),
647                                           HTML::strong($this->groupName($group))),
648                                  HTML::td(array('align'=>'center'),$nbsp,$checkbox),
649                                  HTML::td(array('align'=>'right','style' => 'background: #aaa url('.$deletesrc.') no-repeat'),$deletebutton),
650                                  HTML::td(HTML::em(getAccessDescription($access)))));
651                     $first_only = false;
652                 } else {
653                     $table->pushContent(
654                         HTML::tr(
655                                  HTML::td(),
656                                  HTML::td(array('class' => 'cal-today','align'=>'right'),
657                                           HTML::strong($this->groupName($group))),
658                                  HTML::td(array('align'=>'center'),$nbsp,$checkbox),
659                                  HTML::td(array('align'=>'right','style' => 'background: #aaa url('.$deletesrc.') no-repeat'),$deletebutton),
660                                  HTML::td()));
661                 }
662             }
663             if (!empty($groups))
664                 $table->pushContent(
665                     HTML::tr(array('valign' => 'top'),
666                              HTML::td(array('align'=>'right'),_("add ")),
667                              HTML::td($newgroup),
668                              HTML::td(array('align'=>'center'),$nbsp,$newperm),
669                              HTML::td(array('align'=>'right','style' => 'background: #ccc url('.$addsrc.') no-repeat'),$addbutton),
670                              HTML::td(HTML::small(_("Check to add this ACL")))));
671         }
672         if ($type == 'default')
673             $table->setAttr('style','border: dotted thin black; background-color:#eee;');
674         elseif ($type == 'inherited')
675             $table->setAttr('style','border: dotted thin black; background-color:#ddd;');
676         elseif ($type == 'page')
677             $table->setAttr('style','border: solid thin black; font-weight: bold;');
678         return $table;
679     }
680
681     // Print ACL as lines of [+-]user[,group,...]:access[,access...]
682     // Seperate acl's by "; " or whitespace
683     // See http://opag.ca/wiki/HelpOnAccessControlLists
684     // As used by WikiAdminSetAclSimple
685     function asAclLines() {
686         $s = ''; $line = '';
687         $this->sanify();
688         foreach ($this->perm as $access => $groups) {
689             // unify groups for same access+bool
690             //    view:CREATOR,-OWNER,
691             $line = $access.':';
692             foreach ($groups as $group => $bool) {
693                 $line .= ($bool?'':'-').$group.",";
694             }
695             if (substr($line,-1) == ',')
696                 $s .= substr($line,0,-1)."; ";
697         }
698         if (substr($s,-2) == '; ')
699             $s = substr($s,0,-2);
700         return $s;
701     }
702
703     // This is just a bad hack for testing.
704     // Simplify the ACL to a unix-like "rwx------+" string
705     // See getfacl(8)
706     function asRwxString($owner,$group=false) {
707         global $request;
708         // simplify object => rwxrw---x+ string as in cygwin (+ denotes additional ACLs)
709         $perm =& $this->perm;
710         // get effective user and group
711         $s = '---------+';
712         if (isset($perm['view'][$owner]) or
713             (isset($perm['view'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
714             $s[0] = 'r';
715         if (isset($perm['edit'][$owner]) or
716             (isset($perm['edit'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
717             $s[1] = 'w';
718         if (isset($perm['change'][$owner]) or
719             (isset($perm['change'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
720             $s[2] = 'x';
721         if (!empty($group)) {
722             if (isset($perm['view'][$group]) or
723                 (isset($perm['view'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
724                 $s[3] = 'r';
725             if (isset($perm['edit'][$group]) or
726                 (isset($perm['edit'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
727                 $s[4] = 'w';
728             if (isset($perm['change'][$group]) or
729                 (isset($perm['change'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
730                 $s[5] = 'x';
731         }
732         if (isset($perm['view'][ACL_EVERY]) or
733             (isset($perm['view'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
734             $s[6] = 'r';
735         if (isset($perm['edit'][ACL_EVERY]) or
736             (isset($perm['edit'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
737             $s[7] = 'w';
738         if (isset($perm['change'][ACL_EVERY]) or
739             (isset($perm['change'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
740             $s[8] = 'x';
741         return $s;
742     }
743 }
744
745 // Local Variables:
746 // mode: php
747 // tab-width: 8
748 // c-basic-offset: 4
749 // c-hanging-comment-ender-p: nil
750 // indent-tabs-mode: nil
751 // End: