diff --git a/HISTORY.txt b/HISTORY.txt index 950d79e..5f270f9 100644 --- a/HISTORY.txt +++ b/HISTORY.txt @@ -10,6 +10,7 @@ Features: Fixes: + - Made help able to work across multiple languages - KTS-972 Owner, Everyone and Authenticated weren't being respected by browse and search - KTS-959 Documents weren't properly purged from the cache on change. diff --git a/help.php b/help.php index 2b4a46c..9c5acbc 100644 --- a/help.php +++ b/help.php @@ -71,20 +71,76 @@ class HelpDispatcher extends KTStandardDispatcher { function do_main() { // store referer $sBackKey = KTUtil::arrayGet($_REQUEST, 'back_key', false); + $sSubPath = KTUtil::arrayGet($_SERVER, 'PATH_INFO'); + + // we want to be able to say "i left the system at point x. go back there" if(!$sBackKey) { $sReferer = KTUtil::arrayGet($_SERVER ,'HTTP_REFERER'); $sBackKey = KTUtil::randomString(); $_SESSION[$sBackKey] = $sReferer; } - $pathinfo = KTUtil::arrayGet($_SERVER, 'PATH_INFO'); - if (empty($pathinfo)) { + // no path specified + if (empty($sSubPath)) { $this->oPage->setTitle(_kt('No help page specified.')); $this->oPage->addError(_kt('No help page specified.')); return ' '; } - $can_edit = Permission::userIsSystemAdministrator($_SESSION['userID']); + // simple test to see if this user is active. + $bCanEdit = Permission::userIsSystemAdministrator($_SESSION['userID']); + + global $default; + $sLangCode = $default->defaultLanguage; + /* + now we need to know a few things. + 1. can we find this help file? + 2. if we can, display it + 2.1 images directly + 2.2 html wrapped. + 3. if now, fail out. + + this is essentially handled by asking help.inc.php for the + subpath we've been given, PLUS THE LANGUAGE, and checking for + a PEAR::raiseError. + + The "Correct" response we care about is a dictionary: + + { + 'is_image': string + 'title': string + 'body': string + } + */ + + $aHelpData = KTHelp::getHelpInfo($sSubPath); + + if (PEAR::isError($aHelpData)) { + $this->oPage->setTitle($aHelpData->getMessage()); + $this->oPage->addError($aHelpData->getMessage()); + return ' '; + } + + $aLocInfo = KTHelp::_getLocationInfo($sSubPath); + + if ($aHelpData['is_image']) { + KTHelp::outputHelpImage($sSubPath); + exit(0); // done. + } else { + $this->oPage->setTitle($aHelpData['title']); + $this->aBreadcrumbs[] = array('url' => $_SERVER['PHP_SELF'], 'name' => $aHelpData['title']); + $oTemplating =& KTTemplating::getSingleton(); + $oTemplate = $oTemplating->loadTemplate("ktcore/help_with_edit"); + $aTemplateData = array( + "context" => $this, + "help_body" => $aHelpData['body'], + "target_name" => KTUtil::arrayGet($aLocInfo, 'internal'), + "back_key" => $sBackKey, + 'can_edit' => $bCanEdit, + ); + return $oTemplate->render($aTemplateData); + } + /* $help_path = KTHelp::getHelpSubPath($pathinfo); if ($help_path == false) { @@ -100,7 +156,7 @@ class HelpDispatcher extends KTStandardDispatcher { KTHelp::outputHelpImage($help_path); } else { // not an image, so: - $aHelpInfo = KTHelp::getHelpFromFile($pathinfo); + $aHelpInfo = KTHelp::getHelpFromFile($pathinfo) } @@ -129,16 +185,7 @@ class HelpDispatcher extends KTStandardDispatcher { $this->oPage->setTitle($aHelpInfo['title']); $this->aBreadcrumbs[] = array('url' => $_SERVER['PHP_SELF'], 'name' => $aHelpInfo['title']); - $oTemplating =& KTTemplating::getSingleton(); - $oTemplate = $oTemplating->loadTemplate("ktcore/help_with_edit"); - $aTemplateData = array( - "context" => $this, - "help_body" => $aHelpInfo['body'], - "target_name" => $_SERVER['PATH_INFO'], - "back_key" => $sBackKey, - 'can_edit' => $can_edit, - ); - return $oTemplate->render($aTemplateData); + */ } function do_go_back() { diff --git a/lib/help/help.inc.php b/lib/help/help.inc.php index 7c735a1..7f7801e 100644 --- a/lib/help/help.inc.php +++ b/lib/help/help.inc.php @@ -31,64 +31,7 @@ require_once(KT_LIB_DIR . "/database/dbutil.inc"); class KTHelp { - - function getHelpSubPath($sHelpFile) { - if (empty($sHelpFile)) { return false; } - $path_segments = explode("/", $sHelpFile); - // cannot be empty, must contain at _least_ 1 item. - if (empty($path_segments[0])) { - $path_segments = array_slice($path_segments,1); - } - - if (empty($path_segments) or (count($path_segments) < 2)) { - return false; // FIXME use PEAR::Error - } - - // we now assume that path_segments[0] is the module - // path_segments[1..] is the subpath. we need to insert the LANG - - $lang_code = 'EN'; // FIXME extract the lang from the environ (?) - - $final_path = array(null,'kthelp', $path_segments[0]); - $final_path[] = $lang_code; - $final_path = kt_array_merge($final_path, array_slice($path_segments, 1)); - - $help_path = implode('/',$final_path); - - return $help_path; - } - - function getHelpFromFile($sHelpFile) { - if (empty($sHelpFile)) { return false; } - $help_path = KTHelp::getHelpSubPath($sHelpFile); - - $fspath = KT_DIR . $help_path; // FIXME use OS.path_sep equivalent? - - if (!file_exists($fspath)) { - return false; - } - - if (KTHelp::isImageFile($help_path)) { - return false; // can't - not what users expect. - } - - // now we ASSUME its html: we'll fail anyway if we aren't. - $handle = fopen($fspath, "r"); - $contents = fread($handle, filesize($fspath)); - fclose($handle); - - $info = KTHelp::_parseHTML($contents); - - $body = KTUtil::arrayGet($info,'body'); - if (empty($body)) { - return false; - } - - $info['name'] = $help_path; // set so we can save into db if needed. - - return $info; - } - + // world's simplest (and possibly worst) regex-split. function _parseHTML($sHTML) { $title_array = preg_split('##',$sHTML,-1,PREG_SPLIT_NO_EMPTY); @@ -107,11 +50,10 @@ class KTHelp { return $res; } - function isImageFile($sHelpPath) { - // from pluginutil.inc.php - $fspath = KT_DIR . $sHelpPath; - - $pi = pathinfo($fspath); + // $sFSPath : filesystem path for the resource. + // return true or false + function isImageFile($sFSPath) { + $pi = pathinfo($sFSPath); $mime_type = ""; $sExtension = KTUtil::arrayGet($pi, 'extension'); if (!empty($sExtension)) { @@ -125,9 +67,18 @@ class KTHelp { return false; } - function outputHelpImage($sHelpPath) { - $fspath = KT_DIR . $sHelpPath; - + // output the help image referred to by the subpath + function outputHelpImage($sSubPath) { + // FIXME there are error cases here ... + $aPathInfo = KTHelp::_getLocationInfo($sSubPath); + if (PEAR::isError($aPathInfo)) { return $aPathInfo; } // gets caught further up the stack + + $pi = pathinfo($aPathInfo['external']); + $mime_type = ""; + $sExtension = KTUtil::arrayGet($pi, 'extension'); + if (!empty($sExtension)) { + $mime_type = DBUtil::getOneResultKey(array("SELECT mimetypes FROM " . KTUtil::getTableName('mimetypes') . " WHERE LOWER(filetypes) = ?", $sExtension), "mimetypes"); + } header("Content-Type: $mime_type"); header("Content-Length: " . filesize($fspath)); @@ -135,6 +86,144 @@ class KTHelp { exit(0); } + /* + input: + sSubPath : the path in the form "plugin/lower-level-file" + sLangCode : the language code in the form "en_US" + + returns a dictionary + { + 'is_image': string + 'title': string + 'body': string + } + */ + function getHelpInfo($sSubPath, $sLangCode = null) { + $aInfo = array( + 'is_image' => false, + 'title' => null, + 'body' => null, + 'help_id' => null, + ); + $aPathInfo = KTHelp::_getLocationInfo($sSubPath, $sLangCode); + if (PEAR::isError($aPathInfo)) { + return $aPathInfo; + } + + // first, check the extension to see if its an image. + // failing that, check the DB for an entry (+ return if found) + // failing that, check the FS for the entry (+ return if found) + // failing that, through an exception. + + if (KTHelp::isImageFile($aPathInfo['external'])) { + $aInfo['is_image'] = true; + return $aInfo; + } + + // check DB + $oReplacement =& KTHelpReplacement::getByName($aPathInfo['internal']); + if (!PEAR::isError($oReplacement)) { + $aInfo['title'] = $oReplacement->getTitle(); + $aInfo['body'] = $oReplacement->getDescription(); + $aInfo['help_id'] = $oReplacement->getID(); + return $aInfo; + } + + // check FS + if (!file_exists($aPathInfo['external'])) { + return PEAR::raiseError(_kt("Unable to locate the requested help file for this language.")); + } + + // so it might exist in some form. + $contents = file_get_contents($aPathInfo['external']); + + $aData = KTHelp::_parseHTML($contents); + + $aInfo['body'] = KTUtil::arrayGet($aData,'body'); + if (empty($aInfo['body'])) { + return PEAR::raiseError(_kt("The requested help language has no contents.")); + } + $aInfo['title'] = KTUtil::arrayGet($aData, 'title', _kt("Untitled Help File")); + + return $aInfo; + } + + function _getLocationInfo($sSubPath, $sLangCode = null) { + // FIXME use a cheap cache here? is it even worth it? + $aInfo = array( + 'subpath' => null, + 'internal' => null, + 'external' => null, + ); + + $oHelpReg =& KTHelpRegistry::getSingleton(); + + if (is_null($sLangCode)) { + global $default; + $sLangCode = $default->defaultLanguage; + } + + $aParts = explode('/', $sSubPath); + + if (count($aParts) < 2) { + return PEAR::raiseError(_kt("Too few parts to the requested help location.")); + } + + $sPluginName = $aParts[0]; + $sSubLocation = implode('/', array_slice($aParts, 1)); + + $sInternalName = sprintf("%s/%s/%s", $sPluginName, $sLangCode, $sSubLocation); + + // this is a pseudo-name. essentially, this maps to the canonical + // name of the help file in the database, NOT to the filesystem + + //$sBaseDir = sprintf("%s/kthelp/%s/%s", KT_DIR, $sPluginName, $sLangCode); + $sBaseDir = $oHelpReg->getBaseDir($sPluginName, $sLangCode); + + if (PEAR::isError($sBaseDir)) { return $sBaseDir; } + $sExternalName = sprintf("%s/%s", $sBaseDir, $sSubLocation); + + $aInfo['subpath'] = $sSubPath; + $aInfo['internal'] = $sInternalName; + $aInfo['external'] = $sExternalName; + + return $aInfo; + } +} + +class KTHelpRegistry { + var $plugin_lang_map; + + function KTHelpRegistry() { + $this->plugin_lang_map = array(); + } + + function &getSingleton () { + if (!KTUtil::arrayGet($GLOBALS, 'oKTHelpRegistry')) { + $GLOBALS['oKTHelpRegistry'] = new KTHelpRegistry; + } + + return $GLOBALS['oKTHelpRegistry']; + } + + function registerHelp($sPluginName, $sLang, $sBaseDir) { + $lang_map = KTUtil::arrayGet($this->plugin_lang_map, $sPluginName, array()); + $lang_map[$sLang] = $sBaseDir; + $this->plugin_lang_map[$sPluginName] = $lang_map; + } + + function getBaseDir($sPluginName, $sLangCode) { + $lang_map = KTUtil::arrayGet($this->plugin_lang_map, $sPluginName); + + if (is_null($lang_map)) { + return PEAR::raiseError(_kt("There is no help available in your language for this plugin")); + } + $sBaseDir = KTUtil::arrayGet($lang_map, $sLangCode); + if (is_null($sBaseDir)) { + return PEAR::raiseError(_kt("There is no help available in your language for this plugin")); + } + return $sBaseDir; + } } ?> diff --git a/plugins/ktcore/KTDashlets.php b/plugins/ktcore/KTDashlets.php index 3b6d011..f599282 100644 --- a/plugins/ktcore/KTDashlets.php +++ b/plugins/ktcore/KTDashlets.php @@ -46,15 +46,13 @@ class KTInfoDashlet extends KTBaseDashlet { $aHelpInfo = array(); $can_edit = Permission::userIsSystemAdministrator($_SESSION['userID']); - $help_path = KTHelp::getHelpSubPath($this->helpLocation); - if ($help_path == false) { + $help_path = KTHelp::_getLocationInfo($this->helpLocation); + if (PEAR::isError($help_path)) { return false; } // We now check for substitute help files. try to generate an error. - $oReplacementHelp = KTHelpReplacement::getByName($help_path); - - $aHelpInfo = KTHelp::getHelpFromFile($this->helpLocation); + $aHelpInfo = KTHelp::getHelpInfo($this->helpLocation); // NORMAL users never see edit-option. if (!$can_edit) { @@ -67,19 +65,6 @@ class KTInfoDashlet extends KTBaseDashlet { } } - - - if (!PEAR::isError($oReplacementHelp)) { - $aHelpInfo['title'] = $oReplacementHelp->getTitle(); - $aHelpInfo['body'] = $oReplacementHelp->getDescription(); - $this->help_id = $oReplacementHelp->getId(); - - } else { - $this->help_id = null; - } - - if (empty($aHelpInfo)) { return false; } - $this->aHelpInfo = $aHelpInfo; $this->canEdit = $can_edit; @@ -97,7 +82,7 @@ class KTInfoDashlet extends KTBaseDashlet { 'body' => $this->aHelpInfo['body'], 'can_edit' => $this->canEdit, 'target_name' => $this->helpLocation, - 'help_id' => $this->help_id, + 'help_id' => $this->aHelpInfo['help_id'], ); return $oTemplate->render($aTemplateData); } diff --git a/plugins/ktcore/admin/manageHelp.php b/plugins/ktcore/admin/manageHelp.php index 76233f5..25396b3 100755 --- a/plugins/ktcore/admin/manageHelp.php +++ b/plugins/ktcore/admin/manageHelp.php @@ -126,19 +126,19 @@ class ManageHelpDispatcher extends KTAdminDispatcher { function do_customise() { $name = KTUtil::arrayGet($_REQUEST, 'name'); - $subname = KTHelp::getHelpSubPath($name); - $oHelpReplacement = KTHelpReplacement::getByName($subname); + $aPathInfo = KTHelp::_getLocationInfo($name); + $oHelpReplacement = KTHelpReplacement::getByName($aPathInfo['internal']); // XXX: Check against "already exists" //var_dump($name); if (!PEAR::isError($oHelpReplacement)) { // Already exists... - return $this->errorRedirectTo('editReplacement', _kt('Replacement already exists.'),'id=' . $oHelpReplacement->getId()); + return $this->successRedirectTo('editReplacement', _kt('Replacement already exists. Editing the existing copy instead of replacing.'),'id=' . $oHelpReplacement->getId()); } - $info = KTHelp::getHelpFromFile($name); - if ($info === false) { + $info = KTHelp::getHelpInfo($name); + if (PEAR::isError($info)) { $info = array('name' => $name); $info['title'] = _kt('New Help File'); $info['body'] = _kt('New Help File');