Commit 840b2ee01352c539ff8aad551c20cb1e57de51e3

Authored by Brad Shuttleworth
1 parent 8ca4a168

- add and enable caching (properly)

- enable document roles (DOUBLE CHECK YOUR DB)
- fix minor toggleselect bug.


git-svn-id: https://kt-dms.svn.sourceforge.net/svnroot/kt-dms/trunk@5125 c91229c3-7414-0410-bfa2-8a42b809f60b
config/cache-path 0 → 100644
  1 +var/cache
... ...
config/config.ini
... ... @@ -3,6 +3,8 @@
3 3 ; db section.
4 4 ; ----------------------------------------------------------------
5 5  
  6 +; logLevel = DEBUG
  7 +
6 8 [db]
7 9 ; The Database Engine to use. Currently mysql is the only
8 10 ; supported type.
... ... @@ -25,6 +27,7 @@ dbAdminPass = js9281djw
25 27 ; need to, as you may introduce errors in your system.
26 28 ; ----------------------------------------------------------------
27 29  
  30 +
28 31 ; install path (file path)
29 32 ;
30 33 ; Leave as default to have it automatically detected.
... ... @@ -168,4 +171,4 @@ restrictAdminPasswords = default
168 171  
169 172 [cache]
170 173 cacheDirectory = ${varDirectory}/cache
171   -cacheEnabled = false
  174 +cacheEnabled = true
... ...
config/dmsDefaults.php
... ... @@ -23,6 +23,9 @@
23 23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 24 */
25 25  
  26 +// DEBUG DEBUG DEBUG APD
  27 +//if (extension_loaded('APD')) { apd_set_pprof_trace(); }
  28 +
26 29 // Default settings differ, we need some of these, so force the matter.
27 30 // Can be overridden here if actually necessary.
28 31 error_reporting(E_ALL & ~E_NOTICE);
... ... @@ -54,6 +57,8 @@ if (!defined('PATH_SEPARATOR')) {
54 57 }
55 58 }
56 59  
  60 +require_once(KT_LIB_DIR . '/Log.inc');
  61 +
