Commit 4756fb33bfd6496447603cfb2458d5ac71ee160e

Authored by Brad Shuttleworth
1 parent 7df8705e

Brad Shuttleworth 2006-04-13 major merge...

Brad Shuttleworth 2006-04-13 add anon-login default.
    Brad Shuttleworth 2006-04-13 improve group cache management somewhat.
    Brad Shuttleworth 2006-04-12 add in the changes to make anonymous a firs...
    Brad Shuttleworth 2006-04-12 new owner location in db.
    Brad Shuttleworth 2006-04-12 reset the memory-cache "each" after we're d...
    Brad Shuttleworth 2006-04-12 fix for KTS-786:  workflow transitions don'...
    Brad Shuttleworth 2006-04-12 minor fix.
    Brad Shuttleworth 2006-04-12 KTS-739: add more fail-out and checking cod...
    Brad Shuttleworth 2006-04-12 remove object cache:  it causes havoc with ...
    Brad Shuttleworth 2006-04-12 fix for role-management non-editable bug.
    Brad Shuttleworth 2006-04-12 fix for translation issue.


git-svn-id: https://kt-dms.svn.sourceforge.net/svnroot/kt-dms/trunk@5241 c91229c3-7414-0410-bfa2-8a42b809f60b
config/config.ini
@@ -140,6 +140,7 @@ uiUrl = ${rootUrl}/presentation/lookAndFeel/knowledgeTree @@ -140,6 +140,7 @@ uiUrl = ${rootUrl}/presentation/lookAndFeel/knowledgeTree
140 [session] 140 [session]
141 ; session timeout (in seconds) 141 ; session timeout (in seconds)
142 sessionTimeout = 1200 142 sessionTimeout = 1200
  143 +allowAnonymousLogin = true
