. * * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, * California 94120-7775, or email info@knowledgetree.com. * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU General Public License version 3. * * In accordance with Section 7(b) of the GNU General Public License version 3, * these Appropriate Legal Notices must retain the display of the "Powered by * KnowledgeTree" logo and retain the original copyright notice. If the display of the * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices * must display the words "Powered by KnowledgeTree" and retain the original * copyright notice. * Contributor( s): ______________________________________ */ require_once(KT_LIB_DIR . '/dispatcher.inc.php'); require_once(KT_LIB_DIR . '/templating/templating.inc.php'); require_once(KT_LIB_DIR . '/browse/columnregistry.inc.php'); require_once(KT_LIB_DIR . '/widgets/reorderdisplay.inc.php'); require_once(KT_LIB_DIR . '/widgets/fieldWidgets.php'); require_once(KT_LIB_DIR . "/widgets/FieldsetDisplayRegistry.inc.php"); require_once(KT_LIB_DIR . "/widgets/fieldsetDisplay.inc.php"); require_once(KT_LIB_DIR . "/widgets/widgetfactory.inc.php"); require_once(KT_LIB_DIR . "/validation/dispatchervalidation.inc.php"); require_once(KT_LIB_DIR . "/metadata/fieldsetregistry.inc.php"); require_once(KT_LIB_DIR . "/validation/validatorfactory.inc.php"); class ManageBrandDispatcher extends KTAdminDispatcher { private $maxLogoWidth = 313; private $maxLogoHeight = 50; function check() { $this->aBreadcrumbs[] = array('url' => $_SERVER['PHP_SELF'], 'name' => _kt('Manage Branding')); return parent::check(); } function do_main() { $uploadLogoForm = $this->getUploadLogoForm(); return $uploadLogoForm->render(); } /** * Returns the upload logo form * @return KTForm * */ function getUploadLogoForm() { $this->oPage->setBreadcrumbDetails(_kt("Upload Logo")); $oForm = new KTForm; $oForm->setOptions(array( 'identifier' => 'ktcore.folder.branding', 'label' => _kt('Upload Logo'), 'submit_label' => _kt('Upload'), 'action' => 'upload', 'fail_action' => 'main', 'encoding' => 'multipart/form-data', 'context' => &$this, 'extraargs' => $this->meldPersistQuery("","",true), 'description' => _kt('The logo upload facility allows you to upload a logo to brand your knowledgetree site.') )); $oWF =& KTWidgetFactory::getSingleton(); $widgets = array(); $validators = array(); // Adding the File Upload Widget $widgets[] = $oWF->get('ktcore.widgets.file', array( 'label' => _kt('Logo File'), 'required' => true, 'name' => 'file', 'id' => 'file', 'value' => '', 'description' => _kt('The logo should be 313px by 50px in dimension. If you don\'t have a 313x50 logo you should choose to either "crop" or "scale" it. If you are certain that your logo has the correct dimentions you can safely skip by the selecting "Don\'t do anything"'), )); $aVocab['crop'] = 'Crop - Cut out a selection'; $aVocab['scale'] = 'Scale - Stretch or Shrink to fit'; $aVocab['nothing'] = 'Don\'t do anything'; //Adding document type lookup widget $widgets[] = $oWF->get('ktcore.widgets.selection',array( 'label' => _kt('Fitting Image'), 'id' => 'logo_action', 'description' => _kt('How would you like to resize the image?'), 'name' => 'resize_method', 'vocab' => $aVocab, 'selected' => 'crop', 'label_method' => 'getName', 'simple_select' => true, )); $oForm->setWidgets($widgets); $oForm->setValidators($validators); // TODO: Should electronic signature be implemented for this? // Implement an electronic signature for accessing the admin section, it will appear every 10 minutes /* //Have to instanciate the oFolder global $default; $iFolderId = $this->oFolder->getId(); if($default->enableESignatures){ $sUrl = KTPluginUtil::getPluginPath('electronic.signatures.plugin', true); $heading = _kt('You are attempting to perform a bulk upload'); $submit['type'] = 'button'; $submit['onclick'] = "javascript: showSignatureForm('{$sUrl}', '{$heading}', 'ktcore.transactions.bulk_upload', 'bulk', 'bulk_upload_form', 'submit', {$iFolderId});"; }else{ $submit['type'] = 'submit'; $submit['onclick'] = ''; } */ return $oForm; } /** * Returns the crop logo form * * This form will assist the user in selecting an area of the image to use as the logo * within predefined dimensions required for the logo to fit properly into the page header. * * @return KTForm * */ function getCropLogoForm($logoFileName = '') { $this->oPage->setBreadcrumbDetails(_kt("Crop Logo")); $oForm = new KTForm; $oForm->setOptions(array( 'identifier' => 'ktcore.folder.branding', 'name' => 'crop_form', 'label' => _kt('Crop Logo'), 'submit_label' => _kt('Crop'), 'action' => 'crop', 'fail_action' => 'main', 'encoding' => 'multipart/form-data', 'context' => &$this, 'extraargs' => $this->meldPersistQuery("","",true), 'description' => _kt('Use this facility to ensure that the logo meets the required dimensions for the header.') )); $oWF =& KTWidgetFactory::getSingleton(); $widgets = array(); $validators = array(); $logoFile = 'var'.DIRECTORY_SEPARATOR.'branding'.DIRECTORY_SEPARATOR.'logo'.DIRECTORY_SEPARATOR.$logoFileName; // Adding the Image Crop Widget $widgets[] = $oWF->get('ktcore.widgets.imagecrop', array( 'label' => _kt('Crop Logo'), //'name' => 'Logo', 'value' => $logoFile, 'description' => _kt('To crop an area of the logo, click and drag the resizable rectangle over the image.'), )); // Adding the Hidden FileName Input String $widgets[] = $oWF->get('ktcore.widgets.hidden', array( 'name' => 'logo_file_name', 'value' => $logoFileName, )); // Adding the Hidden Coordinates X1 $widgets[] = $oWF->get('ktcore.widgets.hidden', array( 'name' => 'crop_x1', 'value' => 'x1test', )); // Adding the Hidden Coordinates Y1 $widgets[] = $oWF->get('ktcore.widgets.hidden', array( 'name' => 'crop_y1', 'value' => '', )); // Adding the Hidden Coordinates X2 $widgets[] = $oWF->get('ktcore.widgets.hidden', array( 'name' => 'crop_x2', 'value' => '', )); // Adding the Hidden Coordinates Y2 $widgets[] = $oWF->get('ktcore.widgets.hidden', array( 'name' => 'crop_y2', 'value' => '', )); $oForm->setWidgets($widgets); $oForm->setValidators($validators); return $oForm; } /** * Returns the apply logo form * * This form will display a preview of the correctly sized logo and prompt the user to apply it. * * @return KTForm * */ function getApplyLogoForm($logoFileName = '') { $this->oPage->setBreadcrumbDetails(_kt("Apply Logo")); $oForm = new KTForm; $oForm->setOptions(array( 'identifier' => 'ktcore.folder.branding', 'label' => _kt('Apply Logo'), 'submit_label' => _kt('Apply'), 'action' => 'apply', 'fail_action' => 'main', 'encoding' => 'multipart/form-data', 'context' => &$this, 'extraargs' => $this->meldPersistQuery("","",true), 'description' => _kt('Applying the logo will activate it in the header making it visible to all who access this site.') )); $oWF =& KTWidgetFactory::getSingleton(); $widgets = array(); $validators = array(); $logoFileName = 'var'.DIRECTORY_SEPARATOR.'branding'.DIRECTORY_SEPARATOR.'logo'.DIRECTORY_SEPARATOR.$logoFileName; // Adding the Image Crop Widget $widgets[] = $oWF->get('ktcore.widgets.image', array( 'label' => _kt('Logo Preview'), 'name' => $logoFileName, // title and alt attributes get set to this. 'value' => $logoFileName, )); // Adding the Hidden FileName Input String $widgets[] = $oWF->get('ktcore.widgets.hidden', array( 'name' => 'logo_file_name', 'value' => $logoFileName, )); $oForm->setWidgets($widgets); $oForm->setValidators($validators); return $oForm; } /* * Action responsible for uploading the logo * */ function do_upload(){ global $default; $oForm = $this->getUploadLogoForm(); $res = $oForm->validate(); if (!empty($res['errors'])) { return $oForm->handleError(); } // Setting up the branding directory, logos will be stored in var/branding/ $brandDir = $default->varDirectory.DIRECTORY_SEPARATOR.'branding'; if (stristr(PHP_OS,'WIN')) { $brandDir = str_replace('/', '\\', $brandDir); } //if branding dir does not exist, generate one and add an index file to block access if (!file_exists($brandDir)) { mkdir($brandDir, 0755); touch($brandDir.DIRECTORY_SEPARATOR.'index.html'); file_put_contents($brandDir.DIRECTORY_SEPARATOR.'index.html', 'You do not have permission to access this directory.'); } $logoDir = $brandDir.DIRECTORY_SEPARATOR."logo"; //if branding dir does not exist, generate one and add an index file to block access if (!file_exists($logoDir)) { mkdir($logoDir, 0755); touch($logoDir.DIRECTORY_SEPARATOR.'index.html'); file_put_contents($logoDir.DIRECTORY_SEPARATOR.'index.html', 'You do not have permission to access this directory.'); } $logoFileName = $_FILES['_kt_attempt_unique_file']['name']; //Changing to logo.jpg (Need to preserve extention as GD requires the exact image type to work) $ext = end(explode('.', $logoFileName)); $logoFileName = 'logo_tmp.'.$ext; $logoFile = $logoDir.DIRECTORY_SEPARATOR.$logoFileName; // deleting old tmp file if (file_exists($logoFile)) { @unlink($logoFile); } //TODO: Test Upload Failure by setting the $logoFile to '' if(!move_uploaded_file($_FILES['_kt_attempt_unique_file']['tmp_name'], $logoFile)) { $default->log->error("Couldn't upload file from '".$_FILES['_kt_attempt_unique_file']['tmp_name']."' to '$logoFile'"); $this->errorRedirectToMain("Couldn't upload file"); exit(0); } $resizeMethod = $_REQUEST['data']['resize_method']; switch ($resizeMethod) { case 'crop': $cropLogoForm = $this->getCropLogoForm($logoFileName); return $cropLogoForm->render(); case 'scale': $type = $_FILES['_kt_attempt_unique_file']['type']; $res = $this->scaleImage($logoFile, $logoFile, $this->maxLogoWidth, $this->maxLogoHeight, $type); $form = $this->getApplyLogoForm($logoFileName); return $form->render(); default: $form = $this->getApplyLogoForm($logoFileName); return $form->render(); } } /* * This method uses the GD library to scale an image. * - Supported images are jpeg, png and gif * */ public function scaleImage( $origFile, $destFile, $width, $height, $type = 'image/jpeg', $scaleUp = true) { global $default; //Requires the GD library if not exit gracefully if (!extension_loaded('gd')) { $default->log->error("The GD library isn't loaded"); return false; } switch($type) { case 'image/jpeg': $orig = imagecreatefromjpeg($origFile); break; case 'image/pjpeg': $orig = imagecreatefromjpeg($origFile); break; case 'image/png': $orig = imagecreatefrompng($origFile); break; case 'image/gif': $orig = imagecreatefromgif($origFile); break; default: //Handle Error $default->log->error("Tried to scale an unsupported file type: $type"); return false; } if($orig) { /* * calculate the size of the new image. */ $orig_x = imagesx($orig); $orig_y = imagesy($orig); if (($orig_x < $width) && ($orig_y < $height)) { //Image Qualifies for Upscaling //If we're not going to scale up then exit here. if (!$scaleUp) { return true; } } $image_x = $width; $image_y = $height; //$image_y = round(($orig_y * $image_x) / $orig_x); //Preserve proportion /* * create the new image, and scale the original into it. */ $image = imagecreatetruecolor($image_x, $image_y); imagecopyresampled($image, $orig, 0, 0, 0, 0, $image_x, $image_y, $orig_x, $orig_y); switch($type) { case 'image/jpeg': imagejpeg($image, $destFile); break; case 'image/pjpeg': imagejpeg($image, $destFile); break; case 'image/png': imagepng($image, $destFile); break; case 'image/gif': imagegif($image, $destFile); break; default: //Handle Error $default->log->error("Tried to scale an unsupported file type: $type"); return false; } } else { //Handle Error $default->log->error("Couldn't obtain a valid GD resource"); $default->log->error($sourceFile); $default->log->error($destFile); return false; } return true; } /* * Action responsible for cropping the logo * */ function do_crop(){ global $default; $logoFileName = $_REQUEST['data']['logo_file_name']; $logoFile = 'var'.DIRECTORY_SEPARATOR.'branding'.DIRECTORY_SEPARATOR.'logo'.DIRECTORY_SEPARATOR.$logoFileName; $x1 = $_REQUEST['data']['crop_x1']; $y1 = $_REQUEST['data']['crop_y1']; $x2 = $_REQUEST['data']['crop_x2']; $y2 = $_REQUEST['data']['crop_y2']; $type = $this->getMime($logoFileName); //GD Crop $res = $this->cropImage($logoFile, $logoFile, $x1, $y1, $x2, $y2, $type); //If dimensions don't conform then will scale it further $width = $x2 - $x1; $height = $y2 - $y1; if (($width > $this->maxLogoWidth) || ($height > $this->maxLogoHeight)) { $default->log->info('SCALING IMAGE AFTER CROP'); $res = $this->scaleImage($logoFile, $logoFile, $this->maxLogoWidth, $this->maxLogoHeight, $type); } // ImageMagick Crop /* // do generation $pathConvert = (!empty($default->convertPath)) ? $default->convertPath : 'convert'; // windows path may contain spaces if (stristr(PHP_OS,'WIN')) { $cmd = "\"{$pathConvert}\" \"{$logoFileName}" . $pageNumber . "\" -crop 313x50+110+110 \"$logoFileName\""; } else { $cmd = "{$pathConvert} {$logoFileName}" . $pageNumber . " -resize 313x50 $logoFileName"; } $result = KTUtil::pexec($cmd); */ $applyLogoForm = $this->getApplyLogoForm($logoFileName); return $applyLogoForm->render(); } /** * Returns the MIME of the filename, deducted from its extension * If the extension is unknown, returns "image/jpeg" */ function getMime($filename) { $pos = strrpos($filename, '.'); $extension = ""; if ($pos !== false) { $extension = strtolower(substr($filename, $pos+1)); } switch($extension) { case 'gif': return 'image/gif'; case 'jfif': return 'image/jpeg'; case 'jfif-tbnl': return 'image/jpeg'; case 'png': return 'image/png'; case 'jpe': return 'image/jpeg'; case 'jpeg': return 'image/jpeg'; case 'jpg': return 'image/jpeg'; default: return 'image/jpeg'; } } /* * This method uses the GD library to crop an image. * - Supported images are jpeg, png and gif * */ public function cropImage( $origFile, $destFile, $x1, $y1, $x2, $y2, $type = 'image/jpeg', $scaleUp = true) { global $default; $width = $x2 - $x1; $height = $y2 - $y1; //Requires the GD library if not exit gracefully if (!extension_loaded('gd')) { $default->log->error("The GD library isn't loaded"); return false; } switch($type) { case 'image/jpeg': $orig = imagecreatefromjpeg($origFile); break; case 'image/pjpeg': $orig = imagecreatefromjpeg($origFile); break; case 'image/png': $orig = imagecreatefrompng($origFile); break; case 'image/gif': $orig = imagecreatefromgif($origFile); break; default: //Handle Error $default->log->error("Tried to crop an unsupported file type: $type"); return false; } if($orig) { /* * create the new image, and crop it. */ $image = imagecreatetruecolor($width, $height); //imagecopyresampled($image, $orig, 0, 0, 0, 0, $image_x, $image_y, $orig_x, $orig_y); // Generate the cropped image imagecopyresampled($image, $orig, 0, 0, $x1, $y1, $width, $height, $width, $height); //imagecopyresized($canvas, $piece, 0,0, $cropLeft, $cropHeight,$newwidth, $newheight, $width, $height); switch($type) { case 'image/jpeg': imagejpeg($image, $destFile); break; case 'image/pjpeg': imagejpeg($image, $destFile); break; case 'image/png': imagepng($image, $destFile); break; case 'image/gif': imagegif($image, $destFile); break; default: //Handle Error $default->log->error("Tried to crop an unsupported file type: $type"); return false; } } else { //Handle Error $default->log->error("Couldn't obtain a valid GD resource $sourceFile $destFile"); return false; } return true; } /* * Action responsible for applying the logo * */ function do_apply(){ global $default; $rootPath = $default->varDirectory . '/'; $tmpLogoFileName = $_REQUEST['data']['logo_file_name']; $tmpLogoFileName = end(explode(DIRECTORY_SEPARATOR, $tmpLogoFileName)); $tmpLogoFile = $default->varDirectory.DIRECTORY_SEPARATOR.'branding'.DIRECTORY_SEPARATOR.'logo'.DIRECTORY_SEPARATOR.$tmpLogoFileName; $ext = end(explode('.', $tmpLogoFileName)); $logoFileName = 'logo_'.md5(Date('ymd-hms')).'.'.$ext; $logoFile = $default->varDirectory.DIRECTORY_SEPARATOR.'branding'.DIRECTORY_SEPARATOR.'logo'.DIRECTORY_SEPARATOR.$logoFileName; $logoFileRel = end(explode(DIRECTORY_SEPARATOR, $default->varDirectory)).DIRECTORY_SEPARATOR.'branding'.DIRECTORY_SEPARATOR.'logo'.DIRECTORY_SEPARATOR.$logoFileName; // Applying the new logo if(!@copy($tmpLogoFile, $logoFile)){ $default->log->info("Couldn't copy logo ".$tmpLogoFile." to ".$logoFile); } else { //Cleaning stale files $brandDir = $default->varDirectory.DIRECTORY_SEPARATOR.'branding'.DIRECTORY_SEPARATOR.'logo'.DIRECTORY_SEPARATOR; $handle = opendir($brandDir); while (false !== ($file = readdir($handle))) { if (!is_dir($file) && $file != 'logo_tmp.jpg' && $file != $logoFileName) { if (!@unlink($brandDir.$file)) { $default->log->error("Couldn't delete '".$brandDir.$file."'"); } } } } // // Updating Config Settings with the new Logo Location // $sql = "SELECT id from config_settings WHERE item = 'companyLogo'"; $companyLogoId = DBUtil::getOneResultKey($sql,'id'); if (PEAR::isError($companyLogoId)) { if (PEAR::isError($res)) { $default->log->error(sprintf(_kt("Failed to apply logo: %s"), $res->getMessage())); $this->errorRedirectToMain(sprintf(_kt("Failed to apply logo: %s"), $res->getMessage())); exit(); } } $res = DBUtil::autoUpdate('config_settings', array('value' => $logoFileRel), $companyLogoId); if (PEAR::isError($res)) { $default->log->error(sprintf(_kt("Failed to apply logo: %s"), $res->getMessage())); $this->errorRedirectToMain(sprintf(_kt("Failed to apply logo: %s"), $res->getMessage())); exit(); } // Clear the cached settings $oKTConfig = new KTConfig(); $oKTConfig->clearCache(); $this->successRedirectTo('', _kt("Logo succesfully applied.")); } /* Old Manage Views Code! Crap, must delete */ function do_editView() { $oTemplating =& KTTemplating::getSingleton(); $oTemplate = $oTemplating->loadTemplate('ktcore/misc/columns/edit_view'); $oColumnRegistry =& KTColumnRegistry::getSingleton(); $aColumns = $oColumnRegistry->getColumnsForView($_REQUEST['viewNS']); //var_dump($aColumns); exit(0); $aAllColumns = $oColumnRegistry->getColumns(); $view_name = $oColumnRegistry->getViewName(($_REQUEST['viewNS'])); $this->oPage->setTitle($view_name); $this->oPage->setBreadcrumbDetails($view_name); $aOptions = array(); $vocab = array(); foreach ($aAllColumns as $aInfo) { $vocab[$aInfo['namespace']] = $aInfo['name']; } $aOptions['vocab'] = $vocab; $add_field = new KTLookupWidget(_kt("Columns"), _kt("Select a column to add to the view. Please note that while you can add multiple copies of a column, they will all behave as a single column"), 'column_ns', null, $this->oPage, true, null, $aErrors = null, $aOptions); $aTemplateData = array( 'context' => $this, 'current_columns' => $aColumns, 'all_columns' => $aAllColumns, 'view' => $_REQUEST['viewNS'], 'add_field' => $add_field, ); return $oTemplate->render($aTemplateData); } function do_deleteEntry() { $entry_id = KTUtil::arrayGet($_REQUEST, 'entry_id'); $view = KTUtil::arrayGet($_REQUEST, 'viewNS'); // none of these conditions can be reached "normally". $oEntry = KTColumnEntry::get($entry_id); if (PEAR::isError($oEntry)) { $this->errorRedirectToMain(_kt("Unable to locate the entry")); } if ($oEntry->getRequired()) { $this->errorRedirectToMain(_kt("That column is required")); } if ($oEntry->getViewNamespace() != $view) { $this->errorRedirectToMain(_kt("That column is not for the specified view")); } $res = $oEntry->delete(); if (PEAR::isError($res)) { $this->errorRedirectToMain(sprintf(_kt("Failed to remove that column: %s"), $res->getMessage())); } $this->successRedirectTo("editView", _kt("Deleted Entry"), sprintf("viewNS=%s", $view)); } function do_addEntry() { $column_ns = KTUtil::arrayGet($_REQUEST, 'column_ns'); $view = KTUtil::arrayGet($_REQUEST, 'viewNS'); $this->startTransaction(); $position = KTColumnEntry::getNextEntryPosition($view); $oEntry = KTColumnEntry::createFromArray(array( 'ColumnNamespace' => $column_ns, 'ViewNamespace' => $view, 'Position' => $position, // start it at the bottom 'config' => array(), // stub, for now. 'Required' => 0 )); $this->successRedirectTo("editView", _kt("Added Entry"), sprintf("viewNS=%s", $view)); } function do_orderUp(){ $entryId = $_REQUEST['entry_id']; $view = $_REQUEST['viewNS']; $oEntry = KTColumnEntry::get($entryId); if (PEAR::isError($oEntry)) { $this->errorRedirectTo('editView', _kt('Unable to locate the column entry'), "viewNS={$view}"); exit(); } $res = $oEntry->movePosition($view, $entryId, 'up'); if (PEAR::isError($res)) { $this->errorRedirectTo('editView', $res->getMessage(), "viewNS={$view}"); exit(); } $this->redirectTo('editView', "viewNS={$view}"); } function do_orderDown(){ $entryId = $_REQUEST['entry_id']; $view = $_REQUEST['viewNS']; $oEntry = KTColumnEntry::get($entryId); if (PEAR::isError($oEntry)) { $this->errorRedirectTo('editView', _kt('Unable to locate the column entry'), "viewNS={$view}"); exit(); } $res = $oEntry->movePosition($view, $entryId, 'down'); if (PEAR::isError($res)) { $this->errorRedirectTo('editView', $res->getMessage(), "viewNS={$view}"); exit(); } $this->redirectTo("editView", "viewNS={$view}"); } } ?>