00001 <?php
00002
00019 final class SnapPermission extends SnapObject {
00021 const USER_ADMIN = 'ADMIN';
00023 const USER_RESTORE = 'RESTORE';
00025 const USER_DESTROY = 'DESTROY';
00026
00028 const ACCESS_DEFAULT_DENY = 0;
00030 const ACCESS_GROUP_ALLOW = 1;
00032 const ACCESS_GROUP_DENY = 2;
00034 const ACCESS_USER_ALLOW = 3;
00036 const ACCESS_USER_DENY = 4;
00038 const ACCESS_RESTORE = 5;
00040 const ACCESS_DESTROY = 6;
00042 const ACCESS_ADMIN = 7;
00043
00045 const CAP_DEFAULT = 'DEFAULT';
00047 const CAP_ALLOW = 'ALLOW';
00049 const CAP_DENY = 'DENY';
00050
00054 private static $SPECIAL_USERS = null;
00055
00060 private $updateTransaction = null;
00061
00066 private static $BS = array(
00067 self::CAP_DEFAULT => array(
00068 'perm_and' => '0',
00069 'perm_or' => '0',
00070 'mask_and' => '0',
00071 'mask_or' => '0'
00072 ),
00073 self::CAP_ALLOW => array(
00074 'perm_and' => '1',
00075 'perm_or' => '1',
00076 'mask_and' => '1',
00077 'mask_or' => '1'
00078 ),
00079 self::CAP_DENY => array(
00080 'perm_and' => '0',
00081 'perm_or' => '0',
00082 'mask_and' => '1',
00083 'mask_or' => '1'
00084 ),
00085 99 => array(
00086 'perm_and' => '1',
00087 'perm_or' => '0',
00088 'mask_and' => '1',
00089 'mask_or' => '0'
00090 )
00091 );
00092
00100 public function __construct($file) {
00101 $fields = array('file' => true, 'fileType' => true, 'permObjects' => true,
00102 'parties' => array($this, 'loadParties'), 'cache' => true);
00103 parent::__construct('Permission', $fields, array());
00104
00105 $fileObj = self::convertReference($file, 'File');
00106 if($fileObj == null || !$fileObj instanceof SnapFile) {
00107 $this->setError('Invalid file given to permission object!');
00108 $this->setValid(false);
00109 }
00110 else {
00111 $this->set('file', $fileObj);
00112 $this->set('fileType', $fileObj->getType());
00113 $this->set('permObjects', array());
00114 $this->set('cache', array());
00115 }
00116 }
00117
00122 protected function populate() {
00123 $this->setValid(true);
00124 return true;
00125 }
00126
00131 protected function loadParties() {
00132 $query = 'SELECT uid FROM ' . $this->get('fileType') . 'UserPermission WHERE '
00133 . strtolower($this->get('fileType')) . 'Id = ' . $this->get('file')->getId()
00134 . ' GROUP BY uid';
00135 if(!SnapDBI::query($query)) {
00136 $this->setError('Error during query');
00137 return false;
00138 }
00139 $parties = array('users' => array(), 'groups' => array());
00140 while($row = SnapDBI::getRow())
00141 $parties['users'][] = $row['uid'];
00142 SnapDBI::freeResult();
00143
00144 $query = 'SELECT gid FROM ' . $this->get('fileType') . 'GroupPermission WHERE '
00145 . strtolower($this->get('fileType')) . 'Id = ' . $this->get('file')->getId()
00146 . ' GROUP BY gid';
00147 if(!SnapDBI::query($query)) {
00148 $this->setError('Error during query');
00149 return false;
00150 }
00151 while($row = SnapDBI::getRow())
00152 $parties['groups'][] = $row['gid'];
00153 SnapDBI::freeResult();
00154
00155 $this->set('parties', $parties);
00156 return true;
00157 }
00158
00165 private function getUserKey($uid) {
00166 $file = $this->get('file');
00167 $key = 'U:' . $uid . ';' . substr($file->getType(), 0, 1) . ':' . $file->getId();
00168 return $key;
00169 }
00170
00177 protected function getGroupKey($gid) {
00178 $file = $this->get('file');
00179 $key = 'G:' . $gid . ';' . substr($file->getType(), 0, 1) . ':' . $file->getId();
00180 return $key;
00181 }
00182
00192 protected function getUserPermObject($uid) {
00193 $permObjects = $this->get('permObjects');
00194 $fileObj = $this->get('file');
00195 $key = $this->getUserKey($uid);
00196 if(array_key_exists($key, $permObjects))
00197 return $permObjects[$key][0];
00198
00199 $objType = 'Snap' . $fileObj->getType() . 'UserPermission';
00200 $perm = call_user_func(array($objType, 'retrieve'), $fileObj->getId(), $uid);
00201
00202 $permObjects[$key] = array($perm);
00203 $this->set('permObjects', $permObjects);
00204
00205 return $perm;
00206 }
00207
00217 protected function getGroupPermObject($gid) {
00218 $permObjects = $this->get('permObjects');
00219 $fileObj = $this->get('file');
00220 $key = $this->getGroupKey($gid);
00221 if(array_key_exists($key, $permObjects))
00222 return $permObjects[$key];
00223
00224 $objType = 'Snap' . $fileObj->getType() . 'GroupPermission';
00225 $perm = call_user_func(array($objType, 'retrieve'), $fileObj->getId(), $gid);
00226
00227 $permObjects[$key] = $perm;
00228 $this->set('permObjects', $permObjects);
00229
00230 return $perm;
00231 }
00232
00242 protected function getGroupPermObjects($uid) {
00243 $key = $this->getUserKey($uid);
00244 if(!isset($permObjects[$key]))
00245 $this->getUserPermObject($uid);
00246
00247 $permObjects = $this->get('permObjects');
00248 $fileObj = $this->get('file');
00249 if(array_key_exists($key, $permObjects) && array_key_exists('groups', $permObjects[$key]))
00250 return $permObjects[$key]['groups'];
00251
00252 $objType = 'Snap' . $fileObj->getType() . 'GroupPermission';
00253 $perms = call_user_func(array($objType, 'getGroupPermissionsForUser'), $fileObj->getId(), $uid);
00254
00255 $permObjects[$key]['groups'] = $perms;
00256 $this->set('permObjects', $permObjects);
00257
00258 return $perms;
00259 }
00260
00271 protected function getCachedAccess($cap, $uid = '') {
00272 if($uid == '')
00273 $uid = Snap2::getCurrentUser();
00274
00275 $cacheObjects = $this->get('cache');
00276 if(!isset($cacheObjects[$uid])) {
00277 $cacheObjects[$uid] = SnapPermissionCache::retrieve($this->get('fileType'), $this->get('file')->getId(), $uid);
00278
00279 $this->set('cache', $cacheObjects);
00280 }
00281
00282 $access = $cacheObjects[$uid]->getEA($cap);
00283 return $access;
00284 }
00285
00291 public function mayChangePermission($uid = '') {
00292 if(!$this->checkValid()) return false;
00293
00294 if(self::isSpecialUser($uid) === 'ADMIN')
00295 return true;
00296
00297 if(!$this->has('Change' . $this->get('fileType') . 'Permission', $uid))
00298 return false;
00299
00300 return true;
00301 }
00302
00310 public function canChangePermission() {
00311 if(!$this->checkValid()) return false;
00312
00313 $file = $this->get('file');
00314
00315 if($file->getType() == 'Directory' && $file->getId() == Snap2::DELETED_DIR_ID) {
00316 $this->setReason('You cannot change permissions on the root or DELETED directories');
00317 return false;
00318 }
00319
00320 if($file->isCanonChildOf(Snap2::DELETED_DIR_ID)) {
00321 $this->setReason('You cannot change the permission of objects in /DELETED/');
00322 return false;
00323 }
00324
00325 if(!$this->mayChangePermission()) {
00326 $this->setReason('Permission denied');
00327 return false;
00328 }
00329
00330 return true;
00331 }
00332
00347 private function hasImpl($cap, $uid) {
00348 if(self::isSpecialUser(self::USER_ADMIN, $uid))
00349 return true;
00350
00351 $userObj = $this->getUserPermObject($uid);
00352 if(!$userObj || $userObj->getCapability($cap) == self::CAP_DEFAULT) {
00353 $groupObjects = $this->getGroupPermObjects($uid);
00354 $highest = 0;
00355 foreach($groupObjects as $gr) {
00356 switch($gr->getCapability($cap)) {
00357 case self::CAP_DEFAULT:
00358 break;
00359 case self::CAP_ALLOW:
00360 if($highest < 1)
00361 $highest = 1;
00362 break;
00363 case self::CAP_DENY:
00364 $highest = 2;
00365 break;
00366 }
00367 }
00368 if($highest == 1)
00369 return true;
00370 else
00371 return false;
00372 }
00373 else if($userObj && $userObj->getCapability($cap) == self::CAP_ALLOW) {
00374 return true;
00375 }
00376 else {
00377 return false;
00378 }
00379 }
00380
00387 private function saveToCache($caps, $uid) {
00388 $cobjects = $this->get('cache');
00389 $cacheObj = $cobjects[$uid];
00390
00391 foreach($caps as $cap) {
00392 $access = $this->hasImpl($cap, $uid);
00393 $cacheObj->setEA($cap, $access);
00394 }
00395
00396 $cacheObj->commit();
00397 }
00398
00405 public function has($cap, $uid = '') {
00406 if(!$this->checkValid()) return false;
00407
00408 $caps = SnapPermission::getCapabilities($this->get('fileType'));
00409
00410 if(!in_array($cap, $caps)) {
00411 $this->setError('Invalid capability \'' . $cap . '\'');
00412 return false;
00413 }
00414
00415 if($uid == '') {
00416 $uid = Snap2::getCurrentUser();
00417 if($uid === false) {
00418 $this->setError('No current user!');
00419 return false;
00420 }
00421 }
00422
00423 $cachedAccess = $this->getCachedAccess($cap, $uid);
00424 if($cachedAccess !== null)
00425 return $cachedAccess;
00426
00427 $this->saveToCache($caps, $uid);
00428 $cachedAccess = $this->getCachedAccess($cap, $uid);
00429 if($cachedAccess !== null)
00430 return $cachedAccess;
00431
00432 return $this->hasImpl($cap, $uid);
00433 }
00434
00447 public function hasEx($cap, $uid = '') {
00448 if(!$this->checkValid()) return array(false, 'N/A');
00449
00450 $caps = SnapPermission::getCapabilities($this->get('fileType'));
00451
00452 if(!in_array($cap, $caps)) {
00453 $this->setError('Invalid capability \'' . $cap . '\'');
00454 return array(false, false);
00455 }
00456
00457 if($uid == '') {
00458 $uid = Snap2::getCurrentUser();
00459 if($uid === false) {
00460 $this->setError('No current user!');
00461 return array(false, false);
00462 }
00463 }
00464
00465 if(self::isSpecialUser(self::USER_ADMIN, $uid))
00466 return array(self::ACCESS_ADMIN, false);
00467
00468 $userObj = $this->getUserPermObject($uid);
00469 if(!$userObj || $userObj->getCapability($cap) == self::CAP_DEFAULT) {
00470 $groupObjects = $this->getGroupPermObjects($uid);
00471 $highest = 0;
00472 $highestGroup = '';
00473 foreach($groupObjects as $gr) {
00474 switch($gr->getCapability($cap)) {
00475 case self::CAP_DEFAULT:
00476 break;
00477 case self::CAP_ALLOW:
00478 if($highest <= 1) {
00479 $highestGroup = $gr->getOwnerId();
00480 $highest = 1;
00481 }
00482 break;
00483 case self::CAP_DENY:
00484 $highest = 2;
00485 $highestGroup = $gr->getOwnerId();
00486 break;
00487 }
00488 }
00489 switch($highest) {
00490 case 0:
00491 return array(self::ACCESS_DEFAULT_DENY, false);
00492 case 1:
00493 return array(self::ACCESS_GROUP_ALLOW, $highestGroup);
00494 case 2:
00495 return array(self::ACCESS_GROUP_DENY, $highestGroup);
00496 }
00497 }
00498 else if($userObj) {
00499 switch($userObj->getCapability($cap)) {
00500 case self::CAP_ALLOW:
00501 return array(self::ACCESS_USER_ALLOW, false);
00502 case self::CAP_DENY:
00503 return array(self::ACCESS_USER_DENY, false);
00504 default:
00505 return array(self::ACCESS_DEFAULT_DENY, false);
00506 }
00507 }
00508 else {
00509 return array(self::ACCESS_DEFAULT_DENY, false);
00510 }
00511 }
00512
00519 public function getUserAccess($cap, $uid = '') {
00520 if(!$this->checkValid()) return false;
00521
00522 if($uid == '') {
00523 $uid = Snap2::getCurrentUser();
00524 if(!$uid) {
00525 $this->setError('No current user!');
00526 return false;
00527 }
00528 }
00529
00530 $userObj = $this->getUserPermObject($uid);
00531 if(!$userObj)
00532 return self::ACCESS_DEFAULT_DENY;
00533 switch($userObj->getCapability($cap)) {
00534 case self::CAP_ALLOW: return self::ACCESS_USER_ALLOW;
00535 case self::CAP_DENY: return self::ACCESS_USER_DENY;
00536 default: return self::ACCESS_DEFAULT_DENY;
00537 }
00538 }
00539
00547 public function getGroupAccess($cap, $gid) {
00548 if(!$this->checkValid()) return false;
00549
00550 $groupObj = $this->getGroupPermObject($gid);
00551 if(!$groupObj)
00552 return self::ACCESS_DEFAULT_DENY;
00553 switch($groupObj->getCapability($cap)) {
00554 case self::CAP_ALLOW: return self::ACCESS_GROUP_ALLOW;
00555 case self::CAP_DENY: return self::ACCESS_GROUP_DENY;
00556 default: return self::ACCESS_DEFAULT_DENY;
00557 }
00558 }
00559
00572 public function getGroupsAccess($cap, $uid = '') {
00573
00574 if(!$this->checkValid()) return array(false, false);
00575
00576 if($uid == '') {
00577 $uid = Snap2::getCurrentUser();
00578 if(!$uid) {
00579 $this->setError('No current user!');
00580 return array(false, false);
00581 }
00582 }
00583
00584 $groupObjects = $this->getGroupPermObjects($uid);
00585 $highest = 0;
00586 $highestGroup = '';
00587 foreach($groupObjects as $gr) {
00588 switch($gr->getCapability($cap)) {
00589 case self::CAP_DEFAULT:
00590 break;
00591 case self::CAP_ALLOW:
00592 if($highest <= 1) {
00593 $highestGroup = $gr->getOwnerId();
00594 $highest = 1;
00595 }
00596 break;
00597 case self::CAP_DENY:
00598 $highest = 2;
00599 $highestGroup = $gr->getOwnerId();
00600 break;
00601 }
00602 }
00603 switch($highest) {
00604 case 0:
00605 return array(self::ACCESS_DEFAULT_DENY, false);
00606 case 1:
00607 return array(self::ACCESS_GROUP_ALLOW, $highestGroup);
00608 case 2:
00609 return array(self::ACCESS_GROUP_DENY, $highestGroup);
00610 }
00611 }
00612
00613
00624 public function setUserAccess($cap, $access, $uid = '') {
00625 if(!$this->checkValid()) return false;
00626
00627 if(!$this->canChangePermission()) {
00628 $this->setError('Failed to set access: ' . $this->getReason());
00629 return false;
00630 }
00631
00632 if($uid == '') {
00633 $uid = Snap2::getCurrentUser();
00634 if(!$uid) {
00635 $this->setError('No current user!');
00636 return false;
00637 }
00638 }
00639
00640 if($this->updateTransaction == null)
00641 $this->updateTransaction = array('users' => array(), 'groups' => array());
00642 if(!isset($this->updateTransaction['users'][$uid]))
00643 $this->updateTransaction['users'][$uid] = array();
00644
00645 $this->updateTransaction['users'][$uid][$cap] = $access;
00646 return true;
00647 }
00648
00659 public function setGroupAccess($cap, $access, $gid) {
00660 if(!$this->checkValid()) return false;
00661
00662 if(!$this->canChangePermission()) {
00663 $this->setError('Failed to set access: ' . $this->getReason());
00664 return false;
00665 }
00666
00667 if($this->updateTransaction == null)
00668 $this->updateTransaction = array('users' => array(), 'groups' => array());
00669 if(!isset($this->updateTransaction['groups'][$gid]))
00670 $this->updateTransaction['groups'][$gid] = array();
00671
00672 $this->updateTransaction['groups'][$gid][$cap] = $access;
00673 return true;
00674 }
00675
00684 public function revokeUser($uid = '') {
00685 if(!$this->checkValid()) return false;
00686
00687 if(!$this->canChangePermission()) {
00688 $this->setError('Failed to revoke access: ' . $this->getReason());
00689 return false;
00690 }
00691
00692 if($uid == '') {
00693 $uid = Snap2::getCurrentUser();
00694 if(!$uid) {
00695 $this->setError('No current user!');
00696 return false;
00697 }
00698 }
00699
00700 if($this->updateTransaction == null)
00701 $this->updateTransaction = array('users' => array(), 'groups' => array());
00702 if(!isset($this->updateTransaction['users'][$uid]))
00703 $this->updateTransaction['users'][$uid] = array();
00704
00705 $capabilities = SnapPermissionObject::getCapabilities($this->get('fileType'));
00706 foreach($capabilities as $c)
00707 $this->updateTransaction['users'][$uid][$c] = self::CAP_DEFAULT;
00708
00709 return true;
00710 }
00711
00720 public function revokeGroup($gid) {
00721 if(!$this->checkValid()) return false;
00722
00723 if(!$this->canChangePermission()) {
00724 $this->setError('Failed to revoke access: ' . $this->getReason());
00725 return false;
00726 }
00727
00728 if($this->updateTransaction == null)
00729 $this->updateTransaction = array('users' => array(), 'groups' => array());
00730 if(!isset($this->updateTransaction['groups'][$gid]))
00731 $this->updateTransaction['groups'][$gid] = array();
00732
00733 $capabilities = SnapPermissionObject::getCapabilities($this->get('fileType'));
00734 foreach($capabilities as $c)
00735 $this->updateTransaction['groups'][$gid][$c] = self::CAP_DEFAULT;
00736
00737 return true;
00738 }
00739
00751 public function commit($cascade = false) {
00752 if(!$this->canChangePermission()) {
00753 $this->setError('Failed to commit permission changes: ' . $this->getReason());
00754 return false;
00755 }
00756
00757 if(!$this->updateTransaction) {
00758 $this->setWarning('Empty transaction; not committing anything to DB');
00759 return true;
00760 }
00761
00762
00763
00764 SnapCache::clearObjectCache('DirectoryUserPermission');
00765 SnapCache::clearObjectCache('DirectoryGroupPermission');
00766 SnapCache::clearObjectCache('ResourceUserPermission');
00767 SnapCache::clearObjectCache('ResourceGroupPermission');
00768 $permObjects = SnapCache::getObjectCache('Permission');
00769 foreach($permObjects as $p)
00770 $p->clearPermObjects();
00771
00772 $oldEnable = SnapCache::usingCache();
00773 SnapCache::setEnableCache(false, false);
00774
00775 $file = $this->get('file');
00776 $committed = array();
00777 SnapDBI::startTransaction();
00778 if(!$this->doCommit($file->getId(), $file->getType(), $this->updateTransaction, $cascade, $committed)) {
00779 SnapDBI::cancelTransaction();
00780 SnapCache::setEnableCache($oldEnable, false);
00781 $this->setError('failed to doCommit');
00782 return false;
00783 }
00784 $query = 'DELETE FROM ResourceUserPermission WHERE defaultMask = 0 AND permission = 0';
00785 SnapDBI::query($query);
00786 $query = 'DELETE FROM ResourceGroupPermission WHERE defaultMask = 0 AND permission = 0';
00787 SnapDBI::query($query);
00788 $query = 'DELETE FROM DirectoryUserPermission WHERE defaultMask = 0 AND permission = 0';
00789 SnapDBI::query($query);
00790 $query = 'DELETE FROM DirectoryGroupPermission WHERE defaultMask = 0 AND permission = 0';
00791 SnapDBI::query($query);
00792 SnapDBI::commitTransaction();
00793
00794 $this->updateTransaction = null;
00795 SnapCache::setEnableCache($oldEnable, false);
00796 return true;
00797 }
00798
00813 private function doCommit($parentId, $type, $updateTransaction, $cascade, &$committed) {
00814 $curUid = Snap2::getCurrentUser();
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846 $typeIdName = strtolower($type) . 'Id';
00847 $caps = self::getCapabilities($type);
00848 foreach($updateTransaction['users'] as $uid => $info) {
00849
00850 $perm_andBS = str_repeat('1', 32);
00851 $perm_orBS = str_repeat('0', 32);
00852 $mask_andBS = str_repeat('1', 32);
00853 $mask_orBS = str_repeat('0', 32);
00854 foreach($caps as $id => $cap) {
00855 if(isset($info[$cap]))
00856 $status = $info[$cap];
00857 else
00858 $status = 99;
00859 if(!SnapPermissionObject::isCapabilityForType($type, $cap))
00860 continue;
00861 $i = 32 - $id;
00862 $perm_andBS[$i] = self::$BS[$status]['perm_and'];
00863 $perm_orBS[$i] = self::$BS[$status]['perm_or'];
00864 $mask_andBS[$i] = self::$BS[$status]['mask_and'];
00865 $mask_orBS[$i] = self::$BS[$status]['mask_or'];
00866 }
00867 $query = <<<END_QUERY
00868 INSERT INTO ${type}UserPermission (uid, $typeIdName, permission, defaultMask) VALUES
00869 ('$uid', '$parentId', 0 & b'$perm_andBS' | b'$perm_orBS', 0 & b'$mask_andBS' | b'$mask_orBS')
00870 ON DUPLICATE KEY UPDATE permission = permission & b'$perm_andBS' | b'$perm_orBS',
00871 defaultMask = defaultMask & b'$mask_andBS' | b'$mask_orBS'
00872 END_QUERY;
00873 if(!SnapDBI::query($query)) {
00874 SnapDBI::cancelTransaction();
00875 return false;
00876 }
00877 }
00878
00879
00880
00881
00882
00883 if(count($updateTransaction['users']) > 0)
00884 SnapPermissionCache::clearCache($type, $parentId, $uid);
00885
00886 foreach($updateTransaction['groups'] as $gid => $info) {
00887 $perm_andBS = str_repeat('1', 32);
00888 $perm_orBS = str_repeat('0', 32);
00889 $mask_andBS = str_repeat('1', 32);
00890 $mask_orBS = str_repeat('0', 32);
00891 foreach($caps as $id => $cap) {
00892 if(isset($info[$cap]))
00893 $status = $info[$cap];
00894 else
00895 $status = 99;
00896 if(!SnapPermissionObject::isCapabilityForType($type, $cap))
00897 continue;
00898 $i = 32 - $id;
00899 $perm_andBS[$i] = self::$BS[$status]['perm_and'];
00900 $perm_orBS[$i] = self::$BS[$status]['perm_or'];
00901 $mask_andBS[$i] = self::$BS[$status]['mask_and'];
00902 $mask_orBS[$i] = self::$BS[$status]['mask_or'];
00903 }
00904 $query = <<<END_QUERY
00905 INSERT INTO ${type}GroupPermission (gid, $typeIdName, permission, defaultMask) VALUES
00906 ('$gid', '$parentId', 0 & b'$perm_andBS' | b'$perm_orBS', 0 & b'$mask_andBS' | b'$mask_orBS')
00907 ON DUPLICATE KEY UPDATE permission = permission & b'$perm_andBS' | b'$perm_orBS',
00908 defaultMask = defaultMask & b'$mask_andBS' | b'$mask_orBS'
00909 END_QUERY;
00910 if(!SnapDBI::query($query)) {
00911 SnapDBI::cancelTransaction();
00912 return false;
00913 }
00914 }
00915
00916
00917
00918
00919
00920
00921 if(count($updateTransaction['groups']) > 0)
00922 SnapPermissionCache::clearCache($type, $parentId);
00923
00924 $committed[$parentId . $type] = true;
00925
00926
00927
00928
00929
00930 if($type == 'Directory' && $cascade) {
00931 $query = 'SELECT childId FROM DirectoryLink WHERE parentId = ' . $parentId;
00932 if(($result = SnapDBI::query($query, true)) === false)
00933 return false;
00934 foreach($result as $row) {
00935 if(isset($committed[$row['childId'] . 'Directory']))
00936 continue;
00937 $ret = $this->doCommit($row['childId'], 'Directory', $updateTransaction, true, $committed);
00938 if(!$ret)
00939 return false;
00940 }
00941 $query = 'SELECT childId FROM ResourceLink WHERE parentId = ' . $parentId;
00942 if(($result = SnapDBI::query($query, true)) === false)
00943 return false;
00944 foreach($result as $row) {
00945 if(isset($committed[$row['childId'] . 'Resource']))
00946 continue;
00947 $ret = $this->doCommit($row['childId'], 'Resource', $updateTransaction, true, $committed);
00948 if(!$ret)
00949 return false;
00950 }
00951 }
00952
00953 return true;
00954 }
00955
00964 protected function clearPermObjects() {
00965 $this->set('permObjects', array());
00966 $this->set('cache', array());
00967 }
00968
00974 public function cancel() {
00975 $this->updateTransaction = null;
00976 return true;
00977 }
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00998 public function mayLinkTo($to, $uid = '') {
00999 if(!$this->checkValid()) return false;
01000
01001 if($uid == '')
01002 $uid = Snap2::getCurrentUser();
01003
01004 if(self::isSpecialUser(self::USER_ADMIN, $uid))
01005 return true;
01006
01007 $toObj = self::convertReference($to, 'Directory');
01008 if(!$toObj) {
01009 $this->setError('Invalid Snap reference');
01010 return false;
01011 }
01012
01013 if($toObj->getPermission()->has('Create' . $this->get('file')->getType(), $uid))
01014 return true;
01015
01016 return false;
01017 }
01018
01028 public function mayUnlinkFrom($from, $uid = '') {
01029 if(!$this->checkValid()) return false;
01030
01031 if($uid == '')
01032 $uid = Snap2::getCurrentUser();
01033
01034 if(self::isSpecialUser(self::USER_ADMIN, $uid))
01035 return true;
01036
01037 $fromObj = self::convertReference($from, 'Directory');
01038 if(!$fromObj) {
01039 $this->setError('Invalid Snap reference');
01040 return false;
01041 }
01042
01043 if($fromObj->getPermission()->has('Delete' . $this->get('file')->getType(), $uid))
01044 return true;
01045
01046 return false;
01047 }
01048
01058 public function mayRenameAt($at, $uid = '') {
01059 if(!$this->checkValid()) return false;
01060
01061 if($uid == '')
01062 $uid = Snap2::getCurrentUser();
01063
01064 if(self::isSpecialUser(self::USER_ADMIN, $uid))
01065 return true;
01066
01067 $atObj = self::convertReference($at, 'Directory');
01068 if(!$atObj) {
01069 $this->setError('Invalid Snap reference');
01070 return false;
01071 }
01072
01073 if($atObj->getPermission()->has('RenameFile', $uid))
01074 return true;
01075
01076 return false;
01077 }
01078
01088 public function maySetCanonicalParent($newParent, $uid = '') {
01089 if(!$this->checkValid()) return false;
01090
01091 if($uid == '')
01092 $uid = Snap2::getCurrentUser();
01093
01094 if(self::isSpecialUser(self::USER_ADMIN, $uid))
01095 return true;
01096
01097 $newParentObj = self::convertReference($newParent, 'Directory');
01098 if(!$newParentObj) {
01099 $this->setError('Invalid Snap reference');
01100 return false;
01101 }
01102
01103 $file = $this->get('file');
01104 $type = $file->getType();
01105 $oldParent = $file->getCanonicalParent();
01106 if($oldParent == null) {
01107 $this->setError('Internal Snap error: canonical parent is null, but we are not root or DELETED');
01108 return false;
01109 }
01110
01111 if($oldParent->getPermission()->has('MoveFile', $uid) &&
01112 $newParentObj->getPermission()->has('MoveFile', $uid))
01113 return true;
01114
01115 return false;
01116 }
01117
01128 public function mayMove($newParent, $uid = '') {
01129 return $this->maySetCanonicalParent($newParent, $uid);
01130 }
01131
01139 public function mayDelete($uid = '') {
01140 if(!$this->checkValid()) return false;
01141
01142 if($uid == '')
01143 $uid = Snap2::getCurrentUser();
01144
01145 if(self::isSpecialUser(self::USER_ADMIN, $uid))
01146 return true;
01147
01148 $fileType = $this->get('file')->getType();
01149
01150 if ($fileType == 'Resource'){
01151 if($this->has('DeleteUnlink'. $fileType, $uid))
01152 return true;
01153 }
01154
01155 if ($fileType == 'Directory'){
01156 if($this->has('Delete'. $fileType, $uid))
01157 return true;
01158 }
01159
01160 return false;
01161 }
01162
01170 public function mayRestore($uid = '') {
01171 if(!$this->checkValid()) return false;
01172
01173 if($uid == '')
01174 $uid = Snap2::getCurrentUser();
01175
01176 if(self::isSpecialUser(self::USER_RESTORE, $uid)
01177 || self::isSpecialUser(self::USER_ADMIN, $uid))
01178 return true;
01179
01180 return false;
01181 }
01182
01190 public function mayDestroy($uid = '') {
01191 if(!$this->checkValid()) return false;
01192
01193 if($uid == '')
01194 $uid = Snap2::getCurrentUser();
01195
01196 if(self::isSpecialUser(self::USER_DESTROY, $uid)
01197 || self::isSpecialUser(self::USER_ADMIN, $uid))
01198 return true;
01199
01200 return false;
01201 }
01202
01212 public function mayReorderIn($in, $uid = '') {
01213 if(!$this->checkValid()) return false;
01214
01215 if($uid == '')
01216 $uid = Snap2::getCurrentUser();
01217
01218 if(self::isSpecialUser(self::USER_ADMIN, $uid))
01219 return true;
01220
01221 $inObj = self::convertReference($in, 'Directory');
01222 if(!$inObj) {
01223 $this->setError('Invalid Snap reference');
01224 return false;
01225 }
01226
01227 if($inObj->getPermission()->has('ReorderFile', $uid))
01228 return true;
01229
01230 return false;
01231 }
01232
01243 public function mayReorderFiles($uid = '') {
01244 if(!$this->checkValid()) return false;
01245
01246 if($uid == '')
01247 $uid = Snap2::getCurrentUser();
01248
01249 if(self::isSpecialUser(self::USER_ADMIN, $uid))
01250 return true;
01251
01252 if($this->has('ReorderFile', $uid))
01253 return true;
01254
01255 return false;
01256 }
01257
01268 public function mayRenameFiles($uid = '') {
01269 if(!$this->checkValid()) return false;
01270
01271 if($uid == '')
01272 $uid = Snap2::getCurrentUser();
01273
01274 if(self::isSpecialUser(self::USER_ADMIN, $uid))
01275 return true;
01276
01277 if($this->has('RenameFile', $uid))
01278 return true;
01279
01280 return false;
01281 }
01282
01292 public function mayChangeMetadata($uid = '') {
01293 if(!$this->checkValid()) return false;
01294
01295 if($uid == '')
01296 $uid = Snap2::getCurrentUser();
01297
01298 if(self::isSpecialUser(self::USER_ADMIN, $uid))
01299 return true;
01300
01301 if($this->has('ChangeFileMetadata', $uid))
01302 return true;
01303
01304 return false;
01305 }
01306
01307
01308
01316 public function mayCreateDirectory($uid = '') {
01317 if(!$this->checkValid()) return false;
01318
01319 if($uid == '')
01320 $uid = Snap2::getCurrentUser();
01321
01322 if(self::isSpecialUser(self::USER_ADMIN, $uid))
01323 return true;
01324
01325 if($this->has('CreateDirectory', $uid))
01326 return true;
01327
01328 return false;
01329 }
01330
01338 public function mayCreateResource($uid = '') {
01339 if(!$this->checkValid()) return false;
01340
01341 if($uid == '')
01342 $uid = Snap2::getCurrentUser();
01343
01344 if(self::isSpecialUser(self::USER_ADMIN, $uid))
01345 return true;
01346
01347 if($this->has('CreateResource', $uid))
01348 return true;
01349
01350 return false;
01351 }
01352
01353
01354
01362 public function mayCreateVersion($uid = '') {
01363 if(!$this->checkValid()) return false;
01364
01365 if($uid == '')
01366 $uid = Snap2::getCurrentUser();
01367
01368 if(self::isSpecialUser(self::USER_ADMIN, $uid))
01369 return true;
01370
01371 if($this->has('CreateVersion', $uid))
01372 return true;
01373
01374 return false;
01375 }
01376
01377
01378
01386 public function mayUpdate($uid = '') {
01387 if(!$this->checkValid()) return false;
01388
01389 if($uid == '')
01390 $uid = Snap2::getCurrentUser();
01391
01392 if(self::isSpecialUser(self::USER_ADMIN, $uid))
01393 return true;
01394
01395 if($this->has('UpdateVersion', $uid))
01396 return true;
01397
01398 return false;
01399 }
01400
01408 public function maySubmit($uid = '') {
01409 if(!$this->checkValid()) return false;
01410
01411 if($uid == '')
01412 $uid = Snap2::getCurrentUser();
01413
01414 if(self::isSpecialUser(self::USER_ADMIN, $uid))
01415 return true;
01416
01417 if($this->has('SubmitVersion', $uid))
01418 return true;
01419
01420 return false;
01421 }
01422
01430 public function mayApproveForDev($uid = '') {
01431 if(!$this->checkValid()) return false;
01432
01433 if($uid == '')
01434 $uid = Snap2::getCurrentUser();
01435
01436 if(self::isSpecialUser(self::USER_ADMIN, $uid))
01437 return true;
01438
01439 if($this->has('ApproveVersionDev', $uid))
01440 return true;
01441
01442 return false;
01443 }
01444
01452 public function mayApproveForLive($uid = '') {
01453 if(!$this->checkValid()) return false;
01454
01455 if($uid == '')
01456 $uid = Snap2::getCurrentUser();
01457
01458 if(self::isSpecialUser(self::USER_ADMIN, $uid))
01459 return true;
01460
01461 if($this->has('ApproveVersionLive', $uid))
01462 return true;
01463
01464 return false;
01465 }
01466
01482 public function mayDefunct($status, $uid = '') {
01483 if(!$this->checkValid()) return false;
01484
01485 if($uid == '')
01486 $uid = Snap2::getCurrentUser();
01487
01488 if(self::isSpecialUser(self::USER_ADMIN, $uid))
01489 return true;
01490
01491 switch($status) {
01492 case SnapVersion::STATUS_PRIVATE:
01493 if($this->has('UpdateVersion', $uid) &&
01494 $this->has('DefunctVersion', $uid))
01495 return true;
01496 break;
01497 case SnapVersion::STATUS_PENDING:
01498 if($this->has('SubmitVersion', $uid) &&
01499 $this->has('DefunctVersion', $uid))
01500 return true;
01501 break;
01502 case SnapVersion::STATUS_DEV:
01503 if($this->has('ApproveVersionDev', $uid) &&
01504 $this->has('DefunctVersion', $uid))
01505 return true;
01506 break;
01507 case SnapVersion::STATUS_LIVE:
01508 if($this->has('ApproveVersionLive', $uid) &&
01509 $this->has('DefunctVersion', $uid))
01510 return true;
01511 break;
01512 }
01513
01514 return false;
01515 }
01516
01524 public function mayDestroyVersion($uid = '') {
01525 if(!$this->checkValid()) return false;
01526
01527 if($uid == '')
01528 $uid = Snap2::getCurrentUser();
01529
01530 if(self::isSpecialUser(self::USER_ADMIN, $uid)
01531 || self::isSpecialUser(self::USER_DESTROY, $uid))
01532 return true;
01533
01534 if($this->has('DestroyVersion', $uid))
01535 return true;
01536
01537 return false;
01538 }
01539
01547 public function mayDeny($uid = '') {
01548 if(!$this->checkValid()) return false;
01549
01550 if($uid == '')
01551 $uid = Snap2::getCurrentUser();
01552
01553 if(self::isSpecialUser(self::USER_ADMIN, $uid))
01554 return true;
01555
01556 if($this->has('DenyVersion', $uid))
01557 return true;
01558
01559 return false;
01560 }
01561
01569 public function maySteal($uid = '') {
01570 if(!$this->checkValid()) return false;
01571
01572 if($uid == '')
01573 $uid = Snap2::getCurrentUser();
01574
01575 if(self::isSpecialUser(self::USER_ADMIN, $uid))
01576 return true;
01577
01578 if($this->has('StealVersion', $uid))
01579 return true;
01580
01581 return false;
01582 }
01583
01584
01585
01586
01587
01594 public static function isSpecialUser($role, $uid = '') {
01595 if($uid == '')
01596 $uid = Snap2::getCurrentUser();
01597
01598 if(self::$SPECIAL_USERS == null)
01599 self::loadSpecialUsers();
01600
01601 return isset(self::$SPECIAL_USERS[$uid][$role]);
01602 }
01603
01608 public static function listSpecialUsers() {
01609 if(self::$SPECIAL_USERS == null)
01610 self::loadSpecialUsers();
01611
01612 return self::$SPECIAL_USERS;
01613 }
01614
01624 public static function grantPrivilege($role, $uid) {
01625 if(self::$SPECIAL_USERS == null)
01626 self::loadSpecialUsers();
01627
01628 if(!isset(self::$SPECIAL_USERS[Snap2::getCurrentUser()][self::USER_ADMIN])) {
01629 self::setStaticError('You do not have the privilege to grant other users privileges');
01630 return false;
01631 }
01632
01633 if($role != self::USER_ADMIN && $role != self::USER_DESTROY && $role != self::USER_RESTORE) {
01634 self::setStaticError('Invalid role');
01635 return false;
01636 }
01637
01638 if(isset(self::$SPECIAL_USERS[$uid][$role]))
01639 return true;
01640
01641 SnapCache::clearObjectCache('DirectoryUserPermission');
01642 SnapCache::clearObjectCache('DirectoryGroupPermission');
01643 SnapCache::clearObjectCache('ResourceUserPermission');
01644 SnapCache::clearObjectCache('ResourceGroupPermission');
01645 $permObjects = SnapCache::getObjectCache('Permission');
01646 foreach($permObjects as $p)
01647 $p->clearPermObjects();
01648
01649 SnapDBI::startTransaction();
01650 $query = "INSERT INTO SpecialUsers (uid, role) VALUES ('$uid', '$role')";
01651 if(!SnapDBI::query($query)) {
01652 SnapDBI::cancelTransaction();
01653 self::setStaticError('Invalid query');
01654 return false;
01655 }
01656 SnapPermissionCache::clearAll();
01657 SnapDBI::commitTransaction();
01658
01659 if(!isset(self::$SPECIAL_USERS[$uid]))
01660 self::$SPECIAL_USERS[$uid] = array();
01661 self::$SPECIAL_USERS[$uid][$role] = true;
01662
01663 return true;
01664 }
01665
01675 public static function revokePrivilege($role, $uid) {
01676 if(self::$SPECIAL_USERS == null)
01677 self::loadSpecialUsers();
01678
01679 if(!isset(self::$SPECIAL_USERS[Snap2::getCurrentUser()][self::USER_ADMIN])) {
01680 self::setStaticError('You do not have the privilege to grant other users privileges');
01681 return false;
01682 }
01683
01684 if($uid == Snap2::getCurrentUser() && $role == self::USER_ADMIN) {
01685 self::setStaticError('You cannot revoke your own admin privileges');
01686 return false;
01687 }
01688
01689 if($role != self::USER_ADMIN && $role != self::USER_DESTROY && $role != self::USER_RESTORE) {
01690 self::setStaticError('Invalid role');
01691 return false;
01692 }
01693
01694 if(!isset(self::$SPECIAL_USERS[$uid][$role]))
01695 return true;
01696
01697 SnapCache::clearObjectCache('DirectoryUserPermission');
01698 SnapCache::clearObjectCache('DirectoryGroupPermission');
01699 SnapCache::clearObjectCache('ResourceUserPermission');
01700 SnapCache::clearObjectCache('ResourceGroupPermission');
01701 $permObjects = SnapCache::getObjectCache('Permission');
01702 foreach($permObjects as $p)
01703 $p->clearPermObjects();
01704
01705 SnapDBI::startTransaction();
01706 $query = "DELETE FROM SpecialUsers WHERE uid = '$uid' AND role = '$role'";
01707 if(!SnapDBI::query($query)) {
01708 SnapDBI::cancelTransaction();
01709 self::setStaticError('Invalid query');
01710 return false;
01711 }
01712 SnapPermissionCache::clearAll();
01713 SnapDBI::commitTransaction();
01714
01715 unset(self::$SPECIAL_USERS[$uid][$role]);
01716
01717 return true;
01718 }
01719
01724 private static function loadSpecialUsers() {
01725 $query = "SELECT uid, role FROM SpecialUsers";
01726 if(!SnapDBI::query($query)) {
01727 self::setStaticError('Failed to load special users');
01728 return false;
01729 }
01730
01731 self::$SPECIAL_USERS = array();
01732 $numRows = SnapDBI::getNumRows();
01733 for($i = 0; $i < $numRows; $i++) {
01734 $row = SnapDBI::getRow();
01735 if(isset(self::$SPECIAL_USERS[$row['uid']]))
01736 self::$SPECIAL_USERS[$row['uid']][$row['role']] = true;
01737 else
01738 self::$SPECIAL_USERS[$row['uid']] = array($row['role'] => true);
01739 }
01740 SnapDBI::freeResult();
01741
01742 return true;
01743 }
01744
01750 public static function getCapabilities($type) {
01751 return SnapPermissionObject::getCapabilities($type);
01752 }
01753
01759 public static function getCapabilityDescriptions($type) {
01760 return SnapPermissionObject::getCapabilityDescriptions($type);
01761 }
01762 }
01763
01764 ?>