143 144
144 [import] 145 [import]
145 ; unzip command - will use execSearchPath to find if the path to the 146 ; unzip command - will use execSearchPath to find if the path to the
config/siteMap.inc
@@ -34,27 +34,27 @@ $default->siteMap->addPage("dashboard", "/dashboard.php", "General", Guest, "das @@ -34,27 +34,27 @@ $default->siteMap->addPage("dashboard", "/dashboard.php", "General", Guest, "das
34 // dashboard news 34 // dashboard news
35 35
36 //pages for manage documents section 36 //pages for manage documents section
37 -$default->siteMap->addPage("browse", "/browse.php", "Manage Documents", Guest, _("browse documents"));  
38 -$default->siteMap->addPage("viewDocument", "/view.php", "Manage Documents", Guest, _("View Document"), false);  
39 -$default->siteMap->addPage("editDocument", "/edit.php", "Manage Documents", Guest, _("Edit Document"), false); 37 +$default->siteMap->addPage("browse", "/browse.php", "Manage Documents", Guest, _kt("browse documents"));
  38 +$default->siteMap->addPage("viewDocument", "/view.php", "Manage Documents", Guest, _kt("View Document"), false);
  39 +$default->siteMap->addPage("editDocument", "/edit.php", "Manage Documents", Guest, _kt("Edit Document"), false);
40 40
41 // pages for administration section 41 // pages for administration section
42 -$default->siteMap->addDefaultPage("administration", "/admin.php", "Administration", UnitAdmin, _("Administration")); 42 +$default->siteMap->addDefaultPage("administration", "/admin.php", "Administration", UnitAdmin, _kt("Administration"));
43 43
44 // pages for advanced search section 44 // pages for advanced search section
45 -$default->siteMap->addDefaultPage("advancedSearch", "/search/advancedSearchBL.php", "Advanced Search", Guest, _("Advanced Search"), true);  
46 -$default->siteMap->addPage("booleanSearch", "/search/booleanSearch.php", "Boolean Search", Guest, _("Boolean Search"), false); 45 +$default->siteMap->addDefaultPage("advancedSearch", "/search/advancedSearchBL.php", "Advanced Search", Guest, _kt("Advanced Search"), true);
  46 +$default->siteMap->addPage("booleanSearch", "/search/booleanSearch.php", "Boolean Search", Guest, _kt("Boolean Search"), false);
47 47
48 $default->siteMap->addSectionColour("Advanced Search", "th", "A1571B"); 48 $default->siteMap->addSectionColour("Advanced Search", "th", "A1571B");
49 $default->siteMap->addSectionColour("Standard Search", "th", "A1571B"); 49 $default->siteMap->addSectionColour("Standard Search", "th", "A1571B");
50 50
51 // pages for prefs section 51 // pages for prefs section
52 -$default->siteMap->addDefaultPage("preferences", "/preferences.php", "Preferences", User, _("Preferences")); 52 +$default->siteMap->addDefaultPage("preferences", "/preferences.php", "Preferences", User, _kt("Preferences"));
53 53
54 // pages for Help section 54 // pages for Help section
55 -$default->siteMap->addDefaultPage("help", "/presentation/lookAndFeel/knowledgeTree/help.php", "Help", Guest, _("Help")); 55 +$default->siteMap->addDefaultPage("help", "/presentation/lookAndFeel/knowledgeTree/help.php", "Help", Guest, _kt("Help"));
56 56
57 // pages for logout section section 57 // pages for logout section section
58 -$default->siteMap->addDefaultPage("logout", "/presentation/logout.php", "Logout", Guest, _("Logout")); 58 +$default->siteMap->addDefaultPage("logout", "/presentation/logout.php", "Logout", Guest, _kt("Logout"));
59 59
60 ?> 60 ?>
control.php
@@ -63,9 +63,13 @@ if ($action != "login") { @@ -63,9 +63,13 @@ if ($action != "login") {
63 } 63 }
64 } else { 64 } else {
65 // session check fails, so default action should be the login form if no action was specified 65 // session check fails, so default action should be the login form if no action was specified
  66 + $oKTConfig = KTConfig::getSingleton();
  67 + $dest = 'login';
  68 + if ($oKTConfig->get('allowAnonymousLogin', false)) { $dest = 'dashboard'; }
  69 +
66 if (!isset($action)) { 70 if (!isset($action)) {
67 - $action = "login";  
68 - } elseif ($action <> "login") { 71 + $action = $dest;
  72 + } elseif ($action <> $dest) {
69 // we have a controller link and auth has failed, so redirect to the login page 73 // we have a controller link and auth has failed, so redirect to the login page
70 // with the controller link as the redirect 74 // with the controller link as the redirect
71 $url = generateControllerUrl("login"); 75 $url = generateControllerUrl("login");
lib/dispatcher.inc.php
@@ -218,6 +218,25 @@ class KTStandardDispatcher extends KTDispatcher { @@ -218,6 +218,25 @@ class KTStandardDispatcher extends KTDispatcher {
218 } 218 }
219 219
220 function loginRequired() { 220 function loginRequired() {
  221 + $oKTConfig =& KTConfig::getSingleton();
  222 + if ($oKTConfig->get('allowAnonymousLogin', false)) {
  223 + // anonymous logins are now allowed.
  224 + // the anonymous user is -1.
  225 + //
  226 + // we short-circuit the login mechanisms, setup the session, and go.
  227 +
  228 + $oUser =& User::get(-2);
  229 + if (PEAR::isError($oUser) || ($oUser->getName() != 'Anonymous')) {
  230 + ; // do nothing - the database integrity would break if we log the user in now.
  231 + } else {
  232 + $session = new Session();
  233 + $sessionID = $session->create($oUser);
  234 +
  235 + return ;
  236 + }
  237 + }
  238 +
  239 +
221 $sErrorMessage = ""; 240 $sErrorMessage = "";
222 if (PEAR::isError($this->sessionStatus)) { 241 if (PEAR::isError($this->sessionStatus)) {
223 $sErrorMessage = $this->sessionStatus->getMessage(); 242 $sErrorMessage = $this->sessionStatus->getMessage();
@@ -249,9 +268,9 @@ class KTStandardDispatcher extends KTDispatcher { @@ -249,9 +268,9 @@ class KTStandardDispatcher extends KTDispatcher {
249 $this->session = new Session(); 268 $this->session = new Session();
250 $this->sessionStatus = $this->session->verify(); 269 $this->sessionStatus = $this->session->verify();
251 if ($this->sessionStatus !== true) { 270 if ($this->sessionStatus !== true) {
252 - $this->loginRequired(); 271 + $this->loginRequired();
253 } 272 }
254 - 273 + //var_dump($this->sessionStatus);
255 $this->oUser =& User::get($_SESSION['userID']); 274 $this->oUser =& User::get($_SESSION['userID']);
256 $oProvider =& KTAuthenticationUtil::getAuthenticationProviderForUser($this->oUser); 275 $oProvider =& KTAuthenticationUtil::getAuthenticationProviderForUser($this->oUser);
257 $oProvider->verify($this->oUser); 276 $oProvider->verify($this->oUser);
lib/documentmanagement/DocumentType.inc
@@ -185,10 +185,18 @@ class DocumentType extends KTEntity { @@ -185,10 +185,18 @@ class DocumentType extends KTEntity {
185 function &getList($sWhereClause = null) { 185 function &getList($sWhereClause = null) {
186 return KTEntityUtil::getList2('DocumentType', $sWhereClause); 186 return KTEntityUtil::getList2('DocumentType', $sWhereClause);
187 } 187 }
  188 +
  189 + /* alternative for use in creation: delegate for user and location */
  190 + function &getListForUserAndFolder($oUser, $oFolder) {
  191 + $src =& KTDocumentTypeManager::getSingleton();
  192 + return $src->getListForUserAndFolder($oUser, $oFolder);
  193 + }
188 194
189 function &createFromArray($aArray) { 195 function &createFromArray($aArray) {
190 return KTEntityUtil::createFromArray('DocumentType', $aArray); 196 return KTEntityUtil::createFromArray('DocumentType', $aArray);
191 } 197 }
  198 +
  199 +
192 200
193 } 201 }
194 202
@@ -207,4 +215,71 @@ function &amp; documenttypeCreateFromArray($aParameters) { @@ -207,4 +215,71 @@ function &amp; documenttypeCreateFromArray($aParameters) {
207 return $oDocType; 215 return $oDocType;
208 } 216 }
209 217
  218 +
  219 +class DemoDelegation {
  220 + var $handler_ns = 'brad.oddhandler';
  221 + var $handler_name = null;
  222 +
  223 + function DemoDelegation() {
  224 + $this->handler_name = _kt('Demo Delegator');
  225 + }
  226 +
  227 + function &getListForUserAndFolder($oUser, $oFolder) {
  228 + $list =& DocumentType::getList();
  229 + $finallist = array();
  230 + foreach ($list as $oType) {
  231 + if ($oType->getId() % 2 == 0) {
  232 + $finallist[] = $oType;
  233 + }
  234 + }
  235 + return $finallist;
  236 + }
  237 +}
  238 +
  239 +/* simple singleton util class */
  240 +class KTDocumentTypeManager {
  241 + var $_handlers = array();
  242 + var $_active_handler = null;
  243 + var $_checked = false;
  244 +
  245 + function &getSingleton() {
  246 + if (!KTUtil::arrayGet($GLOBALS, 'oKTDocumentTypeManager')) {
  247 + $GLOBALS['oKTDocumentTypeManager'] = new KTDocumentTypeManager;
  248 + }
  249 + return $GLOBALS['oKTDocumentTypeManager'];
  250 + }
  251 +
  252 + function &getListForUserAndFolder($oUser, $oFolder) {
  253 + $this->checkActiveHandler();
  254 + if (is_null($this->_active_handler)) {
  255 + // as totally normal if nothing is registered.
  256 + return DocumentType::getList();
  257 + } else {
  258 + return $this->_active_handler->getListForUserAndFolder($oUser, $oFolder);
  259 + }
  260 + }
  261 +
  262 + function checkActiveHandler() {
  263 + if ($this->_checked) { return ; }
  264 + // not perfect - see workflow-delegator for explanation.
  265 + $res = KTUtil::getSystemSetting('documenttypehandler');
  266 +
  267 + if (empty($res) || PEAR::isError($res)) { // just fail silently - don't degrade the system
  268 + $this->_active_handler = null;
  269 + } else {
  270 + $ns = $res;
  271 + $this->_active_handler = KTUtil::arrayGet($this->handlers, $ns);
  272 + }
  273 +
  274 + $this->_checked = true;
  275 +
  276 + return ;
  277 + }
  278 +
  279 + function registerHandler($oHandler) {
  280 + $this->_handlers[$oHandler->handler_ns] = $oHandler;
  281 + }
  282 +}
  283 +
  284 +
210 ?> 285 ?>
lib/foldermanagement/Folder.inc
@@ -143,6 +143,7 @@ class Folder extends KTEntity { @@ -143,6 +143,7 @@ class Folder extends KTEntity {
143 } 143 }
144 144
145 $oFolder =& Folder::get($iFolderId); 145 $oFolder =& Folder::get($iFolderId);
  146 + if (PEAR::isError($oFolder)) { sprintf("The invalid folder id is: %s", print_r($iFolderId, true)); }
146 $iParentId = $oFolder->getParentId(); 147 $iParentId = $oFolder->getParentId();
147 if (empty($iParentId)) { 148 if (empty($iParentId)) {
148 return $oFolder->getName(); 149 return $oFolder->getName();
lib/groups/Group.inc
@@ -235,6 +235,9 @@ class Group extends KTEntity { @@ -235,6 +235,9 @@ class Group extends KTEntity {
235 if (PEAR::isError($res)) { 235 if (PEAR::isError($res)) {
236 return $res; 236 return $res;
237 } 237 }
  238 +
  239 + GroupUtil::clearGroupCacheForUser($oUser);
  240 +
238 return true; 241 return true;
239 } 242 }
240 // }}} 243 // }}}
lib/groups/GroupUtil.php
@@ -368,6 +368,14 @@ class GroupUtil { @@ -368,6 +368,14 @@ class GroupUtil {
368 // } 368 // }
369 } 369 }
370 // }}} 370 // }}}
  371 +
  372 + function clearGroupCacheForUser($oUser) {
  373 + $oCache =& KTCache::getSingleton();
  374 + if (PEAR::isError($oUser)) { return $oUser; }
  375 + $group = "groupidsforuser";
  376 + $iUserId = KTUtil::getId($oUser);
  377 + $oCache->remove($group, $iUserId);
  378 + }
371 } 379 }
372 // }}} 380 // }}}
373 381
lib/ktentity.inc
@@ -610,14 +610,16 @@ class KTEntityUtil { @@ -610,14 +610,16 @@ class KTEntityUtil {
610 } 610 }
611 return $oObject; 611 return $oObject;
612 /* */ 612 /* */
613 - $oObject =& KTUtil::arrayGet($GLOBALS['_OBJECTCACHE'][$sClassName], $iId);  
614 - if ($oObject) { return $oObject; } 613 + // XXX Object cache currently causes hard-to-trace inconsistencies in data.
  614 + // $oObject =& KTUtil::arrayGet($GLOBALS['_OBJECTCACHE'][$sClassName], $iId);
  615 + // if ($oObject) { return $oObject; }
615 $oObject =& new $sClassName; 616 $oObject =& new $sClassName;
616 $res = $oObject->load($iId); 617 $res = $oObject->load($iId);
617 if (PEAR::isError($res)) { 618 if (PEAR::isError($res)) {
618 return $res; 619 return $res;
619 } 620 }
620 - $GLOBALS['_OBJECTCACHE'][$sClassName][$iId] =& $oObject; 621 + // XXX Object cache currently causes hard-to-trace inconsistencies in data.
  622 + //$GLOBALS['_OBJECTCACHE'][$sClassName][$iId] =& $oObject;
621 return $oObject; 623 return $oObject;
622 /* */ 624 /* */
623 } 625 }
lib/permissions/permissiondescriptor.inc.php
@@ -276,13 +276,14 @@ class KTPermissionDescriptor extends KTEntity { @@ -276,13 +276,14 @@ class KTPermissionDescriptor extends KTEntity {
276 276
277 // {{{ hasRoles 277 // {{{ hasRoles
278 function hasRoles($aRoles) { 278 function hasRoles($aRoles) {
  279 + if (!is_array($aRoles)) { return false; }
279 $sTable = KTUtil::getTableName('permission_descriptor_roles'); 280 $sTable = KTUtil::getTableName('permission_descriptor_roles');
280 if (count($aRoles) === 0) { 281 if (count($aRoles) === 0) {
281 return false; 282 return false;
282 } 283 }
283 $aRoleIDs = array(); 284 $aRoleIDs = array();
284 foreach ($aRoles as $oRole) { 285 foreach ($aRoles as $oRole) {
285 - $aRoleIDs[] = $oRole->getID(); 286 + $aRoleIDs[] = KTUtil::getId($oRole);
286 } 287 }
287 $sRoleIDs = DBUtil::paramArray($aRoleIDs); 288 $sRoleIDs = DBUtil::paramArray($aRoleIDs);
288 $sQuery = "SELECT COUNT(role_id) AS num FROM $sTable 289 $sQuery = "SELECT COUNT(role_id) AS num FROM $sTable
lib/permissions/permissionutil.inc.php
@@ -83,10 +83,19 @@ class KTPermissionUtil { @@ -83,10 +83,19 @@ class KTPermissionUtil {
83 $sDescriptor = KTPermissionUtil::generateDescriptor($aAllowed); 83 $sDescriptor = KTPermissionUtil::generateDescriptor($aAllowed);
84 $oDescriptor =& KTPermissionDescriptor::getByDescriptor(md5($sDescriptor)); 84 $oDescriptor =& KTPermissionDescriptor::getByDescriptor(md5($sDescriptor));
85 if (PEAR::isError($oDescriptor)) { 85 if (PEAR::isError($oDescriptor)) {
  86 +
86 $oDescriptor =& KTPermissionDescriptor::createFromArray(array( 87 $oDescriptor =& KTPermissionDescriptor::createFromArray(array(
87 "descriptortext" => $sDescriptor, 88 "descriptortext" => $sDescriptor,
88 )); 89 ));
  90 + if (PEAR::isError($oDescriptor)) {
  91 + print '<pre>';
  92 + print_r($aAllowed);
  93 + print "-----------\n";
  94 + print_r($oDescriptor);
  95 + print '</pre>';
  96 + }
89 $oDescriptor->saveAllowed($aAllowed); 97 $oDescriptor->saveAllowed($aAllowed);
  98 +
90 } 99 }
91 return $oDescriptor; 100 return $oDescriptor;
92 } 101 }
@@ -137,8 +146,8 @@ class KTPermissionUtil { @@ -137,8 +146,8 @@ class KTPermissionUtil {
137 * previous assignment. 146 * previous assignment.
138 */ 147 */
139 function setPermissionForID($sPermission, $iObjectID, $aAllowed) { 148 function setPermissionForID($sPermission, $iObjectID, $aAllowed) {
140 - $oPermissionAssignment = KTPermissionUtil::getOrCreateAssignment($sPermission, $iObjectID);  
141 - $oDescriptor = KTPermissionUtil::getOrCreateDescriptor($aAllowed); 149 + $oPermissionAssignment =& KTPermissionUtil::getOrCreateAssignment($sPermission, $iObjectID);
  150 + $oDescriptor =& KTPermissionUtil::getOrCreateDescriptor($aAllowed);
142 $oPermissionAssignment->setPermissionDescriptorID($oDescriptor->getID()); 151 $oPermissionAssignment->setPermissionDescriptorID($oDescriptor->getID());
143 $res = $oPermissionAssignment->update(); 152 $res = $oPermissionAssignment->update();
144 return $res; 153 return $res;
@@ -167,12 +176,16 @@ class KTPermissionUtil { @@ -167,12 +176,16 @@ class KTPermissionUtil {
167 $sWhere = 'permission_object_id = ?'; 176 $sWhere = 'permission_object_id = ?';
168 $aParams = array($oPO->getID()); 177 $aParams = array($oPO->getID());
169 $aFolders =& Folder::getList(array($sWhere, $aParams)); 178 $aFolders =& Folder::getList(array($sWhere, $aParams));
170 - foreach ($aFolders as $oFolder) {  
171 - KTPermissionUtil::updatePermissionLookup($oFolder); 179 + if (!PEAR::isError($aFolders)) {
  180 + foreach ($aFolders as $oFolder) {
  181 + KTPermissionUtil::updatePermissionLookup($oFolder);
  182 + }
172 } 183 }
173 $aDocuments =& Document::getList(array($sWhere, $aParams)); 184 $aDocuments =& Document::getList(array($sWhere, $aParams));
174 - foreach ($aDocuments as $oDocument) {  
175 - KTPermissionUtil::updatePermissionLookup($oDocument); 185 + if (!PEAR::isError($aDocuments)) {
  186 + foreach ($aDocuments as $oDocument) {
  187 + KTPermissionUtil::updatePermissionLookup($oDocument);
  188 + }
176 } 189 }
177 } 190 }
178 // }}} 191 // }}}
@@ -219,9 +232,7 @@ class KTPermissionUtil { @@ -219,9 +232,7 @@ class KTPermissionUtil {
219 if (!is_a($oFolderOrDocument, 'Folder')) { 232 if (!is_a($oFolderOrDocument, 'Folder')) {
220 if (!is_a($oFolderOrDocument, 'Document')) { 233 if (!is_a($oFolderOrDocument, 'Document')) {
221 if (!is_a($oFolderOrDocument, 'KTDocumentCore')) { 234 if (!is_a($oFolderOrDocument, 'KTDocumentCore')) {
222 - echo "<pre>";  
223 - var_dump($oFolderOrDocument);  
224 - echo "</pre>"; 235 + return ; // we occasionally get handed a PEAR::raiseError. Just ignore it.
225 } 236 }
226 } 237 }
227 } 238 }
@@ -307,9 +318,16 @@ class KTPermissionUtil { @@ -307,9 +318,16 @@ class KTPermissionUtil {
307 $_roleCache = array(); 318 $_roleCache = array();
308 319
309 foreach ($aMapPermAllowed as $iPermissionId => $aAllowed) { 320 foreach ($aMapPermAllowed as $iPermissionId => $aAllowed) {
  321 + $aAfterRoles = array();
310 if (array_key_exists('role', $aAllowed)) { 322 if (array_key_exists('role', $aAllowed)) {
311 - foreach ($aAllowed['role'] as $iRoleId) { 323 + foreach ($aAllowed['role'] as $k => $iRoleId) {
312 // store the PD <-> RoleId map 324 // store the PD <-> RoleId map
  325 +
  326 + // special-case "all" or "authenticated".
  327 + if (($iRoleId == -3) || ($iRoleId == -4)) {
  328 + $aAfterRoles[] = $iRoleId;
  329 + continue;
  330 + }
313 if (!array_key_exists($iRoleId, $_roleCache)) { 331 if (!array_key_exists($iRoleId, $_roleCache)) {
314 $oRoleAllocation = null; 332 $oRoleAllocation = null;
315 if (is_a($oFolderOrDocument, 'KTDocumentCore') || is_a($oFolderOrDocument, 'Document')) { 333 if (is_a($oFolderOrDocument, 'KTDocumentCore') || is_a($oFolderOrDocument, 'Document')) {
@@ -328,10 +346,16 @@ class KTPermissionUtil { @@ -328,10 +346,16 @@ class KTPermissionUtil {
328 $aMapPermAllowed[$iPermissionId]['group'] = kt_array_merge($aAllowed['group'], $_roleCache[$iRoleId]->getGroupIds()); 346 $aMapPermAllowed[$iPermissionId]['group'] = kt_array_merge($aAllowed['group'], $_roleCache[$iRoleId]->getGroupIds());
329 // naturally, roles cannot be assigned roles, or madness follows. 347 // naturally, roles cannot be assigned roles, or madness follows.
330 } 348 }
  349 +
  350 + unset($aAllowed['role'][$k]);
331 } 351 }
332 352
333 } 353 }
  354 +
334 unset($aMapPermAllowed[$iPermissionId]['role']); 355 unset($aMapPermAllowed[$iPermissionId]['role']);
  356 + if (!empty($aAfterRoles)) {
  357 + $aMapPermAllowed[$iPermissionId]['role'] = $aAfterRoles;
  358 + }
335 } 359 }
336 360
337 /* 361 /*
@@ -370,9 +394,15 @@ class KTPermissionUtil { @@ -370,9 +394,15 @@ class KTPermissionUtil {
370 return false; 394 return false;
371 } 395 }
372 $oPD = KTPermissionDescriptor::get($oPLA->getPermissionDescriptorID()); 396 $oPD = KTPermissionDescriptor::get($oPLA->getPermissionDescriptorID());
  397 +
373 $aGroups = GroupUtil::listGroupsForUserExpand($oUser); 398 $aGroups = GroupUtil::listGroupsForUserExpand($oUser);
374 - if ($oPD->hasUsers(array($oUser))) { return true; }  
375 - else { return $oPD->hasGroups($aGroups); } 399 + if ($oPD->hasRoles(array(-3))) { return true; } // everyone has access.
  400 + else if ($oPD->hasUsers(array($oUser))) { return true; }
  401 + else if ($oPD->hasGroups($aGroups)) { return true; }
  402 + // here we specialcase roles -3 [everyone]
  403 + else if ($oPD->hasRoles(-4) && !$oUser->isAnonymous()) { return true; }
  404 +
  405 + return false;
376 } 406 }
377 // }}} 407 // }}}
378 408
lib/roles/documentroleallocation.inc.php
@@ -52,7 +52,7 @@ class DocumentRoleAllocation extends KTEntity { @@ -52,7 +52,7 @@ class DocumentRoleAllocation extends KTEntity {
52 $aAllowed = array(); 52 $aAllowed = array();
53 } 53 }
54 // special case "document owner". 54 // special case "document owner".
55 - if ($this->iRoleId == -1) { 55 + if ($this->iRoleId == -2) {
56 56
57 $oDoc = KTDocumentCore::get($this->iDocumentId); 57 $oDoc = KTDocumentCore::get($this->iDocumentId);
58 58
@@ -139,7 +139,7 @@ class DocumentRoleAllocation extends KTEntity { @@ -139,7 +139,7 @@ class DocumentRoleAllocation extends KTEntity {
139 } 139 }
140 140
141 // magic for the Owner role here. 141 // magic for the Owner role here.
142 - if (empty($iAllocId) && ($iRoleId == -1)) { 142 + if (empty($iAllocId) && ($iRoleId == -2)) {
143 $permDescriptor = null; 143 $permDescriptor = null;
144 // THIS OBJECT MUST NEVER BE MODIFIED, without first calling CREATE. 144 // THIS OBJECT MUST NEVER BE MODIFIED, without first calling CREATE.
145 $oFakeAlloc = new DocumentRoleAllocation(); 145 $oFakeAlloc = new DocumentRoleAllocation();
lib/roles/roleallocation.inc.php
@@ -101,6 +101,10 @@ class RoleAllocation extends KTEntity { @@ -101,6 +101,10 @@ class RoleAllocation extends KTEntity {
101 $fTable = Folder::_table(); 101 $fTable = Folder::_table();
102 102
103 $oFolder =& Folder::get($iFolderId); 103 $oFolder =& Folder::get($iFolderId);
  104 + // if its an invalid folder, we simply return null, since this is undefined anyway.
  105 + if (PEAR::isError($oFolder)) {
  106 + return null;
  107 + }
104 $parents = Folder::generateFolderIds($iFolderId); 108 $parents = Folder::generateFolderIds($iFolderId);
105 109
106 // FIXME what (if anything) do we need to do to check that this can't be used as an attack? 110 // FIXME what (if anything) do we need to do to check that this can't be used as an attack?
lib/session/Session.inc
@@ -92,14 +92,17 @@ class Session { @@ -92,14 +92,17 @@ class Session {
92 $iUserID = $_SESSION["userID"]; 92 $iUserID = $_SESSION["userID"];
93 93
94 // remove the session information from the database 94 // remove the session information from the database
95 - $sql = $default->db;  
96 - $query = "DELETE FROM $default->sessions_table WHERE session_id = '$sSessionID'" . ($iUserID ? " AND user_id=$iUserID" : "");  
97 - $default->log->info("Session::destroy $query");  
98 - $sql->query($query); 95 +
  96 + $sTable = KTUtil::getTableName('sessions');
  97 + $res = DBUtil::whereDelete($sTable, array('session_id' => $sSessionID));
  98 +
  99 +
99 100
100 // remove the php4 session 101 // remove the php4 session
  102 + unset($_SESSION['userID']);
  103 + unset($_SESSION['sessionStatus']);
101 session_unset(); 104 session_unset();
102 - session_destroy(); 105 + session_destroy();
103 } 106 }
104 107
105 /** 108 /**
@@ -139,6 +142,7 @@ class Session { @@ -139,6 +142,7 @@ class Session {
139 142
140 // this should be an existing session, so check the db 143 // this should be an existing session, so check the db
141 $aRows = DBUtil::getResultArray(array("SELECT * FROM $default->sessions_table WHERE session_id = ?", $sessionID)); 144 $aRows = DBUtil::getResultArray(array("SELECT * FROM $default->sessions_table WHERE session_id = ?", $sessionID));
  145 +
142 $numrows = count($aRows); 146 $numrows = count($aRows);
143 147
144 // FIXME: if there aren't more rows that the max sessions for this user 148 // FIXME: if there aren't more rows that the max sessions for this user
@@ -151,10 +155,14 @@ class Session { @@ -151,10 +155,14 @@ class Session {
151 155
152 $default->log->debug("Session::verify found session in db"); 156 $default->log->debug("Session::verify found session in db");
153 $aRow = $aRows[0]; 157 $aRow = $aRows[0];
154 - // foreach ($aRows as $aRow) {  
155 158
156 $iUserID = $aRow["user_id"]; 159 $iUserID = $aRow["user_id"];
157 - 160 +
  161 + $oKTConfig = KTConfig::getSingleton();
  162 + $allowAnon = $oKTConfig->get('allowAnonymousLogin', false);
  163 + $ANON = -2;
  164 + if ((!allowAnon) && ($iUserId == $ANON)) { return false; }
  165 +
158 // check that ip matches 166 // check that ip matches
159 $ip = $this->getClientIP(); 167 $ip = $this->getClientIP();
160 if ($ip != trim($aRow["ip"])) { 168 if ($ip != trim($aRow["ip"])) {
lib/session/control.inc
@@ -143,12 +143,17 @@ function checkSessionAndRedirect($bRedirect, $bDownload = false) { @@ -143,12 +143,17 @@ function checkSessionAndRedirect($bRedirect, $bDownload = false) {
143 if (PEAR::isError($sessionStatus)) { 143 if (PEAR::isError($sessionStatus)) {
144 $sErrorMessage = $sessionStatus->getMessage(); 144 $sErrorMessage = $sessionStatus->getMessage();
145 } 145 }
  146 +
  147 + $oKTConfig = KTConfig::getSingleton();
  148 + $dest = 'login';
  149 + if ($oKTConfig->get('allowAnonymousLogin', false)) { $dest = 'dashboard'; }
  150 +
146 // redirect to login with error message 151 // redirect to login with error message
147 if ($sErrorMessage) { 152 if ($sErrorMessage) {
148 // session timed out 153 // session timed out
149 - $url = generateControllerUrl("login", "errorMessage=" . urlencode($sErrorMessage)); 154 + $url = generateControllerUrl($dest, "errorMessage=" . urlencode($sErrorMessage));
150 } else { 155 } else {
151 - $url = generateControllerUrl("login"); 156 + $url = generateControllerUrl($dest);
152 } 157 }
153 158
154 $redirect = urlencode(KTUtil::addQueryStringSelf($_SERVER["QUERY_STRING"])); 159 $redirect = urlencode(KTUtil::addQueryStringSelf($_SERVER["QUERY_STRING"]));
lib/templating/kt3template.inc.php
@@ -123,10 +123,7 @@ class KTPage { @@ -123,10 +123,7 @@ class KTPage {
123 "administration" => $this->_actionHelper(array("name" => _kt("DMS Administration"), "action" => "administration", "active" => 0)), 123 "administration" => $this->_actionHelper(array("name" => _kt("DMS Administration"), "action" => "administration", "active" => 0)),
124 ); 124 );
125 125
126 - $this->userMenu = array(  
127 - "preferences" => $this->_actionHelper(array("name" => _kt("Preferences"), "action" => "preferences", "active" => 0)),  
128 - "logout" => $this->_actionHelper(array("name" => _kt("Logout"), "action" => "logout", "active" => 0)),  
129 - ); 126 +
130 } 127 }
131 128
132 129
@@ -303,6 +300,18 @@ class KTPage { @@ -303,6 +300,18 @@ class KTPage {
303 } 300 }
304 } 301 }
305 302
  303 + $this->userMenu = array();
  304 + if (!(PEAR::isError($this->user) || is_null($this->user) || $this->user->isAnonymous())) {
  305 + $this->userMenu = array(
  306 + "preferences" => $this->_actionHelper(array("name" => _kt("Preferences"), "action" => "preferences", "active" => 0)),
  307 + "logout" => $this->_actionHelper(array("name" => _kt("Logout"), "action" => "logout", "active" => 0)),
  308 + );
  309 + } else {
  310 + $this->userMenu = array(
  311 + "login" => $this->_actionHelper(array("name" => _kt("Login"), "action" => "login")),
  312 + );
  313 + }
  314 +
306 // FIXME we need a more complete solution to navigation restriction 315 // FIXME we need a more complete solution to navigation restriction
307 if (!is_null($this->menu['administration']) && !is_null($this->user)) { 316 if (!is_null($this->menu['administration']) && !is_null($this->user)) {
308 if (!Permission::userIsSystemAdministrator($this->user->getId())) { 317 if (!Permission::userIsSystemAdministrator($this->user->getId())) {
lib/users/User.inc
@@ -285,4 +285,6 @@ class User extends KTEntity { @@ -285,4 +285,6 @@ class User extends KTEntity {
285 'last_login' => array('type' => 'after', 'value' => $dDateTime), 285 'last_login' => array('type' => 'after', 'value' => $dDateTime),
286 ), array('multi' => true)); 286 ), array('multi' => true));
287 } 287 }
  288 +
  289 + function isAnonymous() { return $this->iId == -2; }
288 } 290 }
lib/util/ktutil.inc
@@ -587,6 +587,52 @@ class KTUtil { @@ -587,6 +587,52 @@ class KTUtil {
587 } 587 }
588 return null; 588 return null;
589 } 589 }
  590 +
  591 + function getSystemSetting($name, $default = null) {
  592 + // XXX make this use a cache layer?
  593 + $sTable = KTUtil::getTableName('system_settings');
  594 + $aQuery = array(
  595 + sprintf('SELECT value FROM %s WHERE name = ?', $sTable),
  596 + array($name),
  597 + );
  598 + $res = DBUtil::getOneResultKey($aQuery, 'value');
  599 + if (PEAR::isError($res)) {
  600 + return PEAR::raiseError(sprintf(_kt('Unable to retrieve system setting %s: %s'), $name, $res->getMessage()));
  601 + }
  602 +
  603 + if (empty($res)) { return $default; }
  604 +
  605 + return $res;
  606 + }
  607 +
  608 + function setSystemSetting($name, $value) {
  609 + // we either need to insert or update:
  610 + $sTable = KTUtil::getTableName('system_settings');
  611 + $current_value = KTUtil::getSystemSetting($name);
  612 + if (is_null($current_value)) {
  613 + // insert
  614 + $res = DBUtil::autoInsert(
  615 + $sTable,
  616 + array(
  617 + 'name' => $name,
  618 + 'value' => $value,
  619 + ),
  620 + null // opts
  621 + );
  622 + if (PEAR::isError($res)) { return $res; }
  623 + else { return true; }
  624 + } else {
  625 + // update
  626 + $aQuery = array(
  627 + sprintf('UPDATE %s SET value = ? WHERE name = ?', $sTable),
  628 + array($value, $name),
  629 + );
  630 + $res = DBUtil::runQuery($aQuery);
  631 + if (PEAR::isError($res)) { return $res; }
  632 + return true;
  633 + }
  634 + }
  635 +
590 } 636 }
591 637
592 /** 638 /**
login.php
@@ -37,9 +37,15 @@ require_once(KT_LIB_DIR . &#39;/authentication/authenticationutil.inc.php&#39;); @@ -37,9 +37,15 @@ require_once(KT_LIB_DIR . &#39;/authentication/authenticationutil.inc.php&#39;);
37 class LoginPageDispatcher extends KTDispatcher { 37 class LoginPageDispatcher extends KTDispatcher {
38 38
39 function check() { 39 function check() {
  40 + $oKTConfig = KTConfig::getSingleton();
40 $this->session = new Session(); 41 $this->session = new Session();
41 - if ($this->session->verify() == 1) { // erk. neil - DOUBLE CHECK THIS PLEASE.  
42 - exit(redirect(generateControllerLink('dashboard'))); 42 + if ($this->session->verify() == 1) { // the session is valid
  43 + if ($_SESSION['userID'] == -2 && $oKTConfig->get('allowAnonymousLogin', false)) {
  44 + ; // that's ok - we want to login.
  45 + }
  46 + else {
  47 + exit(redirect(generateControllerLink('dashboard')));
  48 + }
43 } else { 49 } else {
44 $this->session->destroy(); // toast it - its probably a hostile session. 50 $this->session->destroy(); // toast it - its probably a hostile session.
45 } 51 }
plugins/ktcore/KTPermissions.php
@@ -165,7 +165,7 @@ class KTRoleAllocationPlugin extends KTFolderAction { @@ -165,7 +165,7 @@ class KTRoleAllocationPlugin extends KTFolderAction {
165 // - and that allocation id 165 // - and that allocation id
166 $aRoles = array(); // stores data for display. 166 $aRoles = array(); // stores data for display.
167 167
168 - $aRoleList = Role::getList(); 168 + $aRoleList = Role::getList('id > 0');
169 foreach ($aRoleList as $oRole) { 169 foreach ($aRoleList as $oRole) {
170 $iRoleId = $oRole->getId(); 170 $iRoleId = $oRole->getId();
171 $aRoles[$iRoleId] = array("name" => $oRole->getName()); 171 $aRoles[$iRoleId] = array("name" => $oRole->getName());
@@ -541,7 +541,9 @@ class KTRoleAllocationPlugin extends KTFolderAction { @@ -541,7 +541,9 @@ class KTRoleAllocationPlugin extends KTFolderAction {
541 } 541 }
542 542
543 foreach ($aDocList as $oDoc) { 543 foreach ($aDocList as $oDoc) {
544 - KTPermissionUtil::updatePermissionLookup($oDoc); 544 + if (!PEAR::isError($oDoc)) {
  545 + KTPermissionUtil::updatePermissionLookup($oDoc);
  546 + }
545 } 547 }
546 } 548 }
547 } 549 }
plugins/ktcore/admin/groupManagement.php
@@ -64,9 +64,9 @@ class KTGroupAdminDispatcher extends KTAdminDispatcher { @@ -64,9 +64,9 @@ class KTGroupAdminDispatcher extends KTAdminDispatcher {
64 $search_fields[] = new KTStringWidget(_kt('Group Name'), _kt("Enter part of the group's name. e.g. <strong>ad</strong> will match <strong>administrators</strong>."), 'name', $name, $this->oPage, true); 64 $search_fields[] = new KTStringWidget(_kt('Group Name'), _kt("Enter part of the group's name. e.g. <strong>ad</strong> will match <strong>administrators</strong>."), 'name', $name, $this->oPage, true);
65 65
66 if (!empty($name)) { 66 if (!empty($name)) {
67 - $search_results =& Group::getList('WHERE name LIKE \'%' . DBUtil::escapeSimple($name) . '%\''); 67 + $search_results =& Group::getList('WHERE name LIKE \'%' . DBUtil::escapeSimple($name) . '%\' AND id > 0');
68 } else if ($show_all !== false) { 68 } else if ($show_all !== false) {
69 - $search_results =& Group::getList(); 69 + $search_results =& Group::getList('id > 0');
70 $no_search = false; 70 $no_search = false;
71 } 71 }
72 72
@@ -211,7 +211,7 @@ class KTGroupAdminDispatcher extends KTAdminDispatcher { @@ -211,7 +211,7 @@ class KTGroupAdminDispatcher extends KTAdminDispatcher {
211 $this->oPage->requireJSStandalone($initJS); 211 $this->oPage->requireJSStandalone($initJS);
212 212
213 $aInitialUsers = $oGroup->getMembers(); 213 $aInitialUsers = $oGroup->getMembers();
214 - $aAllUsers = User::getList(); 214 + $aAllUsers = User::getList('id > 0');
215 215
216 216
217 // FIXME this is massively non-performant for large userbases.. 217 // FIXME this is massively non-performant for large userbases..
plugins/ktcore/admin/roleManagement.php
@@ -41,7 +41,11 @@ class RoleAdminDispatcher extends KTAdminDispatcher { @@ -41,7 +41,11 @@ class RoleAdminDispatcher extends KTAdminDispatcher {
41 41
42 $edit_fields = array(); 42 $edit_fields = array();
43 $role_id = KTUtil::arrayGet($_REQUEST, 'role_id', null); 43 $role_id = KTUtil::arrayGet($_REQUEST, 'role_id', null);
44 - $oRole = Role::get($role_id); 44 + if (is_null($role_id)) {
  45 + $oRole = null; // handle broken case of role == -1
  46 + } else {
  47 + $oRole = Role::get($role_id);
  48 + }
45 49
46 if (PEAR::isError($oRole) || ($oRole == false)) { $for_edit = false; } 50 if (PEAR::isError($oRole) || ($oRole == false)) { $for_edit = false; }
47 else { 51 else {
plugins/ktcore/admin/userManagement.php
@@ -68,9 +68,9 @@ class KTUserAdminDispatcher extends KTAdminDispatcher { @@ -68,9 +68,9 @@ class KTUserAdminDispatcher extends KTAdminDispatcher {
68 // FIXME handle group search stuff. 68 // FIXME handle group search stuff.
69 $search_results = null; 69 $search_results = null;
70 if (!empty($name)) { 70 if (!empty($name)) {
71 - $search_results =& User::getList('WHERE username LIKE \'%' . DBUtil::escapeSimple($name) . '%\''); 71 + $search_results =& User::getList('WHERE username LIKE \'%' . DBUtil::escapeSimple($name) . '%\' AND id > 0');
72 } else if ($show_all !== false) { 72 } else if ($show_all !== false) {
73 - $search_results =& User::getList(); 73 + $search_results =& User::getList('id > 0');
74 $no_search = false; 74 $no_search = false;
75 } 75 }
76 76
plugins/ktcore/admin/workflows.php
@@ -1330,6 +1330,22 @@ class KTWorkflowDispatcher extends KTAdminDispatcher { @@ -1330,6 +1330,22 @@ class KTWorkflowDispatcher extends KTAdminDispatcher {
1330 'redirect_to' => array('editTransition', 'fWorkflowId=' . $oWorkflow->getId() . '&fTransitionId=' . $oTransition->getId()), 1330 'redirect_to' => array('editTransition', 'fWorkflowId=' . $oWorkflow->getId() . '&fTransitionId=' . $oTransition->getId()),
1331 'message' => _kt('Error saving transition'), 1331 'message' => _kt('Error saving transition'),
1332 )); 1332 ));
  1333 +
  1334 + // also grab the list of transitions for the dest state, and remove this one if application
  1335 + $aDestTransitions = KTWorkflowUtil::getTransitionsFrom($oState, array('ids' => true));
  1336 + $bClean = true;
  1337 + $aNewTransitions = array();
  1338 + foreach ($aDestTransitions as $iOldTransitionId) {
  1339 + if ($oTransition->getId() == $iOldTransitionId) {
  1340 + $bClean = false;
  1341 + } else {
  1342 + $aNewTransitions[] = $iOldTransitionId;
  1343 + }
  1344 + }
  1345 + if (!$bClean) {
  1346 + KTWorkflowUtil::saveTransitionsFrom($oState, $aNewTransitions);
  1347 + }
  1348 +
1333 $this->successRedirectTo('editTransition', _kt('Changes saved'), 'fWorkflowId=' . $oWorkflow->getId() . '&fTransitionId=' . $oTransition->getId()); 1349 $this->successRedirectTo('editTransition', _kt('Changes saved'), 'fWorkflowId=' . $oWorkflow->getId() . '&fTransitionId=' . $oTransition->getId());
1334 exit(0); 1350 exit(0);
1335 } 1351 }
plugins/ktcore/folder/BulkImport.php
@@ -63,7 +63,7 @@ class KTBulkImportFolderAction extends KTFolderAction { @@ -63,7 +63,7 @@ class KTBulkImportFolderAction extends KTFolderAction {
63 $add_fields[] = new KTStringWidget(_kt('Path'), _kt('The path containing the documents to be added to the document management system.'), 'path', "", $this->oPage, true); 63 $add_fields[] = new KTStringWidget(_kt('Path'), _kt('The path containing the documents to be added to the document management system.'), 'path', "", $this->oPage, true);
64 64
65 $aVocab = array('' => _kt('&lt;Please select a document type&gt;')); 65 $aVocab = array('' => _kt('&lt;Please select a document type&gt;'));
66 - foreach (DocumentType::getList() as $oDocumentType) { 66 + foreach (DocumentType::getListForUserAndFolder($this->oUser, $this->oFolder) as $oDocumentType) {
67 if(!$oDocumentType->getDisabled()) { 67 if(!$oDocumentType->getDisabled()) {
68 $aVocab[$oDocumentType->getId()] = $oDocumentType->getName(); 68 $aVocab[$oDocumentType->getId()] = $oDocumentType->getName();
69 } 69 }
plugins/ktcore/folder/BulkUpload.php
@@ -70,7 +70,7 @@ class KTBulkUploadFolderAction extends KTFolderAction { @@ -70,7 +70,7 @@ class KTBulkUploadFolderAction extends KTFolderAction {
70 $add_fields[] = new KTFileUploadWidget(_kt('Archive file'), _kt('The archive file containing the documents you wish to add to the document management system.'), 'file', "", $this->oPage, true); 70 $add_fields[] = new KTFileUploadWidget(_kt('Archive file'), _kt('The archive file containing the documents you wish to add to the document management system.'), 'file', "", $this->oPage, true);
71 71
72 $aVocab = array('' => _kt('&lt;Please select a document type&gt;')); 72 $aVocab = array('' => _kt('&lt;Please select a document type&gt;'));
73 - foreach (DocumentType::getList() as $oDocumentType) { 73 + foreach (DocumentType::getListForUserAndFolder($this->oUser, $this->oFolder) as $oDocumentType) {
74 if(!$oDocumentType->getDisabled()) { 74 if(!$oDocumentType->getDisabled()) {
75 $aVocab[$oDocumentType->getId()] = $oDocumentType->getName(); 75 $aVocab[$oDocumentType->getId()] = $oDocumentType->getName();
76 } 76 }
plugins/ktcore/folder/addDocument.php
@@ -74,7 +74,7 @@ class KTFolderAddDocumentAction extends KTFolderAction { @@ -74,7 +74,7 @@ class KTFolderAddDocumentAction extends KTFolderAction {
74 74
75 75
76 $aVocab = array('' => _kt('&lt;Please select a document type&gt;')); 76 $aVocab = array('' => _kt('&lt;Please select a document type&gt;'));
77 - foreach (DocumentType::getList() as $oDocumentType) { 77 + foreach (DocumentType::getListForUserAndFolder($this->oUser, $this->oFolder) as $oDocumentType) {
78 if(!$oDocumentType->getDisabled()) { 78 if(!$oDocumentType->getDisabled()) {
79 $aVocab[$oDocumentType->getId()] = $oDocumentType->getName(); 79 $aVocab[$oDocumentType->getId()] = $oDocumentType->getName();
80 } 80 }
preferences.php
@@ -39,6 +39,11 @@ require_once(KT_LIB_DIR . &#39;/widgets/fieldWidgets.php&#39;); @@ -39,6 +39,11 @@ require_once(KT_LIB_DIR . &#39;/widgets/fieldWidgets.php&#39;);
39 class PreferencesDispatcher extends KTStandardDispatcher { 39 class PreferencesDispatcher extends KTStandardDispatcher {
40 var $sSection = 'preferences'; 40 var $sSection = 'preferences';
41 41
  42 + function check() {
  43 + if ($this->oUser->getId() == -2) { return false; }
  44 + return parent::check();
  45 + }
  46 +
42 function PreferencesDispatcher() { 47 function PreferencesDispatcher() {
43 $this->aBreadcrumbs = array( 48 $this->aBreadcrumbs = array(
44 array('action' => 'preferences', 'name' => _kt('Preferences')), 49 array('action' => 'preferences', 'name' => _kt('Preferences')),
sql/mysql/install/data.sql
@@ -657,7 +657,7 @@ INSERT INTO `plugins` VALUES (15, &#39;nbm.browseable.plugin&#39;, &#39;plugins/browseableda @@ -657,7 +657,7 @@ INSERT INTO `plugins` VALUES (15, &#39;nbm.browseable.plugin&#39;, &#39;plugins/browseableda
657 -- Dumping data for table `roles` 657 -- Dumping data for table `roles`
658 -- 658 --
659 659
660 -INSERT INTO `roles` VALUES (-1, 'Owner'); 660 +INSERT INTO `roles` VALUES (-2, 'Owner');
661 661
662 -- 662 --
663 -- Dumping data for table `saved_searches` 663 -- Dumping data for table `saved_searches`
sql/mysql/upgrade/3.0.1.2/owner_role_move.sql 0 → 100644
  1 +UPDATE roles SET id = -2 WHERE id = -1;
templates/kt3/standard_page.smarty
@@ -70,8 +70,9 @@ @@ -70,8 +70,9 @@
70 <li class="pref">{if ($page->user)} 70 <li class="pref">{if ($page->user)}
71 <span class="ktLoggedInUser">{$page->user->getName()}</span> 71 <span class="ktLoggedInUser">{$page->user->getName()}</span>
72 {/if} 72 {/if}
  73 + {if !empty($page->userMenu)}
73 &middot; 74 &middot;
74 - 75 + {/if}
75 76
76 {foreach item=aMenuItem from=$page->userMenu name=prefmenu} 77 {foreach item=aMenuItem from=$page->userMenu name=prefmenu}
77 {if ($aMenuItem.active == 1)} 78 {if ($aMenuItem.active == 1)}