57 62 // {{{ KTInit
58 63 class KTInit {
59 64 // {{{ prependPath()
... ... @@ -350,6 +355,84 @@ class KTInit {
350 355 return "";
351 356 }
352 357 // }}}
  358 +
  359 + // {{{ initConfig
  360 + function initConfig() {
  361 + global $default;
  362 + $use_cache = false;
  363 + $store_cache = false;
  364 + if (file_exists(KT_DIR . "/config/cache-path")) {
  365 + $store_cache = true;
  366 + $user = KTLegacyLog::running_user();
  367 + $cache_file = trim(file_get_contents(KT_DIR . "/config/cache-path")) . '/configcache' . $user;
  368 + if (!KTUtil::isAbsolutePath($cache_file)) { $cache_file = sprintf("%s/%s", KT_DIR, $cache_file); }
  369 + $config_file = trim(file_get_contents(KT_DIR . "/config/config-path"));
  370 + if (!KTUtil::isAbsolutePath($config_file)) { $config_file = sprintf("%s/%s", KT_DIR, $config_file); }
  371 +
  372 + $exists = file_exists($cache_file);
  373 + if ($exists) {
  374 + $cachestat = stat($cache_file);
  375 + $configstat = stat($config_file);
  376 + $tval = 9;
  377 + // print sprintf("is %d > %d\n", $cachestat[$tval], $configstat[$tval]);
  378 + if ($cachestat[$tval] > $configstat[$tval]) {
  379 + $use_cache = true;
  380 + }
  381 + }
  382 +
  383 +
  384 + }
  385 +
  386 + if ($use_cache) {
  387 + $oKTConfig =& KTConfig::getSingleton();
  388 + $oKTConfig->loadCache($cache_file);
  389 +
  390 + foreach ($oKTConfig->flat as $k => $v) {
  391 + $default->$k = $v;
  392 + }
  393 + } else {
  394 + $oKTConfig =& KTConfig::getSingleton();
  395 +
  396 + $oKTConfig->setdefaultns("KnowledgeTree", "fileSystemRoot", KT_DIR);
  397 + $oKTConfig->setdefaultns("KnowledgeTree", "serverName", KTUtil::arrayGet($_SERVER, 'HTTP_HOST', 'localhost'));
  398 + $oKTConfig->setdefaultns("KnowledgeTree", "sslEnabled", false);
  399 + if (array_key_exists('HTTPS', $_SERVER)) {
  400 + if (strtolower($_SERVER['HTTPS']) === 'on') {
  401 + $oKTConfig->setdefaultns("KnowledgeTree", "sslEnabled", true);
  402 + }
  403 + }
  404 + $oKTConfig->setdefaultns("KnowledgeTree", "rootUrl", $this->guessRootUrl());
  405 + $oKTConfig->setdefaultns("KnowledgeTree", "execSearchPath", $_SERVER['PATH']);
  406 + $oKTConfig->setdefaultns("KnowledgeTree", "pathInfoSupport", false);
  407 + $oKTConfig->setdefaultns("storage", "manager", 'KTOnDiskPathStorageManager');
  408 + $oKTConfig->setdefaultns("config", "useDatabaseConfiguration", false);
  409 + $oKTConfig->setdefaultns("tweaks", "browseToUnitFolder", false);
  410 + $oKTConfig->setdefaultns("tweaks", "genericMetaDataRequired", true);
  411 + $oKTConfig->setdefaultns("tweaks", "phpErrorLogFile", false);
  412 + $oKTConfig->setdefaultns("tweaks", "developmentWindowLog", false);
  413 +
  414 + $oKTConfig->setdefaultns("user_prefs", "passwordLength", 6);
  415 + $oKTConfig->setdefaultns("user_prefs", "restrictAdminPasswords", false);
  416 +
  417 + $oKTConfig->setdefaultns("ui", "ieGIF", true);
  418 + $oKTConfig->setdefaultns("ui", "alwaysShowAll", false);
  419 + $oKTConfig->setdefaultns("ui", "condensedAdminUI", false);
  420 +
  421 + $oKTConfig->setdefaultns(null, "logLevel", 'INFO');
  422 + $oKTConfig->setdefaultns("import", "unzip", 'unzip');
  423 + $oKTConfig->setdefaultns("cache", "cacheDirectory", '${varDirectory}/cache');
  424 + $oKTConfig->setdefaultns("cache", "cacheEnabled", 'false');
  425 +
  426 + $this->readConfig();
  427 +
  428 + $oKTConfig =& KTConfig::getSingleton();
  429 + if ($store_cache) { $oKTConfig->createCache($cache_file);}
  430 +
  431 +
  432 + }
  433 + }
  434 + // }}}
  435 +
353 436 // {{{ readConfig
354 437 function readConfig () {
355 438 global $default;
... ... @@ -367,6 +450,7 @@ class KTInit {
367 450 }
368 451 if ($v === "false") {
369 452 $v = false;
  453 +
370 454 }
371 455 if ($v === "true") {
372 456 $v = true;
... ... @@ -397,40 +481,8 @@ require_once(KT_LIB_DIR . '/util/ktutil.inc');
397 481  
398 482 require_once(KT_LIB_DIR . "/config/config.inc.php");
399 483  
  484 +$KTInit->initConfig();
400 485 $oKTConfig =& KTConfig::getSingleton();
401   -
402   -$oKTConfig->setdefaultns("KnowledgeTree", "fileSystemRoot", KT_DIR);
403   -$oKTConfig->setdefaultns("KnowledgeTree", "serverName", KTUtil::arrayGet($_SERVER, 'HTTP_HOST', 'localhost'));
404   -$oKTConfig->setdefaultns("KnowledgeTree", "sslEnabled", false);
405   -if (array_key_exists('HTTPS', $_SERVER)) {
406   - if (strtolower($_SERVER['HTTPS']) === 'on') {
407   - $oKTConfig->setdefaultns("KnowledgeTree", "sslEnabled", true);
408   - }
409   -}
410   -$oKTConfig->setdefaultns("KnowledgeTree", "rootUrl", $KTInit->guessRootUrl());
411   -$oKTConfig->setdefaultns("KnowledgeTree", "execSearchPath", $_SERVER['PATH']);
412   -$oKTConfig->setdefaultns("KnowledgeTree", "pathInfoSupport", false);
413   -$oKTConfig->setdefaultns("storage", "manager", 'KTOnDiskPathStorageManager');
414   -$oKTConfig->setdefaultns("config", "useDatabaseConfiguration", false);
415   -$oKTConfig->setdefaultns("tweaks", "browseToUnitFolder", false);
416   -$oKTConfig->setdefaultns("tweaks", "genericMetaDataRequired", true);
417   -$oKTConfig->setdefaultns("tweaks", "phpErrorLogFile", false);
418   -$oKTConfig->setdefaultns("tweaks", "developmentWindowLog", false);
419   -
420   -$oKTConfig->setdefaultns("user_prefs", "passwordLength", 6);
421   -$oKTConfig->setdefaultns("user_prefs", "restrictAdminPasswords", false);
422   -
423   -$oKTConfig->setdefaultns("ui", "ieGIF", true);
424   -$oKTConfig->setdefaultns("ui", "alwaysShowAll", false);
425   -$oKTConfig->setdefaultns("ui", "condensedAdminUI", false);
426   -
427   -$oKTConfig->setdefaultns(null, "logLevel", 'INFO');
428   -$oKTConfig->setdefaultns("import", "unzip", 'unzip');
429   -$oKTConfig->setdefaultns("cache", "cacheDirectory", '${varDirectory}/cache');
430   -$oKTConfig->setdefaultns("cache", "cacheEnabled", 'false');
431   -
432   -$KTInit->readConfig();
433   -
434 486 $KTInit->setupServerVariables();
435 487  
436 488 // instantiate log
... ...
config/tableMappings.inc
... ... @@ -143,6 +143,7 @@ $default->notifications_table = "notifications";
143 143 $default->authentication_sources_table = "authentication_sources";
144 144 $default->dashlet_disable_table = "dashlet_disables";
145 145 $default->role_allocations_table = "role_allocations";
  146 +$default->document_role_allocations_table = "document_role_allocations";
146 147 $default->plugins_table = "plugins";
147 148 $default->document_metadata_version_table = "document_metadata_version";
148 149 $default->document_content_version_table = "document_content_version";
... ...
lib/cache/cache.inc.php
... ... @@ -10,6 +10,15 @@ class KTCache {
10 10 }
11 11 // }}}
12 12  
  13 + // takes an Entity type-name, and an array of the failed attrs.
  14 + function alertFailure($sEntityType, $aFail) {
  15 + //var_dump($aFail);
  16 + $sMessage = sprintf('Failure in cache-comparison on type "%s": %s', $sEntityType, implode(', ', $aFail));
  17 + global $default;
  18 + $default->log->error($sMessage);
  19 + $_SESSION['KTErrorMessage'][] = $sMessage;
  20 + }
  21 +
13 22 function KTCache() {
14 23 require_once("Cache/Lite.php");
15 24 require_once(KT_LIB_DIR . '/config/config.inc.php');
... ...
lib/config/config.inc.php
... ... @@ -37,6 +37,38 @@ class KTConfig {
37 37 var $flat = array();
38 38 var $flatns = array();
39 39  
  40 + // FIXME nbm: how do we cache errors here?
  41 + function loadCache($filename) {
  42 + $config_str = file_get_contents($filename);
  43 + $config_cache = unserialize($config_str);
  44 + $this->flat = $config_cache['flat'];
  45 + $this->flatns = $config_cache['flatns'];
  46 + $this->expanded = $config_cache['expanded'];
  47 + $this->expanding = $config_cache['expanding'];
  48 + /*
  49 + print "----- Me\n";
  50 + unset($this->aFileRoot);
  51 + unset($this->aSectionFile);
  52 + var_dump($this);
  53 + print "----- Cache\n";
  54 + var_dump($config_cache);
  55 + */
  56 +
  57 + return true;
  58 + }
  59 +
  60 + function createCache($filename) {
  61 + $config_cache = array();
  62 + $config_cache['flat'] = $this->flat;
  63 + $config_cache['flatns'] = $this->flatns;
  64 + $config_cache['expanded'] = $this->expanded;
  65 + $config_cache['expanding'] = $this->expanding;
  66 +
  67 + file_put_contents($filename, serialize($config_cache));
  68 +
  69 +
  70 + }
  71 +
40 72 function loadFile($filename, $bDefault = false) {
41 73 $c = new Config;
42 74 $root =& $c->parseConfig($filename, "IniCommented");
... ...
lib/documentmanagement/Document.inc
... ... @@ -69,6 +69,9 @@ class Document {
69 69 function getCreatorID() { return $this->_oDocumentCore->getCreatorId(); }
70 70 function setCreatorID($iNewValue) { $this->_oDocumentCore->setCreatorId($iNewValue); }
71 71  
  72 + function getOwnerID() { return $this->_oDocumentCore->getOwnerId(); }
  73 + function setOwnerID($iNewValue) { $this->_oDocumentCore->setOwnerId($iNewValue); }
  74 +
72 75 function getLastModifiedDate() { return $this->_oDocumentCore->getLastModifiedDate(); }
73 76 function setLastModifiedDate($dNewValue) { $this->_oDocumentCore->setLastModifiedDate($dNewValue); }
74 77  
... ... @@ -418,6 +421,7 @@ class Document {
418 421 $oDocument = new Document();
419 422 $aOptions = array_change_key_case($aOptions);
420 423  
  424 +
421 425 $aCoreKeys = array(
422 426 "CreatorId",
423 427 "Created",
... ...
lib/documentmanagement/documentcore.inc.php
... ... @@ -73,6 +73,7 @@ class KTDocumentCore extends KTEntity {
73 73  
74 74 // transaction-related
75 75 "iCreatorId" => 'creator_id',
  76 +
76 77 "dCreated" => 'created',
77 78 "iModifiedUserId" => 'modified_user_id',
78 79 "dModified" => 'modified',
... ... @@ -92,6 +93,7 @@ class KTDocumentCore extends KTEntity {
92 93 // permission-related
93 94 "iPermissionObjectId" => 'permission_object_id',
94 95 "iPermissionLookupId" => 'permission_lookup_id',
  96 + "iOwnerId" => 'owner_id',
95 97 );
96 98  
97 99 function KTDocument() {
... ... @@ -100,6 +102,8 @@ class KTDocumentCore extends KTEntity {
100 102 // {{{ getters/setters
101 103 function getCreatorId() { return $this->iCreatorId; }
102 104 function setCreatorId($iNewValue) { $this->iCreatorId = $iNewValue; }
  105 + function getOwnerId() { return $this->iOwnerId; }
  106 + function setOwnerId($iNewValue) { $this->iOwnerId = $iNewValue; }
103 107 function getCreatedDateTime() { return $this->dCreated; }
104 108 function getModifiedUserId() { return $this->iModifiedUserId; }
105 109 function setModifiedUserId($iNewValue) { $this->iModifiedUserId = $iNewValue; }
... ... @@ -142,28 +146,11 @@ class KTDocumentCore extends KTEntity {
142 146  
143 147 // {{{ ktentity requirements
144 148 function _fieldValues () {
145   - $this->sFullPath = KTDocumentCore::_generateFolderPath($this->iFolderId);
146   - $this->sParentFolderIds = KTDocumentCore::_generateFolderIds($this->iFolderId);
  149 + $this->sFullPath = Folder::generateFolderPath($this->iFolderId);
  150 + $this->sParentFolderIds = Folder::generateFolderIds($this->iFolderId);
147 151 return parent::_fieldValues();
148 152 }
149 153  
150   - /**
151   - * Recursive function to generate a comma delimited string containing
152   - * the parent folder ids
153   - *
154   - * @return String comma delimited string containing the parent folder ids
155   - */
156   - function _generateParentFolderIds($iFolderId) {
157   - $sTable = KTUtil::getTableName('folders');
158   - if (empty($iFolderId)) {
159   - return;
160   - }
161   -
162   - $sQuery = sprintf('SELECT parent_id FROM %s WHERE id = ?', $sTable);
163   - $aParams = array($iFolderId);
164   - $iParentId = DBUtil::getOneResultKey(array($sQuery, $aParams), 'parent_id');
165   - return KTDocumentCore::_generateParentFolderIds($iParentId) . ",$iFolderId";
166   - }
167 154  
168 155 /**
169 156 * Returns a comma delimited string containing the parent folder ids, strips leading /
... ... @@ -195,9 +182,12 @@ class KTDocumentCore extends KTEntity {
195 182 * Returns a forward slash deliminated string giving full path of document, strips leading /
196 183 */
197 184 function _generateFolderPath($iFolderId) {
  185 + return Folder::generateFolderPath($iFolderId);
  186 +/*
198 187 $sPath = KTDocumentCore::_generateFullFolderPath($iFolderId);
199 188 $sPath = substr($sPath, 1, strlen($sPath));
200 189 return $sPath;
  190 +*/
201 191 }
202 192 // }}}
203 193  
... ... @@ -212,6 +202,9 @@ class KTDocumentCore extends KTEntity {
212 202 if (empty($this->iModifiedUserId)) {
213 203 $this->iModifiedUserId = $this->iCreatorId;
214 204 }
  205 + if (empty($this->iOwnerId)) {
  206 + $this->iOwnerId = $this->iCreatorId;
  207 + }
215 208 if (empty($this->iMetadataVersion)) {
216 209 $this->iMetadataVersion = 0;
217 210 }
... ... @@ -221,7 +214,7 @@ class KTDocumentCore extends KTEntity {
221 214 $oFolder = Folder::get($this->getFolderId());
222 215 $this->iPermissionObjectId = $oFolder->getPermissionObjectId();
223 216 $res = parent::create();
224   -
  217 +
225 218 if ($res === true) {
226 219 KTPermissionUtil::updatePermissionLookup($this);
227 220 }
... ...
lib/documentmanagement/documentutil.inc.php
... ... @@ -185,7 +185,7 @@ class KTDocumentUtil {
185 185 return $res;
186 186 }
187 187 } else {
188   - $oUploadChannel->sendMessage(new KTUploadGenericMessage(_("Storing contents")));
  188 + // $oUploadChannel->sendMessage(new KTUploadGenericMessage(_("Storing contents")));
189 189 $res = KTDocumentUtil::storeContents($oDocument, $oContents, $aOptions);
190 190 if (PEAR::isError($res)) {
191 191 $oDocument->delete();
... ... @@ -200,7 +200,7 @@ class KTDocumentUtil {
200 200 return $res;
201 201 }
202 202 } else {
203   - $oUploadChannel->sendMessage(new KTUploadGenericMessage(_("Saving metadata")));
  203 + // $oUploadChannel->sendMessage(new KTUploadGenericMessage(_("Saving metadata")));
204 204 $res = KTDocumentUtil::saveMetadata($oDocument, $aMetadata);
205 205 if (PEAR::isError($res)) {
206 206 $oDocument->delete();
... ... @@ -374,6 +374,16 @@ class KTDocumentUtil {
374 374  
375 375 // {{{ add
376 376 function &add($oFolder, $sFilename, $oUser, $aOptions) {
  377 + $GLOBALS['_IN_ADD'] = true;
  378 + $ret = KTDocumentUtil::_in_add($oFolder, $sFilename, $oUser, $aOptions);
  379 + unset($GLOBALS['_IN_ADD']);
  380 + return $ret;
  381 + }
  382 + // }}}
  383 +
  384 +
  385 + // {{{ _in_add
  386 + function &_in_add($oFolder, $sFilename, $oUser, $aOptions) {
377 387 if (KTDocumentUtil::fileExists($oFolder, $sFilename)) {
378 388 $oDoc = Document::getByFilenameAndFolder($sFilename, $oFolder->getId());
379 389 if (PEAR::isError($oDoc)) {
... ... @@ -403,12 +413,12 @@ class KTDocumentUtil {
403 413 $oUploadChannel =& KTUploadChannel::getSingleton();
404 414 $oUploadChannel->sendMessage(new KTUploadNewFile($sFilename));
405 415 $oDocument =& KTDocumentUtil::_add($oFolder, $sFilename, $oUser, $aOptions);
406   - $oUploadChannel->sendMessage(new KTUploadGenericMessage(_("Document created")));
  416 + // $oUploadChannel->sendMessage(new KTUploadGenericMessage(_("Document created")));
407 417 if (PEAR::isError($oDocument)) {
408 418 return $oDocument;
409 419 }
410 420  
411   - $oUploadChannel->sendMessage(new KTUploadGenericMessage(_("Scanning file")));
  421 + // $oUploadChannel->sendMessage(new KTUploadGenericMessage(_("Scanning file")));
412 422 $oKTTriggerRegistry = KTTriggerRegistry::getSingleton();
413 423 $aTriggers = $oKTTriggerRegistry->getTriggers('content', 'scan');
414 424 $iTrigger = 0;
... ... @@ -416,7 +426,7 @@ class KTDocumentUtil {
416 426 $sTrigger = $aTrigger[0];
417 427 $oTrigger = new $sTrigger;
418 428 $oTrigger->setDocument($oDocument);
419   - $oUploadChannel->sendMessage(new KTUploadGenericMessage(sprintf(_(" (trigger %s)"), $sTrigger)));
  429 + // $oUploadChannel->sendMessage(new KTUploadGenericMessage(sprintf(_(" (trigger %s)"), $sTrigger)));
420 430 $ret = $oTrigger->scan();
421 431 if (PEAR::isError($ret)) {
422 432 $oDocument->delete();
... ... @@ -434,11 +444,11 @@ class KTDocumentUtil {
434 444 }
435 445 $oTrigger = new $sTrigger;
436 446 $oTrigger->setDocument($oDocument);
437   - $oUploadChannel->sendMessage(new KTUploadGenericMessage(sprintf(_(" (trigger %s)"), $sTrigger)));
  447 + // $oUploadChannel->sendMessage(new KTUploadGenericMessage(sprintf(_(" (trigger %s)"), $sTrigger)));
438 448 $oTrigger->transform();
439 449 }
440 450  
441   - $oUploadChannel->sendMessage(new KTUploadGenericMessage(_("Creating transaction")));
  451 + // $oUploadChannel->sendMessage(new KTUploadGenericMessage(_("Creating transaction")));
442 452 $aOptions = array('user' => $oUser);
443 453 //create the document transaction record
444 454 $oDocumentTransaction = & new DocumentTransaction($oDocument, "Document created", 'ktcore.transactions.create', $aOptions);
... ... @@ -448,7 +458,7 @@ class KTDocumentUtil {
448 458 return $res;
449 459 }
450 460  
451   - $oUploadChannel->sendMessage(new KTUploadGenericMessage(_("Sending subscriptions")));
  461 + // $oUploadChannel->sendMessage(new KTUploadGenericMessage(_("Sending subscriptions")));
452 462 // fire subscription alerts for the checked in document
453 463 $oSubscriptionEvent = new SubscriptionEvent();
454 464 $oFolder = Folder::get($oDocument->getFolderID());
... ... @@ -467,6 +477,7 @@ class KTDocumentUtil {
467 477 $ret = $oTrigger->postValidate();
468 478  
469 479 }
  480 + KTDocumentUtil::updateSearchableText($oDocument, true);
470 481  
471 482 $oUploadChannel->sendMessage(new KTUploadGenericMessage(_("All done...")));
472 483  
... ... @@ -533,7 +544,10 @@ class KTDocumentUtil {
533 544 // }}}
534 545  
535 546 // {{{ updateSearchableText
536   - function updateSearchableText($oDocument) {
  547 + function updateSearchableText($oDocument, $bOverride = false) {
  548 + if (isset($GLOBALS['_IN_ADD']) && empty($bOverride)) {
  549 + return;
  550 + }
537 551 $oDocument = KTUtil::getObject('Document', $oDocument);
538 552 $iDocumentId = $oDocument->getId();
539 553 $sTable = KTUtil::getTableName('document_transaction_text');
... ...
lib/foldermanagement/Folder.inc
... ... @@ -101,33 +101,31 @@ class Folder extends KTEntity {
101 101 return $res;
102 102 }
103 103 // }}}
104   - /**
105   - * Recursive function to generate a comma delimited string containing
106   - * the parent folder ids
107   - *
108   - * @return String comma delimited string containing the parent folder ids
109   - */
110   - function generateParentFolderIDS($iFolderID) {
111   - global $default;
112   - //if the folder is not the root folder
113   - if ($iFolderID != 0) {
114   - $sql = $default->db;
115   - $sql->query(array("SELECT parent_id FROM $default->folders_table WHERE ID = ?", $iFolderID));/*ok*/
116   - $sql->next_record();
117   - return Folder::generateParentFolderIDS($sql->f("parent_id")) . ",$iFolderID";
118   - }
119   - return;
120   -
121   - }
122   -
  104 +
123 105 /**
124 106 * Returns a comma delimited string containing the parent folder ids, strips leading /
125 107 *
126 108 * @return String comma delimited string containing the parent folder ids
127 109 */
128   - function generateFolderIDs($iFolderID) {
129   - $sFolderIDs = Folder::generateParentFolderIDS($iFolderID);
130   - return substr($sFolderIDs, 1, strlen($sFolderIDs));
  110 + function generateFolderIDs($iFolderId) {
  111 + if (empty($iFolderId)) {
  112 + return;
  113 + }
  114 + $oFolder =& Folder::get($iFolderId);
  115 + if (PEAR::isError($oFolder)) {
  116 + return $oFolder;
  117 + }
  118 +
  119 + $iParentId = $oFolder->getParentId();
  120 + if (empty($iParentId)) {
  121 + return $oFolder->getId();
  122 + }
  123 + $oParentFolder =& Folder::get($iParentId);
  124 + $sParentFolderParentFolderIds = $oParentFolder->getParentFolderIDs();
  125 + if (empty($sParentFolderParentFolderIds)) {
  126 + return sprintf('%s,%s', $iParentId, $oFolder->getId());;
  127 + }
  128 + return sprintf('%s,%s,%s', $sParentFolderParentFolderIds, $iParentId, $oFolder->getId());
131 129 }
132 130  
133 131 /**
... ... @@ -212,12 +210,9 @@ class Folder extends KTEntity {
212 210 global $default;
213 211 //get the direct children
214 212 $sql = $default->db;
215   - $sql->query(array("SELECT id from $default->folders_table WHERE parent_id = ?", $iId));/*ok*/
216   - while ($sql->next_record()) {
217   - //force an update, this will cause this child's children to be updated
218   - $oFolder = Folder::get($sql->f("id"));
  213 + $aFolders =& Folder::getByParentId($iId);
  214 + foreach ($aFolders as $oFolder) {
219 215 $oFolder->update(true);
220   -
221 216 }
222 217 return;
223 218 }
... ... @@ -260,6 +255,13 @@ class Folder extends KTEntity {
260 255 Folder::getChildren($sql->f("id"), $aChildren);
261 256 }
262 257 return $aChildren;
  258 + /*
  259 + $oFolder = Folder::get($iFolderID);
  260 + $path = $oFolder->getParentFolderIds() . ',' . $oFolder->getId();
  261 + return Folder::getList(array(
  262 + sprintf('(parent_folder_ids = "%s" OR parent_folder_ids LIKE "%s,%%")', $path, $path),
  263 + ));
  264 + */
263 265 }
264 266  
265 267 /**
... ... @@ -412,11 +414,8 @@ class Folder extends KTEntity {
412 414 */
413 415 function getParentFolderID($iFolderID) {
414 416 if ($iFolderID != 0) {
415   - global $default;
416   - $sql = $default->db;
417   - $sql->query(array("SELECT parent_id FROM " . $default->folders_table . " WHERE id = ?", $iFolderID));/*ok*/
418   - $sql->next_record();
419   - return $sql->f("parent_id");
  417 + $oFolder = Folder::get($iFolderID);
  418 + return $oFolder->getParentFolderID();
420 419 }
421 420 return 0;
422 421 }
... ... @@ -503,6 +502,12 @@ class Folder extends KTEntity {
503 502 'permission_lookup_id' => $iLookupID,
504 503 ), array('multi' => true));
505 504 }
  505 +
  506 + function getByParentId($iParentID) {
  507 + return KTEntityUtil::getByDict('Folder', array(
  508 + 'parent_id' => $iParentID,
  509 + ), array('multi' => true));
  510 + }
506 511  
507 512 // STATIC
508 513 function &createFromArray($aOptions) {
... ...
lib/ktentity.inc
... ... @@ -26,8 +26,15 @@
26 26 * @package lib
27 27 */
28 28  
  29 +$_LCASECACHE = array();
  30 +$_OBJECTCACHE = array();
  31 +$_RANDOMCALL = 0;
  32 +$_STOPCACHING = array();
  33 +
29 34 require_once(KT_LIB_DIR . '/cache/cache.inc.php');
30 35  
  36 +DEFINE("EVIL_CACHE_GRIND", false);
  37 +
31 38 class KTEntity {
32 39 var $_bUsePearError = false;
33 40 /** object primary key */
... ... @@ -41,18 +48,34 @@ class KTEntity {
41 48 return array('getlist');
42 49 }
43 50  
44   - function clearCachedGroups() {
45   - $groups = $this->_cachedGroups();
  51 + function _innerClearCachedGroups($sClassName) {
  52 + if ($GLOBALS['_STOPCACHING'][$sClassName]) {
  53 + if ($GLOBALS['_STOPCACHING'][$sClassName] > 5) {
  54 + return;
  55 + }
  56 + } else {
  57 + $GLOBALS['_STOPCACHING'][$sClassName] = 0;
  58 + }
  59 + $group_func = array($sClassName, '_cachedGroups');
  60 + $groups = call_user_func($group_func);
  61 + $groups[] = 'auto';
46 62 $oCache =& KTCache::getSingleton();
47   - $aSuffixes = array('', '_count', '_fullselect');
  63 + $aSuffixes = array(''); // , '_count', '_fullselect');
48 64 foreach ($groups as $group_base) {
49 65 global $default;
50 66 foreach ($aSuffixes as $sSuffix) {
51   - $group = sprintf("%s/%s%s", get_class($this), $group_base, $sSuffix);
  67 + $group = sprintf("%s/%s%s", $sClassName, $group_base, $sSuffix);
52 68 $default->log->debug("Clearing cached group: $group");
53 69 $oCache->clear($group);
54 70 }
55 71 }
  72 + $GLOBALS['_STOPCACHING'][$sClassName]++;
  73 +
  74 + }
  75 +
  76 + function clearCachedGroups() {
  77 + $sClass = get_class($this);
  78 + $this->_innerClearCachedGroups($sClass);
56 79 }
57 80  
58 81 /**
... ... @@ -143,27 +166,73 @@ class KTEntity {
143 166 }
144 167  
145 168 function load($iId = null) {
  169 + global $default;
146 170 if (is_null($iId)) {
147 171 if (is_null($this->iId)) {
148 172 return PEAR::raiseError("No ID given");
149 173 }
150 174 $iId = $this->iId;
151 175 }
152   - $table = $this->_table();
153   - $select = $this->_getSqlSelection();
154   - $sQuery = "SELECT $select FROM $table WHERE id = ?";
155   - $aParams = array($iId);
156   -
157   - $res = DBUtil::getResultArray(array($sQuery, $aParams));
158   -
159   - if (PEAR::isError($res)) {
160   - return $res;
161   - }
162   - if (count($res) === 0) {
163   - return PEAR::raiseError("No such ID: $iId");
164   - }
165   - if (count($res) > 1) {
166   - return PEAR::raiseError("Multiple matches for ID: $iId");
  176 + $sClassName = get_class($this);
  177 + // cache at lowest possible level.
  178 + $oCache =& KTCache::getSingleton();
  179 + $group = sprintf("%s/%s", $sClassName , 'id');
  180 + list($bCached, $mCached) = $oCache->get($group, $iId);
  181 + if ($bCached && EVIL_CACHE_GRIND) {
  182 + $default->log->debug(sprintf("Found and testing object cache for class %s, id %d", $sClassName, $iId));
  183 +
  184 + $table = $this->_table();
  185 + $select = $this->_getSqlSelection();
  186 + $sQuery = "SELECT $select FROM $table WHERE id = ?";
  187 + $aParams = array($iId);
  188 +
  189 + $res = DBUtil::getResultArray(array($sQuery, $aParams));
  190 + // we _have_ a cache: error is a disaster
  191 + if (PEAR::isError($res) || (count($res) === 0) || (count($res) > 1)) {
  192 + $oCache->alertFailure($sClassName, array('<strong>SERIOUS FAILURE:</strong> real object is an error, cache claims "valid".'));
  193 + return $res;
  194 + }
  195 +
  196 + // now compare the sub-values.
  197 + $aFailures = array();
  198 + $sEntClass = get_class($this);
  199 +
  200 + foreach (array_keys($res) as $sKey => $sVal) {
  201 + if ($mCached[$sKey] != $res[$sKey]) {
  202 + $aFailures[] = $sKey;
  203 + }
  204 + }
  205 +
  206 + if (!empty($aFailures)) {
  207 + $oCache->alertFailure($sClassName, $aFailures);
  208 + }
  209 +
  210 + $res = $mCached;
  211 + } else if ($bCached) {
  212 + global $default;
  213 + $default->log->debug(sprintf("Using object cache for class %s, id %d", $sClassName, $iId));
  214 + $res = $mCached;
  215 + /* */
  216 + } else {
  217 + $default->log->debug(sprintf("No object cache for class %s, id %d", $sClassName, $iId));
  218 + $table = $this->_table();
  219 + $select = $this->_getSqlSelection();
  220 + $sQuery = "SELECT $select FROM $table WHERE id = ?";
  221 + $aParams = array($iId);
  222 +
  223 + $res = DBUtil::getResultArray(array($sQuery, $aParams));
  224 +
  225 + if (PEAR::isError($res)) {
  226 + return $res;
  227 + }
  228 + if (count($res) === 0) {
  229 + return PEAR::raiseError("No such ID: $iId");
  230 + }
  231 +
  232 + if (count($res) > 1) {
  233 + return PEAR::raiseError("Multiple matches for ID: $iId");
  234 + }
  235 + $oCache->set($group, $iId, $res); // finally, cache if its "good".
167 236 }
168 237 $vk = array_flip($this->_aFieldToSelect);
169 238 $aLoadInfo = array();
... ... @@ -208,26 +277,43 @@ class KTEntity {
208 277 //
209 278 // If the element isn't in the case array, the method doesn't
210 279 // exist.
211   -
  280 + $sClassName = get_class($this);
  281 +
  282 + $aCache = KTUtil::arrayGet($GLOBALS['_LCASECACHE'], $sClassName);
  283 +
  284 + $sLowerElement = strtolower($sElement);
  285 + if ($aCache) {
  286 + $r = KTUtil::arrayGet($aCache['fieldnames'], $sLowerElement);
  287 + if ($r) { return $r; }
  288 + }
  289 +
212 290 $array = array_keys($this->_aFieldToSelect);
213 291  
214   - foreach($array as $k) {
215   - $case[strtolower($k)] = $k;
  292 + if (!$aCache) {
  293 + $case = array();
  294 + foreach($array as $k) {
  295 + $case[strtolower($k)] = $k;
  296 + }
  297 + foreach($case as $k => $v) {
  298 + $case[substr($k, 1)] = $v;
  299 + }
  300 + } else {
  301 + $case = $aCache['fieldnames'];
216 302 }
217 303  
218   - $sElement = strtolower($sElement);
219   -
220   - if (array_key_exists($sElement, $case)) {
221   - return $case[strtolower($sElement)];
  304 + //var_dump($case);
  305 +
  306 + if (!$aCache) {
  307 + $aCache = array();
  308 + $aCache['fieldnames'] = $case;
222 309 }
223   -
224   - foreach($array as $k) {
225   - $case[substr(strtolower($k), 1)] = $k;
  310 +
  311 + $GLOBALS['_LCASECACHE'][$sClassName] =& $aCache;
  312 +
  313 + if (array_key_exists($sLowerElement, $case)) {
  314 + return $case[$sLowerElement];
226 315 }
227 316  
228   - if (array_key_exists($sElement, $case)) {
229   - return $case[strtolower($sElement)];
230   - }
231 317 return PEAR::raiseError("No such element");
232 318 }
233 319  
... ... @@ -275,14 +361,29 @@ class KTEntityUtil {
275 361 $bIDs = KTUtil::arrayGet($aOptions, "ids", false);
276 362 $sIDField = 'id';
277 363 $cache = KTUtil::arrayGet($aOptions, 'cache', false);
  364 +
  365 + if (!$cache) { // && EVIL_CACHE_GRIND) {
  366 + $cache = 'auto';
  367 + }
  368 +
  369 + if (isset($GLOBALS['_STOPCACHING'][$sClassName])) {
  370 + if ($GLOBALS['_STOPCACHING'][$sClassName] > 5) {
  371 + $cache = false;
  372 + }
  373 + }
  374 +
  375 +
278 376 $fullselect = KTUtil::arrayGet($aOptions, 'fullselect', false);
  377 +
279 378 if ($cache) {
280   - if (is_array($sWhereClause)) {
  379 + if ($cache === 'auto') {
  380 + $vals = serialize($sWhereClause);
  381 + } else if (is_array($sWhereClause)) {
281 382 $vals = serialize($sWhereClause[1]);
282 383 } else {
283 384 $vals = serialize($sWhereClause);
284 385 }
285   - $default->log->debug(sprintf("Trying object cache for class %s, %s: %s", $sClassName, $cache, $vals));
  386 + $default->log->debug(sprintf("Trying list cache for class %s, %s: %s", $sClassName, $cache, $vals));
286 387  
287 388 $oCache =& KTCache::getSingleton();
288 389 $suffix = '';
... ... @@ -294,8 +395,63 @@ class KTEntityUtil {
294 395 } else {
295 396 $bCached = false;
296 397 }
  398 +
  399 + if ($cache && !$bCached) {
  400 + global $default;
  401 + $default->log->debug(sprintf("No list cache for class %s, %s: %s", $sClassName, $cache, $vals));
  402 + }
  403 + if ($bCached && EVIL_CACHE_GRIND) {
  404 + if (!empty($fullselect)) {
  405 + $oObject = new $sClassName;
  406 + $select = $oObject->_getSqlSelection();
  407 + $sQuery = "SELECT $select FROM " . $sTable;/*ok*/
  408 + } else {
  409 + $sIDField = KTUtil::arrayGet($aOptions, "idfield", 'id');
  410 + $sQuery = "SELECT $sIDField FROM " . $sTable;/*ok*/
  411 + }
  412 + $aParams = array();
  413 + if (!is_null($sWhereClause)) {
  414 + if (is_string($sWhereClause)) {
  415 + if (substr($sWhereClause, 0, 5) != 'WHERE') {
  416 + if (substr($sWhereClause, 0, 5) != 'ORDER') {
  417 + $sQuery .= ' WHERE';
  418 + }
  419 + }
  420 + $sQuery .= ' ' . $sWhereClause;
  421 + } else if (is_array($sWhereClause)) {
  422 + if (substr($sWhereClause[0], 0, 5) != 'WHERE') {
  423 + if (substr($sWhereClause[0], 0, 5) != 'ORDER') {
  424 + $sQuery .= ' WHERE';
  425 + }
  426 + }
  427 + $sQuery .= ' ' . $sWhereClause[0];
  428 + $aParams = $sWhereClause[1];
  429 + } else {
  430 + return new PEAR_Error('Weird WhereClause passed');
  431 + }
  432 + }
  433 + $sOrderBy = KTUtil::arrayGet($aOptions, 'orderby');
  434 + if (!empty($sOrderBy)) {
  435 + $sQuery .= " ORDER BY " . $sOrderBy;
  436 + }
297 437  
298   - if ($bCached) {
  438 + if (!empty($fullselect)) {
  439 + $aIDs = DBUtil::getResultArray(array($sQuery, $aParams));
  440 + } else {
  441 + $aIDs = DBUtil::getResultArrayKey(array($sQuery, $aParams), $sIDField);
  442 + }
  443 + // compare mcached == $aIds
  444 +
  445 + if ($aIDs != $mCached) {
  446 + /*
  447 + print "==================\n\n\n\n\n";
  448 + var_dump($aIDs);
  449 + print "------\n";
  450 + var_dump($mCached);
  451 + */
  452 + $oCache->alertFailure($group, array('Stored IDS != Cache IDS'));
  453 + }
  454 + } else if ($bCached) {
299 455 $default->log->debug(sprintf("Using object cache for class %s, %s: %s", $sClassName, $cache, $vals));
300 456 $aIDs = $mCached;
301 457 /* */
... ... @@ -401,15 +557,11 @@ class KTEntityUtil {
401 557 if (PEAR::isError($ret)) {
402 558 return $ret;
403 559 }
404   - $oCache =& KTCache::getSingleton();
405   - $group = sprintf("%s/%s", $sClassName, 'id');
406   - $oCache->set($group, $oObject->getId(), $oObject);
407 560 return $oObject;
408 561 }
409 562  
410 563 function &loadFromArrayMulti($sClassName, $aMultiArray, $aOptions = null) {
411 564 $aRet = array();
412   - $oCache =& KTCache::getSingleton();
413 565 foreach ($aMultiArray as $aArray) {
414 566 $oObject =& new $sClassName;
415 567 $ret = $oObject->loadFromArray($aArray);
... ... @@ -417,28 +569,19 @@ class KTEntityUtil {
417 569 return $ret;
418 570 }
419 571 $aRet[] = $oObject;
420   - $group = sprintf("%s/%s", $sClassName, 'id');
421   - $oCache->set($group, $oObject->getId(), $oObject);
422 572 }
423 573 return $aRet;
424 574 }
425 575  
426 576 function &get($sClassName, $iId) {
427   - $oCache =& KTCache::getSingleton();
428   - $group = sprintf("%s/%s", $sClassName, 'id');
429   - list($bCached, $mCached) = $oCache->get($group, $iId);
430   - if ($bCached) {
431   - global $default;
432   - $default->log->debug(sprintf("Using object cache for class %s, id %d", $sClassName, $iId));
433   - return $mCached;
434   - /* */
435   - }
  577 + $oObject =& KTUtil::arrayGet($GLOBALS['_OBJECTCACHE'][$sClassName], $iId);
  578 + if ($oObject) { return $oObject; }
436 579 $oObject =& new $sClassName;
437 580 $res = $oObject->load($iId);
438 581 if (PEAR::isError($res)) {
439 582 return $res;
440 583 }
441   - $oCache->set($group, $iId, $oObject);
  584 + $GLOBALS['_OBJECTCACHE'][$sClassName][$iId] =& $oObject;
442 585 return $oObject;
443 586 }
444 587  
... ...
lib/permissions/permissiondescriptor.inc.php
... ... @@ -28,6 +28,10 @@
28 28  
29 29 require_once(KT_LIB_DIR . "/ktentity.inc");
30 30  
  31 +$_PDGC = array();
  32 +$_PDRC = array();
  33 +$_PDUC = array();
  34 +
31 35 class KTPermissionDescriptor extends KTEntity {
32 36 /** primary key */
33 37 var $iId = -1;
... ... @@ -142,6 +146,7 @@ class KTPermissionDescriptor extends KTEntity {
142 146 // {{{ GROUPS
143 147 // {{{ _clearGroups
144 148 function _clearGroups() {
  149 + unset($GLOBALS['_PDGC'][$this->getId()]);
145 150 $sTable = KTUtil::getTableName('permission_descriptor_groups');
146 151 $sQuery = "DELETE FROM $sTable WHERE descriptor_id = ?";
147 152 $aParams = array($this->getID());
... ... @@ -188,10 +193,15 @@ class KTPermissionDescriptor extends KTEntity {
188 193  
189 194 // {{{ getGroups
190 195 function getGroups() {
  196 + if (isset($GLOBALS['_PDGC'][$this->getId()])) {
  197 + return $GLOBALS['_PDGC'][$this->getId()];
  198 + }
191 199 $sTable = KTUtil::getTableName('permission_descriptor_groups');
192 200 $sQuery = "SELECT group_id FROM $sTable WHERE descriptor_id = ?";
193 201 $aParams = array($this->getID());
194   - return DBUtil::getResultArrayKey(array($sQuery, $aParams), 'group_id');
  202 + $res = DBUtil::getResultArrayKey(array($sQuery, $aParams), 'group_id');
  203 + $GLOBALS['_PDGC'][$this->getId()] = $res;
  204 + return $res;
195 205 }
196 206 // }}}
197 207  
... ... @@ -245,6 +255,7 @@ class KTPermissionDescriptor extends KTEntity {
245 255 // {{{ ROLES
246 256 // {{{ _clearRoles
247 257 function _clearRoles() {
  258 + unset($GLOBALS['_PDRC'][$this->getId()]);
248 259 $sTable = KTUtil::getTableName('permission_descriptor_roles');
249 260 $sQuery = "DELETE FROM $sTable WHERE descriptor_id = ?";
250 261 $aParams = array($this->getID());
... ... @@ -291,10 +302,15 @@ class KTPermissionDescriptor extends KTEntity {
291 302  
292 303 // {{{ getRoles
293 304 function getRoles() {
  305 + if (isset($GLOBALS['_PDRC'][$this->getId()])) {
  306 + return $GLOBALS['_PDRC'][$this->getId()];
  307 + }
294 308 $sTable = KTUtil::getTableName('permission_descriptor_roles');
295 309 $sQuery = "SELECT role_id FROM $sTable WHERE descriptor_id = ?";
296 310 $aParams = array($this->getID());
297   - return DBUtil::getResultArrayKey(array($sQuery, $aParams), 'role_id');
  311 + $res = DBUtil::getResultArrayKey(array($sQuery, $aParams), 'role_id');
  312 + $GLOBALS['_PDRC'][$this->getId()] = $res;
  313 + return $res;
298 314 }
299 315 // }}}
300 316  
... ... @@ -348,6 +364,7 @@ class KTPermissionDescriptor extends KTEntity {
348 364 // {{{ USERS
349 365 // {{{ _clearUsers
350 366 function _clearUsers() {
  367 + unset($GLOBALS['_PDUC'][$this->getId()]);
351 368 $sTable = KTUtil::getTableName('permission_descriptor_users');
352 369 $sQuery = "DELETE FROM $sTable WHERE descriptor_id = ?";
353 370 $aParams = array($this->getID());
... ... @@ -394,10 +411,15 @@ class KTPermissionDescriptor extends KTEntity {
394 411  
395 412 // {{{ getUsers
396 413 function getUsers() {
  414 + if (isset($GLOBALS['_PDUC'][$this->getId()])) {
  415 + return $GLOBALS['_PDUC'][$this->getId()];
  416 + }
397 417 $sTable = KTUtil::getTableName('permission_descriptor_users');
398 418 $sQuery = "SELECT user_id FROM $sTable WHERE descriptor_id = ?";
399 419 $aParams = array($this->getID());
400   - return DBUtil::getResultArrayKey(array($sQuery, $aParams), 'user_id');
  420 + $res = DBUtil::getResultArrayKey(array($sQuery, $aParams), 'user_id');
  421 + $GLOBALS['_PDUC'][$this->getId()] = $res;
  422 + return $res;
401 423 }
402 424 // }}}
403 425  
... ...
lib/permissions/permissionutil.inc.php
... ... @@ -37,6 +37,7 @@ require_once(KT_LIB_DIR . &quot;/permissions/permissionobject.inc.php&quot;);
37 37 require_once(KT_LIB_DIR . "/permissions/permissiondynamiccondition.inc.php");
38 38 require_once(KT_LIB_DIR . "/groups/GroupUtil.php");
39 39 require_once(KT_LIB_DIR . "/roles/roleallocation.inc.php");
  40 +require_once(KT_LIB_DIR . "/roles/documentroleallocation.inc.php");
40 41  
41 42 require_once(KT_LIB_DIR . "/workflow/workflowutil.inc.php");
42 43 require_once(KT_LIB_DIR . "/workflow/workflowstatepermissionsassignment.inc.php");
... ... @@ -310,13 +311,22 @@ class KTPermissionUtil {
310 311 foreach ($aAllowed['role'] as $iRoleId) {
311 312 // store the PD <-> RoleId map
312 313 if (!array_key_exists($iRoleId, $_roleCache)) {
313   - $oRoleAllocation =& RoleAllocation::getAllocationsForFolderAndRole($iRoleSourceFolder, $iRoleId);
  314 + $oRoleAllocation = null;
  315 + if (is_a($oFolderOrDocument, 'KTDocumentCore') || is_a($oFolderOrDocument, 'Document')) {
  316 + $oRoleAllocation =& DocumentRoleAllocation::getAllocationsForDocumentAndRole($oFolderOrDocument->getId(), $iRoleId);
  317 + if (PEAR::isError($oRoleAllocation)) { $oRoleAllocation = null; }
  318 + }
  319 + // if that's null - not set _on_ the document, then
  320 + if (is_null($oRoleAllocation)) {
  321 + $oRoleAllocation =& RoleAllocation::getAllocationsForFolderAndRole($iRoleSourceFolder, $iRoleId);
  322 + }
314 323 $_roleCache[$iRoleId] = $oRoleAllocation;
315 324 }
316 325 // roles are _not_ always assigned (can be null at root)
317   - if ($_roleCache[$iRoleId] != null) {
  326 + if (!is_null($_roleCache[$iRoleId])) {
318 327 $aMapPermAllowed[$iPermissionId]['user'] = array_merge($aAllowed['user'], $_roleCache[$iRoleId]->getUserIds());
319 328 $aMapPermAllowed[$iPermissionId]['group'] = array_merge($aAllowed['group'], $_roleCache[$iRoleId]->getGroupIds());
  329 + // naturally, roles cannot be assigned roles, or madness follows.
320 330 }
321 331 }
322 332  
... ... @@ -361,7 +371,8 @@ class KTPermissionUtil {
361 371 }
362 372 $oPD = KTPermissionDescriptor::get($oPLA->getPermissionDescriptorID());
363 373 $aGroups = GroupUtil::listGroupsForUserExpand($oUser);
364   - return $oPD->hasGroups($aGroups);
  374 + if ($oPD->hasUsers(array($oUser))) { return true; }
  375 + else { return $oPD->hasGroups($aGroups); }
365 376 }
366 377 // }}}
367 378  
... ...
lib/plugins/pluginentity.inc.php
... ... @@ -52,7 +52,7 @@ class KTPluginEntity extends KTEntity {
52 52 }
53 53  
54 54 function _cachedGroups() {
55   - return array('getList', 'getByNamespace');
  55 + return array('getlist', 'getList', 'getByNamespace');
56 56 }
57 57 // }}}
58 58  
... ... @@ -80,13 +80,13 @@ class KTPluginEntity extends KTEntity {
80 80 // STATIC
81 81 function &getList($sWhereClause = null) {
82 82 global $default;
83   - $aOptions = array('fullselect' => true, 'cache' => 'getList');
  83 + $aOptions = array('fullselect' => false, 'cache' => 'getList');
84 84 return KTEntityUtil::getList2('KTPluginEntity', $sWhereClause, $aOptions);
85 85 }
86 86  
87 87 // STATIC
88 88 function &getByNamespace($sName) {
89   - $aOptions = array('fullselect' => true, 'cache' => 'getByNamespace');
  89 + $aOptions = array('fullselect' => false, 'cache' => 'getByNamespace');
90 90 return KTEntityUtil::getBy('KTPluginEntity', 'namespace', $sName, $aOptions);
91 91 }
92 92  
... ... @@ -98,4 +98,14 @@ class KTPluginEntity extends KTEntity {
98 98 return KTEntityUtil::getBy('KTPluginEntity', 'disabled', false,
99 99 $aOptions);
100 100 }
  101 +
  102 + function setEnabled($aIds) {
  103 + $sTable = KTPluginEntity::_table();
  104 + $sIds = DBUtil::paramArray($aIds);
  105 + $sQuery = sprintf('UPDATE %s SET disabled = 1 WHERE id NOT IN (%s)', $sTable, $sIds);
  106 + DBUtil::runQuery(array($sQuery, $aIds));
  107 + $sQuery = sprintf('UPDATE %s SET disabled = 0 WHERE id IN (%s)', $sTable, $sIds);
  108 + DBUtil::runQuery(array($sQuery, $aIds));
  109 + KTPluginEntity::_innerClearCachedGroups('KTPluginEntity');
  110 + }
101 111 }
... ...
lib/roles/roleallocation.inc.php
... ... @@ -66,6 +66,18 @@ class RoleAllocation extends KTEntity {
66 66 $this->iPermissionDescriptorId = $oDescriptor->getId();
67 67 }
68 68  
  69 + function getAllowed() {
  70 + if (!is_null($this->iPermissionDescriptorId)) {
  71 + $oDescriptor = KTPermissionDescriptor::get($this->iPermissionDescriptorId); // fully done, etc.
  72 + $aAllowed = $oDescriptor->getAllowed();
  73 + } else {
  74 + $aAllowed = array();
  75 + }
  76 + return $aAllowed;
  77 + }
  78 +
  79 +
  80 +
69 81 function _fieldValues () { return array(
70 82 'role_id' => $this->iRoleId,
71 83 'folder_id' => $this->iFolderId,
... ...
lib/storage/ondiskpathstoragemanager.inc.php
... ... @@ -73,7 +73,7 @@ class KTOnDiskPathStorageManager extends KTStorageManager {
73 73 }
74 74  
75 75 function generateStoragePath(&$oDocument) {
76   - $sStoragePath = sprintf("%s/%s-%s", KTDocumentCore::_generateFolderPath($oDocument->getFolderID()), $oDocument->getContentVersionId(), $oDocument->getFileName());
  76 + $sStoragePath = sprintf("%s/%s-%s", Folder::generateFolderPath($oDocument->getFolderID()), $oDocument->getContentVersionId(), $oDocument->getFileName());
77 77 return $sStoragePath;
78 78 }
79 79  
... ... @@ -178,8 +178,8 @@ class KTOnDiskPathStorageManager extends KTStorageManager {
178 178 $sDocumentRoot = $oConfig->get('urls/documentRoot');
179 179  
180 180 foreach ($aContentVersions as $oVersion) {
181   - $sOldPath = sprintf("%s/%s-%s", KTDocumentCore::_generateFolderPath($oSourceFolder->getID()), $oVersion->getId(), $oVersion->getFileName());
182   - $sNewPath = sprintf("%s/%s-%s", KTDocumentCore::_generateFolderPath($oDestinationFolder->getID()), $oVersion->getId(), $oVersion->getFileName());
  181 + $sOldPath = sprintf("%s/%s-%s", Folder::generateFolderPath($oSourceFolder->getID()), $oVersion->getId(), $oVersion->getFileName());
  182 + $sNewPath = sprintf("%s/%s-%s", Folder::generateFolderPath($oDestinationFolder->getID()), $oVersion->getId(), $oVersion->getFileName());
183 183 $sFullOldPath = sprintf("%s/%s", $sDocumentRoot, $sOldPath);
184 184 $sFullNewPath = sprintf("%s/%s", $sDocumentRoot, $sNewPath);
185 185 $res = KTUtil::moveFile($sFullOldPath, $sFullNewPath);
... ... @@ -322,8 +322,8 @@ class KTOnDiskPathStorageManager extends KTStorageManager {
322 322 $oConfig =& KTConfig::getSingleton();
323 323 $sDocumentRoot = $oConfig->get('urls/documentRoot');
324 324  
325   - $sOldPath = sprintf("%s/%s-%s", KTDocumentCore::_generateFolderPath($oDocument->getFolderID()), $oOldContentVersion->getId(), $oOldContentVersion->getFileName());
326   - $sNewPath = sprintf("%s/%s-%s", KTDocumentCore::_generateFolderPath($oDocument->getFolderID()), $oDocument->_oDocumentContentVersion->getId(), $sNewFilename);
  325 + $sOldPath = sprintf("%s/%s-%s", Folder::generateFolderPath($oDocument->getFolderID()), $oOldContentVersion->getId(), $oOldContentVersion->getFileName());
  326 + $sNewPath = sprintf("%s/%s-%s", Folder::generateFolderPath($oDocument->getFolderID()), $oDocument->_oDocumentContentVersion->getId(), $sNewFilename);
327 327 $sFullOldPath = sprintf("%s/%s", $sDocumentRoot, $sOldPath);
328 328 $sFullNewPath = sprintf("%s/%s", $sDocumentRoot, $sNewPath);
329 329  
... ...
lib/templating/kt3template.inc.php
... ... @@ -367,7 +367,7 @@ class KTPage {
367 367 $microtime_simple = explode(' ', microtime());
368 368 $finaltime = (float) $microtime_simple[1] + (float) $microtime_simple[0];
369 369  
370   - return ($finaltime - $GLOBALS['_KT_starttime']);
  370 + return sprintf("%.3f", ($finaltime - $GLOBALS['_KT_starttime']));
371 371 }
372 372 }
373 373  
... ...
lib/widgets/portlet.inc.php
... ... @@ -46,6 +46,8 @@ class KTPortlet {
46 46 }
47 47  
48 48 function setPlugin(&$oPlugin) {
  49 + global $default;
  50 + $default->log->debug('portlet regging plugin: ' . $oPlugin->sNamespace);
49 51 $this->oPlugin =& $oPlugin;
50 52 }
51 53  
... ...
plugins/ktcore/KTCorePlugin.php
... ... @@ -58,6 +58,7 @@ class KTCorePlugin extends KTPlugin {
58 58 // Permissions
59 59 $this->registerAction('documentaction', 'KTDocumentPermissionsAction', 'ktcore.actions.document.permissions', 'KTPermissions.php');
60 60 $this->registerAction('folderaction', 'KTRoleAllocationPlugin', 'ktcore.actions.folder.roles', 'KTPermissions.php');
  61 + $this->registerAction('documentaction', 'KTDocumentRolesAction', 'ktcore.actions.document.roles', 'KTPermissions.php');
61 62  
62 63 $this->registerDashlet('KTInfoDashlet', 'ktcore.dashlet.info', 'KTDashlets.php');
63 64 $this->registerDashlet('KTNotificationDashlet', 'ktcore.dashlet.notifications', 'KTDashlets.php');
... ...
plugins/ktcore/KTPermissions.php
... ... @@ -35,10 +35,12 @@ require_once(KT_LIB_DIR . &quot;/groups/Group.inc&quot;);
35 35 require_once(KT_LIB_DIR . "/users/User.inc");
36 36 require_once(KT_LIB_DIR . "/roles/Role.inc");
37 37 require_once(KT_LIB_DIR . "/roles/roleallocation.inc.php");
  38 +require_once(KT_LIB_DIR . "/roles/documentroleallocation.inc.php");
38 39  
39 40  
40 41 require_once(KT_LIB_DIR . "/permissions/permission.inc.php");
41 42 require_once(KT_LIB_DIR . "/permissions/permissionobject.inc.php");
  43 +require_once(KT_LIB_DIR . "/permissions/permissionlookup.inc.php");
42 44 require_once(KT_LIB_DIR . "/permissions/permissionassignment.inc.php");
43 45 require_once(KT_LIB_DIR . "/permissions/permissiondescriptor.inc.php");
44 46 require_once(KT_LIB_DIR . "/permissions/permissionutil.inc.php");
... ... @@ -52,52 +54,87 @@ class KTDocumentPermissionsAction extends KTDocumentAction {
52 54 }
53 55  
54 56 function do_main() {
55   - $this->oPage->setBreadcrumbDetails("permissions");
56   -
  57 + $this->oPage->setBreadcrumbDetails("Document Permissions");
57 58 $oTemplate = $this->oValidator->validateTemplate("ktcore/document/document_permissions");
58   - $oPO = KTPermissionObject::get($this->oDocument->getPermissionObjectID());
  59 +
  60 + $oPL = KTPermissionLookup::get($this->oDocument->getPermissionLookupID());
59 61 $aPermissions = KTPermission::getList();
60 62 $aMapPermissionGroup = array();
61   - $aMapPermissionRole = array();
  63 + $aMapPermissionRole = array();
  64 + $aMapPermissionUser = array();
  65 +
  66 + $aAllGroups = Group::getList(); // probably small enough
  67 + $aAllRoles = Role::getList(); // probably small enough.
  68 + // users are _not_ fetched this way.
  69 +
  70 + $aActiveGroups = array();
  71 + $aActiveUsers = array();
  72 + $aActiveRoles = array();
  73 +
62 74 foreach ($aPermissions as $oPermission) {
63   - $oPA = KTPermissionAssignment::getByPermissionAndObject($oPermission, $oPO);
64   - if (PEAR::isError($oPA)) {
  75 + $oPLA = KTPermissionLookupAssignment::getByPermissionAndLookup($oPermission, $oPL);
  76 + if (PEAR::isError($oPLA)) {
65 77 continue;
66 78 }
67   - $oDescriptor = KTPermissionDescriptor::get($oPA->getPermissionDescriptorID());
  79 + $oDescriptor = KTPermissionDescriptor::get($oPLA->getPermissionDescriptorID());
68 80 $iPermissionID = $oPermission->getID();
69 81 $aIDs = $oDescriptor->getGroups();
70 82 $aMapPermissionGroup[$iPermissionID] = array();
71 83 foreach ($aIDs as $iID) {
72 84 $aMapPermissionGroup[$iPermissionID][$iID] = true;
  85 + $aActiveGroups[$iID] = true;
73 86 }
74 87 $aIds = $oDescriptor->getRoles();
75 88 $aMapPermissionRole[$iPermissionID] = array();
76 89 foreach ($aIds as $iId) {
77 90 $aMapPermissionRole[$iPermissionID][$iId] = true;
  91 + $aActiveRoles[$iId] = true;
  92 + }
  93 + $aIds = $oDescriptor->getUsers();
  94 + $aMapPermissionUser[$iPermissionID] = array();
  95 + foreach ($aIds as $iId) {
  96 + $aMapPermissionUser[$iPermissionID][$iId] = true;
  97 + $aActiveUsers[$iId] = true;
78 98 }
79 99 }
  100 +
  101 + // now we constitute the actual sets.
  102 + $users = array();
  103 + $groups = array();
  104 + $roles = array(); // should _always_ be empty, barring a bug in permissions::updatePermissionLookup
80 105  
81   - $oInherited = KTPermissionUtil::findRootObjectForPermissionObject($oPO);
82   - if ($oInherited === $this->oDocument) {
83   - $bEdit = true;
84   - } else {
85   - $iInheritedFolderID = $oInherited->getID();
86   - /* $sInherited = displayFolderPathLink(Folder::getFolderPathAsArray($iInheritedFolderID),
87   - Folder::getFolderPathNamesAsArray($iInheritedFolderID),
88   - "$default->rootUrl/control.php?action=editFolderPermissions");*/
89   - $sInherited = join(" &raquo; ", $oInherited->getPathArray());
90   - $bEdit = false;
91   - }
  106 + // this should be quite limited - direct role -> user assignment is typically rare.
  107 + foreach ($aActiveUsers as $id => $marker) {
  108 + $oUser = User::get($id);
  109 + $users[$oUser->getName()] = $oUser;
  110 + }
  111 + asort($users); // ascending, per convention.
  112 +
  113 + foreach ($aActiveGroups as $id => $marker) {
  114 + $oGroup = Group::get($id);
  115 + $groups[$oGroup->getName()] = $oGroup;
  116 + }
  117 + asort($groups);
  118 +
  119 + foreach ($aActiveRoles as $id => $marker) {
  120 + $oRole = Role::get($id);
  121 + $roles[$oRole->getName()] = $oRole;
  122 + }
  123 + asort($roles);
  124 +
  125 + $bEdit = false;
  126 + $sInherited = '';
92 127  
93 128 $aTemplateData = array(
94 129 "context" => $this,
95 130 "permissions" => $aPermissions,
96   - "groups" => Group::getList(),
97   - "roles" => Role::getList(),
  131 + "groups" => $groups,
  132 + "users" => $users,
  133 + "roles" => $roles,
98 134 "iDocumentID" => $_REQUEST['fDocumentID'],
99 135 "aMapPermissionGroup" => $aMapPermissionGroup,
100 136 "aMapPermissionRole" => $aMapPermissionRole,
  137 + "aMapPermissionUser" => $aMapPermissionUser,
101 138 "edit" => $bEdit,
102 139 "inherited" => $sInherited,
103 140 );
... ... @@ -509,3 +546,93 @@ class KTRoleAllocationPlugin extends KTFolderAction {
509 546 }
510 547 }
511 548 }
  549 +
  550 +class KTDocumentRolesAction extends KTDocumentAction {
  551 + var $sDisplayName = 'View Roles';
  552 + var $sName = 'ktcore.actions.document.roles';
  553 +
  554 + var $_sShowPermission = "ktcore.permissions.write";
  555 + var $bAutomaticTransaction = true;
  556 +
  557 + function do_main() {
  558 + $this->oPage->setTitle(_("View Roles"));
  559 + $this->oPage->setBreadcrumbDetails(_("View Roles"));
  560 + $oTemplating = new KTTemplating;
  561 + $oTemplate = $oTemplating->loadTemplate("ktcore/action/view_roles");
  562 +
  563 + // we need to have:
  564 + // - a list of roles
  565 + // - with their users / groups
  566 + // - and that allocation id
  567 + $aRoles = array(); // stores data for display.
  568 +
  569 + $aRoleList = Role::getList();
  570 + foreach ($aRoleList as $oRole) {
  571 + $iRoleId = $oRole->getId();
  572 + $aRoles[$iRoleId] = array("name" => $oRole->getName());
  573 + $oRoleAllocation = DocumentRoleAllocation::getAllocationsForDocumentAndRole($this->oDocument->getId(), $iRoleId);
  574 + if (is_null($oRoleAllocation)) {
  575 + $oRoleAllocation = RoleAllocation::getAllocationsForFolderAndRole($this->oDocument->getFolderID(), $iRoleId);
  576 + }
  577 +
  578 + $u = array();
  579 + $g = array();
  580 + $aid = null;
  581 + $raid = null;
  582 + if (is_null($oRoleAllocation)) {
  583 + ; // nothing.
  584 + } else {
  585 + //var_dump($oRoleAllocation);
  586 + $raid = $oRoleAllocation->getId(); // real_alloc_id
  587 + $aAllowed = $oRoleAllocation->getAllowed();
  588 +
  589 + if (!empty($aAllowed['user'])) {
  590 + $u = $aAllowed['user'];
  591 + }
  592 + if (!empty($aAllowed['group'])) {
  593 + $g = $aAllowed['group'];
  594 + }
  595 + }
  596 + $aRoles[$iRoleId]['users'] = $u;
  597 + $aRoles[$iRoleId]['groups'] = $g;
  598 + $aRoles[$iRoleId]['real_allocation_id'] = $raid;
  599 + }
  600 +
  601 + // final step.
  602 +
  603 + // map to users, groups.
  604 + foreach ($aRoles as $key => $role) {
  605 + $_users = array();
  606 + foreach ($aRoles[$key]['users'] as $iUserId) {
  607 + $oUser = User::get($iUserId);
  608 + if (!(PEAR::isError($oUser) || ($oUser == false))) {
  609 + $_users[] = $oUser->getName();
  610 + }
  611 + }
  612 + if (empty($_users)) {
  613 + $aRoles[$key]['users'] = '<span class="descriptiveText"> ' . _('no users') . '</span>';
  614 + } else {
  615 + $aRoles[$key]['users'] = implode(', ',$_users);
  616 + }
  617 +
  618 + $_groups = array();
  619 + foreach ($aRoles[$key]['groups'] as $iGroupId) {
  620 + $oGroup = Group::get($iGroupId);
  621 + if (!(PEAR::isError($oGroup) || ($oGroup == false))) {
  622 + $_groups[] = $oGroup->getName();
  623 + }
  624 + }
  625 + if (empty($_groups)) {
  626 + $aRoles[$key]['groups'] = '<span class="descriptiveText"> ' . _('no groups') . '</span>';
  627 + } else {
  628 + $aRoles[$key]['groups'] = implode(', ',$_groups);
  629 + }
  630 + }
  631 +
  632 + $aTemplateData = array(
  633 + 'context' => &$this,
  634 + 'roles' => $aRoles,
  635 + );
  636 + return $oTemplate->render($aTemplateData);
  637 + }
  638 +}
512 639 \ No newline at end of file
... ...
plugins/ktcore/admin/plugins.php
... ... @@ -63,12 +63,8 @@ class KTPluginDispatcher extends KTAdminDispatcher {
63 63  
64 64 function do_update() {
65 65 $sTable = KTUtil::getTableName('plugins');
66   - $aIds = KTUtil::arrayGet($_REQUEST, 'pluginids');
67   - $sIds = DBUtil::paramArray($aIds);
68   - $sQuery = sprintf('UPDATE %s SET disabled = 1 WHERE id NOT IN (%s)', $sTable, $sIds);
69   - DBUtil::runQuery(array($sQuery, $aIds));
70   - $sQuery = sprintf('UPDATE %s SET disabled = 0 WHERE id IN (%s)', $sTable, $sIds);
71   - DBUtil::runQuery(array($sQuery, $aIds));
  66 + $aIds = (array) KTUtil::arrayGet($_REQUEST, 'pluginids');
  67 + KTPluginEntity::setEnabled($aIds);
72 68 $this->successRedirectToMain('Plugins updated');
73 69 }
74 70  
... ...
resources/js/toggleselect.js
... ... @@ -20,6 +20,7 @@ function toggleSelectFor(source, nameprefix) {
20 20 if (c.type == 'checkbox') {
21 21 if ((n.length >= nameprefix.length) && (nameprefix == n.substring(0,nameprefix.length))) {
22 22 c.checked = state;
  23 + activateRow(c);
23 24 }
24 25 }
25 26 }
... ...
templates/ktcore/document/document_permissions.smarty
1 1 <h2>{i18n}Document permissions{/i18n}</h2>
2 2  
3   -
4   -
5   -{if ((empty($roles) && empty($groups)))}
6   -<div class="ktInfo"><p>{i18n}No roles or groups have been defined. Permissions can only
7   -be allocated to roles and groups.{/i18n}</p></div>
  3 +<p class="descriptiveText">{i18n}This page shows the permissions that apply to
  4 +this specific document. Where the folder view shows you information by role and group,
  5 +this page shows the actual groups (and, if they are assigned directly to a role, the users)
  6 +who have the different permissions. As a result, groups, users and roles with <strong>no</strong>
  7 +permissions are not shown.{/i18n}</p>
  8 +
  9 +{if ((empty($roles) && empty($groups) && empty($users)))}
  10 +<div class="ktInfo"><p>{i18n}No roles or groups have been defined or have permissions.{/i18n}</p></div>
8 11 {else}
9 12  
10   -{*
11   -
12   -{if $iFolderId != 1}
13   -<div class="ktInfo">
14   -{ if $inherited }
15   -<p>{i18n arg_permission_source=$inherited}This folder <strong>inherits</strong> its permissions from #permission_source#.{/i18n}
16   -<a class="ktActionLink ktEdit"
17   - href="{addQS}action=copyPermissions&fFolderId={$iFolderId}{/addQS}">{i18n}Override Permissions{/i18n}</a> </p>
18   -{ else }
19   -<p>{i18n}This folder defines its own permissions.{/i18n}
20   -<a class="ktActionLink ktDelete"
21   - href="{addQS}action=inheritPermissions&fFolderId={$iFolderId}{/addQS}">{i18n}Inherit permissions{/i18n}</a>
22   -{ /if }
23   -</span>
24   -</div>
25   -{ /if }
26   -
27   -*}
28   -
29 13 <form action="{$smarty.server.PHP_SELF}" method="POST">
30 14 <input type="hidden" name="action" value="update">
31 15 <input type="hidden" name="fFolderId" value="{$iFolderId}">
... ... @@ -94,6 +78,36 @@ value=&quot;{$iGroupId}&quot;&gt;&lt;/td&gt;
94 78 { /foreach }
95 79 </tr>
96 80 { /foreach }
  81 +
  82 +
  83 +{ foreach item=oUser from=$users }
  84 +<td><span class="descriptiveText">{i18n}User: {/i18n}</span> {$oUser->getName()}</td>
  85 + { assign var=iUserId value=$oUser->getId() }
  86 + { foreach item=oPerm from=$permissions }
  87 + { assign var=iPermId value=$oPerm->getId() }
  88 + { assign var=bHasPerm value=$aMapPermissionUser[$iPermId][$iUserId] }
  89 +
  90 +{ if $edit}
  91 +{ if $bHasPerm }
  92 +<td class="centered"><input type="checkbox" name="foo[{$iPermId}][group][]"
  93 +value="{$iGroupId}" checked="true"></td>
  94 +{ else }
  95 +<td class="centered"><input type="checkbox" name="foo[{$iPermId}][group][]"
  96 +value="{$iGroupId}"></td>
  97 +{ /if }
  98 +{else}
  99 +{ if $bHasPerm }
  100 +<td class="centered"><span class="ktAction ktInline ktAllowed">{i18n}Allowed{/i18n}</span></td>
  101 +{ else }
  102 +<td class="centered"><span class="ktAction ktInline ktDenied">{i18n}Denied{/i18n}</span></td>
  103 +{ /if }
  104 +{/if}
  105 +
  106 +
  107 + { /foreach }
  108 +</tr>
  109 +{ /foreach }
  110 +
97 111 </tbody>
98 112 </table>
99 113 {if $edit}
... ...
var/cache/.empty 0 → 100644